1 /*
2    AngelCode Scripting Library
3    Copyright (c) 2003-2017 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_scriptengine.cpp
34 //
35 // The implementation of the script engine interface
36 //
37 
38 
39 #include <stdlib.h>
40 
41 #include "as_config.h"
42 #include "as_scriptengine.h"
43 #include "as_builder.h"
44 #include "as_context.h"
45 #include "as_string_util.h"
46 #include "as_tokenizer.h"
47 #include "as_texts.h"
48 #include "as_module.h"
49 #include "as_callfunc.h"
50 #include "as_generic.h"
51 #include "as_scriptobject.h"
52 #include "as_compiler.h"
53 #include "as_bytecode.h"
54 #include "as_debug.h"
55 
56 BEGIN_AS_NAMESPACE
57 
58 
59 
60 #ifdef AS_PROFILE
61 // Instantiate the profiler once
62 CProfiler g_profiler;
63 #endif
64 
65 
66 
67 
68 extern "C"
69 {
70 
asGetLibraryVersion()71 AS_API const char * asGetLibraryVersion()
72 {
73 #ifdef _DEBUG
74 	return ANGELSCRIPT_VERSION_STRING " DEBUG";
75 #else
76 	return ANGELSCRIPT_VERSION_STRING;
77 #endif
78 }
79 
asGetLibraryOptions()80 AS_API const char * asGetLibraryOptions()
81 {
82 	const char *string = " "
83 
84 	// Options
85 #ifdef AS_MAX_PORTABILITY
86 		"AS_MAX_PORTABILITY "
87 #endif
88 #ifdef AS_DEBUG
89 		"AS_DEBUG "
90 #endif
91 #ifdef AS_NO_CLASS_METHODS
92 		"AS_NO_CLASS_METHODS "
93 #endif
94 #ifdef AS_USE_DOUBLE_AS_FLOAT
95 		"AS_USE_DOUBLE_AS_FLOAT "
96 #endif
97 #ifdef AS_64BIT_PTR
98 		"AS_64BIT_PTR "
99 #endif
100 #ifdef AS_NO_THREADS
101 		"AS_NO_THREADS "
102 #endif
103 #ifdef AS_NO_ATOMIC
104 		"AS_NO_ATOMIC "
105 #endif
106 #ifdef AS_NO_COMPILER
107 		"AS_NO_COMPILER "
108 #endif
109 #ifdef AS_NO_MEMBER_INIT
110 		"AS_NO_MEMBER_INIT "
111 #endif
112 #ifdef AS_NO_THISCALL_FUNCTOR_METHOD
113 		"AS_NO_THISCALL_FUNCTOR_METHOD "
114 #endif
115 #ifdef AS_NO_EXCEPTIONS
116 		"AS_NO_EXCEPTIONS "
117 #endif
118 #ifdef WIP_16BYTE_ALIGN
119 		"WIP_16BYTE_ALIGN "
120 #endif
121 #ifdef AS_BIG_ENDIAN
122 		"AS_BIG_ENDIAN "
123 #endif
124 
125 	// Target system
126 #ifdef AS_WIN
127 		"AS_WIN "
128 #endif
129 #ifdef AS_LINUX
130 		"AS_LINUX "
131 #endif
132 #ifdef AS_MAC
133 		"AS_MAC "
134 #endif
135 #ifdef AS_SUN
136 		"AS_SUN "
137 #endif
138 #ifdef AS_BSD
139 		"AS_BSD "
140 #endif
141 #ifdef AS_XBOX
142 		"AS_XBOX "
143 #endif
144 #ifdef AS_XBOX360
145 		"AS_XBOX360 "
146 #endif
147 #ifdef AS_PSP
148 		"AS_PSP "
149 #endif
150 #ifdef AS_PS2
151 		"AS_PS2 "
152 #endif
153 #ifdef AS_PS3
154 		"AS_PS3 "
155 #endif
156 #ifdef AS_PSVITA
157 		"AS_PSVITA "
158 #endif
159 #ifdef AS_DC
160 		"AS_DC "
161 #endif
162 #ifdef AS_GC
163 		"AS_GC "
164 #endif
165 #ifdef AS_WII
166 		"AS_WII "
167 #endif
168 #ifdef AS_WIIU
169 		"AS_WIIU "
170 #endif
171 #ifdef AS_IPHONE
172 		"AS_IPHONE "
173 #endif
174 #ifdef AS_ANDROID
175 		"AS_ANDROID "
176 #endif
177 #ifdef AS_HAIKU
178 		"AS_HAIKU "
179 #endif
180 #ifdef AS_ILLUMOS
181 		"AS_ILLUMOS "
182 #endif
183 #ifdef AS_MARMALADE
184 		"AS_MARMALADE "
185 #endif
186 
187 
188 	// CPU family
189 #ifdef AS_PPC
190 		"AS_PPC "
191 #endif
192 #ifdef AS_PPC_64
193 		"AS_PPC_64 "
194 #endif
195 #ifdef AS_X86
196 		"AS_X86 "
197 #endif
198 #ifdef AS_MIPS
199 		"AS_MIPS "
200 #endif
201 #ifdef AS_SH4
202 		"AS_SH4 "
203 #endif
204 #ifdef AS_XENON
205 		"AS_XENON "
206 #endif
207 #ifdef AS_ARM
208 		"AS_ARM "
209 #endif
210 #ifdef AS_SOFTFP
211 		"AS_SOFTFP "
212 #endif
213 #ifdef AS_X64_GCC
214 		"AS_X64_GCC "
215 #endif
216 #ifdef AS_X64_MSVC
217 		"AS_X64_MSVC "
218 #endif
219 #ifdef AS_SPARC
220 		"AS_SPARC "
221 #endif
222 	;
223 
224 	return string;
225 }
226 
asCreateScriptEngine(asDWORD version)227 AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version)
228 {
229 	// Verify the version that the application expects
230 	if( (version/10000) != (ANGELSCRIPT_VERSION/10000) )
231 		return 0;
232 
233 	if( (version/100)%100 != (ANGELSCRIPT_VERSION/100)%100 )
234 		return 0;
235 
236 	if( (version%100) > (ANGELSCRIPT_VERSION%100) )
237 		return 0;
238 
239 	// Verify the size of the types
240 	asASSERT( sizeof(asBYTE)  == 1 );
241 	asASSERT( sizeof(asWORD)  == 2 );
242 	asASSERT( sizeof(asDWORD) == 4 );
243 	asASSERT( sizeof(asQWORD) == 8 );
244 	asASSERT( sizeof(asPWORD) == sizeof(void*) );
245 
246 	// Verify the boolean type
247 	asASSERT( sizeof(bool) == AS_SIZEOF_BOOL );
248 	asASSERT( true == VALUE_OF_BOOLEAN_TRUE );
249 
250 	// Verify endianess
251 #ifdef AS_BIG_ENDIAN
252 	asDWORD dw = 0x00010203;
253 	asQWORD qw = ((asQWORD(0x00010203)<<32)|asQWORD(0x04050607));
254 #else
255 	asDWORD dw = 0x03020100;
256 	// C++ didn't have a standard way of declaring 64bit literal constants until C++11, so
257 	// I'm forced to do it like this to avoid compilers warnings when compiling with the full
258 	// C++ compliance.
259 	asQWORD qw = ((asQWORD(0x07060504)<<32)|asQWORD(0x03020100));
260 #endif
261 	asASSERT( memcmp("\x00\x01\x02\x03", &dw, 4) == 0 );
262 	asASSERT( memcmp("\x00\x01\x02\x03\x04\x05\x06\x07", &qw, 8) == 0 );
263 	UNUSED_VAR(dw);
264 	UNUSED_VAR(qw);
265 
266 	return asNEW(asCScriptEngine)();
267 }
268 
269 } // extern "C"
270 
271 
272 // interface
SetEngineProperty(asEEngineProp property,asPWORD value)273 int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value)
274 {
275 	switch( property )
276 	{
277 	case asEP_ALLOW_UNSAFE_REFERENCES:
278 		ep.allowUnsafeReferences = value ? true : false;
279 		break;
280 
281 	case asEP_OPTIMIZE_BYTECODE:
282 		ep.optimizeByteCode = value ? true : false;
283 		break;
284 
285 	case asEP_COPY_SCRIPT_SECTIONS:
286 		ep.copyScriptSections = value ? true : false;
287 		break;
288 
289 	case asEP_MAX_STACK_SIZE:
290 		if( value == 0 )
291 		{
292 			// Restore default: no limit and initially size 4KB
293 			ep.maximumContextStackSize = 0;
294 			initialContextStackSize    = 1024;
295 		}
296 		else
297 		{
298 			// The size is given in bytes, but we only store dwords
299 			ep.maximumContextStackSize = (asUINT)value/4;
300 			if( initialContextStackSize > ep.maximumContextStackSize )
301 			{
302 				initialContextStackSize = ep.maximumContextStackSize;
303 				if( initialContextStackSize == 0 )
304 					initialContextStackSize = 1;
305 			}
306 		}
307 		break;
308 
309 	case asEP_USE_CHARACTER_LITERALS:
310 		ep.useCharacterLiterals = value ? true : false;
311 		break;
312 
313 	case asEP_ALLOW_MULTILINE_STRINGS:
314 		ep.allowMultilineStrings = value ? true : false;
315 		break;
316 
317 	case asEP_ALLOW_IMPLICIT_HANDLE_TYPES:
318 		ep.allowImplicitHandleTypes = value ? true : false;
319 		break;
320 
321 	case asEP_BUILD_WITHOUT_LINE_CUES:
322 		ep.buildWithoutLineCues = value ? true : false;
323 		break;
324 
325 	case asEP_INIT_GLOBAL_VARS_AFTER_BUILD:
326 		ep.initGlobalVarsAfterBuild = value ? true : false;
327 		break;
328 
329 	case asEP_REQUIRE_ENUM_SCOPE:
330 		ep.requireEnumScope = value ? true : false;
331 		break;
332 
333 	case asEP_SCRIPT_SCANNER:
334 		if( value <= 1 )
335 			ep.scanner = (int)value;
336 		else
337 			return asINVALID_ARG;
338 		break;
339 
340 	case asEP_INCLUDE_JIT_INSTRUCTIONS:
341 		ep.includeJitInstructions = value ? true : false;
342 		break;
343 
344 	case asEP_STRING_ENCODING:
345 		if( value <= 1 )
346 			ep.stringEncoding = (int)value;
347 		else
348 			return asINVALID_ARG;
349 		break;
350 
351 	case asEP_PROPERTY_ACCESSOR_MODE:
352 		if( value <= 2 )
353 			ep.propertyAccessorMode = (int)value;
354 		else
355 			return asINVALID_ARG;
356 		break;
357 
358 	case asEP_EXPAND_DEF_ARRAY_TO_TMPL:
359 		ep.expandDefaultArrayToTemplate = value ? true : false;
360 		break;
361 
362 	case asEP_AUTO_GARBAGE_COLLECT:
363 		ep.autoGarbageCollect = value ? true : false;
364 		break;
365 
366 	case asEP_DISALLOW_GLOBAL_VARS:
367 		ep.disallowGlobalVars = value ? true : false;
368 		break;
369 
370 	case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT:
371 		ep.alwaysImplDefaultConstruct = value ? true : false;
372 		break;
373 
374 	case asEP_COMPILER_WARNINGS:
375 		if( value <= 2 )
376 			ep.compilerWarnings = (int)value;
377 		else
378 			return asINVALID_ARG;
379 		break;
380 
381 	case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE:
382 		ep.disallowValueAssignForRefType = value ? true : false;
383 		break;
384 
385 	case asEP_ALTER_SYNTAX_NAMED_ARGS:
386 		if( value <= 2 )
387 			ep.alterSyntaxNamedArgs = (int)value;
388 		else
389 			return asINVALID_ARG;
390 		break;
391 
392 	case asEP_DISABLE_INTEGER_DIVISION:
393 		ep.disableIntegerDivision = value ? true : false;
394 		break;
395 
396 	case asEP_DISALLOW_EMPTY_LIST_ELEMENTS:
397 		ep.disallowEmptyListElements = value ? true : false;
398 		break;
399 
400 	case asEP_PRIVATE_PROP_AS_PROTECTED:
401 		ep.privatePropAsProtected = value ? true : false;
402 		break;
403 
404 	case asEP_ALLOW_UNICODE_IDENTIFIERS:
405 		ep.allowUnicodeIdentifiers = value ? true : false;
406 		break;
407 
408 	case asEP_HEREDOC_TRIM_MODE:
409 		if (value <= 2)
410 			ep.heredocTrimMode = (int)value;
411 		else
412 			return asINVALID_ARG;
413 		break;
414 
415 	case asEP_MAX_NESTED_CALLS:
416 		if (value > 0xFFFFFFFF)
417 			ep.maxNestedCalls = 0xFFFFFFFF;
418 		else
419 			ep.maxNestedCalls = (asUINT)value;
420 		break;
421 
422 	default:
423 		return asINVALID_ARG;
424 	}
425 
426 	return asSUCCESS;
427 }
428 
429 // interface
GetEngineProperty(asEEngineProp property) const430 asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const
431 {
432 	switch( property )
433 	{
434 	case asEP_ALLOW_UNSAFE_REFERENCES:
435 		return ep.allowUnsafeReferences;
436 
437 	case asEP_OPTIMIZE_BYTECODE:
438 		return ep.optimizeByteCode;
439 
440 	case asEP_COPY_SCRIPT_SECTIONS:
441 		return ep.copyScriptSections;
442 
443 	case asEP_MAX_STACK_SIZE:
444 		return ep.maximumContextStackSize*4;
445 
446 	case asEP_USE_CHARACTER_LITERALS:
447 		return ep.useCharacterLiterals;
448 
449 	case asEP_ALLOW_MULTILINE_STRINGS:
450 		return ep.allowMultilineStrings;
451 
452 	case asEP_ALLOW_IMPLICIT_HANDLE_TYPES:
453 		return ep.allowImplicitHandleTypes;
454 
455 	case asEP_BUILD_WITHOUT_LINE_CUES:
456 		return ep.buildWithoutLineCues;
457 
458 	case asEP_INIT_GLOBAL_VARS_AFTER_BUILD:
459 		return ep.initGlobalVarsAfterBuild;
460 
461 	case asEP_REQUIRE_ENUM_SCOPE:
462 		return ep.requireEnumScope;
463 
464 	case asEP_SCRIPT_SCANNER:
465 		return ep.scanner;
466 
467 	case asEP_INCLUDE_JIT_INSTRUCTIONS:
468 		return ep.includeJitInstructions;
469 
470 	case asEP_STRING_ENCODING:
471 		return ep.stringEncoding;
472 
473 	case asEP_PROPERTY_ACCESSOR_MODE:
474 		return ep.propertyAccessorMode;
475 
476 	case asEP_EXPAND_DEF_ARRAY_TO_TMPL:
477 		return ep.expandDefaultArrayToTemplate;
478 
479 	case asEP_AUTO_GARBAGE_COLLECT:
480 		return ep.autoGarbageCollect;
481 
482 	case asEP_DISALLOW_GLOBAL_VARS:
483 		return ep.disallowGlobalVars;
484 
485 	case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT:
486 		return ep.alwaysImplDefaultConstruct;
487 
488 	case asEP_COMPILER_WARNINGS:
489 		return ep.compilerWarnings;
490 
491 	case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE:
492 		return ep.disallowValueAssignForRefType;
493 
494 	case asEP_ALTER_SYNTAX_NAMED_ARGS:
495 		return ep.alterSyntaxNamedArgs;
496 
497 	case asEP_DISABLE_INTEGER_DIVISION:
498 		return ep.disableIntegerDivision;
499 
500 	case asEP_DISALLOW_EMPTY_LIST_ELEMENTS:
501 		return ep.disallowEmptyListElements;
502 
503 	case asEP_PRIVATE_PROP_AS_PROTECTED:
504 		return ep.privatePropAsProtected;
505 
506 	case asEP_ALLOW_UNICODE_IDENTIFIERS:
507 		return ep.allowUnicodeIdentifiers;
508 
509 	case asEP_HEREDOC_TRIM_MODE:
510 		return ep.heredocTrimMode;
511 
512 	case asEP_MAX_NESTED_CALLS:
513 		return ep.maxNestedCalls;
514 
515 	default:
516 		return 0;
517 	}
518 
519 	UNREACHABLE_RETURN;
520 }
521 
522 // interface
CreateDelegate(asIScriptFunction * func,void * obj)523 asIScriptFunction *asCScriptEngine::CreateDelegate(asIScriptFunction *func, void *obj)
524 {
525 	if( func == 0 || obj == 0 )
526 		return 0;
527 
528 	// The function must be a class method
529 	asITypeInfo *type = func->GetObjectType();
530 	if( type == 0 )
531 		return 0;
532 
533 	// The object type must allow handles
534 	if( (type->GetFlags() & asOBJ_REF) == 0 || (type->GetFlags() & (asOBJ_SCOPED | asOBJ_NOHANDLE)) )
535 		return 0;
536 
537 	// Create the delegate the same way it would be created by the scripts
538 	return AS_NAMESPACE_QUALIFIER CreateDelegate(reinterpret_cast<asCScriptFunction*>(func), obj);
539 }
540 
asCScriptEngine()541 asCScriptEngine::asCScriptEngine()
542 {
543 	asCThreadManager::Prepare(0);
544 
545 	shuttingDown = false;
546 	inDestructor = false;
547 
548 	// Engine properties
549 	{
550 		ep.allowUnsafeReferences         = false;
551 		ep.optimizeByteCode              = true;
552 		ep.copyScriptSections            = true;
553 		ep.maximumContextStackSize       = 0;         // no limit
554 		ep.useCharacterLiterals          = false;
555 		ep.allowMultilineStrings         = false;
556 		ep.allowImplicitHandleTypes      = false;
557 		// TODO: optimize: Maybe this should be turned off by default? If a debugger is not used
558 		//                 then this is just slowing down the execution.
559 		ep.buildWithoutLineCues          = false;
560 		ep.initGlobalVarsAfterBuild      = true;
561 		ep.requireEnumScope              = false;
562 		ep.scanner                       = 1;         // utf8. 0 = ascii
563 		ep.includeJitInstructions        = false;
564 		ep.stringEncoding                = 0;         // utf8. 1 = utf16
565 		ep.propertyAccessorMode          = 2;         // 0 = disable, 1 = app registered only, 2 = app and script created
566 		ep.expandDefaultArrayToTemplate  = false;
567 		ep.autoGarbageCollect            = true;
568 		ep.disallowGlobalVars            = false;
569 		ep.alwaysImplDefaultConstruct    = false;
570 		ep.compilerWarnings              = 1;         // 0 = no warnings, 1 = warning, 2 = treat as error
571 		// TODO: 3.0.0: disallowValueAssignForRefType should be true by default
572 		ep.disallowValueAssignForRefType = false;
573 		ep.alterSyntaxNamedArgs          = 0;         // 0 = no alternate syntax, 1 = accept alternate syntax but warn, 2 = accept without warning
574 		ep.disableIntegerDivision        = false;
575 		ep.disallowEmptyListElements     = false;
576 		ep.privatePropAsProtected        = false;
577 		ep.allowUnicodeIdentifiers       = false;
578 		ep.heredocTrimMode               = 1;         // 0 = never trim, 1 = don't trim on single line, 2 = trim initial and final empty line
579 		ep.maxNestedCalls                = 100;
580 	}
581 
582 	gc.engine = this;
583 	tok.engine = this;
584 
585 	refCount.set(1);
586 	stringFactory = 0;
587 	configFailed = false;
588 	isPrepared = false;
589 	isBuilding = false;
590 	deferValidationOfTemplateTypes = false;
591 	lastModule = 0;
592 
593 
594 	initialContextStackSize = 1024;      // 4 KB (1024 * sizeof(asDWORD)
595 
596 
597 	typeIdSeqNbr      = 0;
598 	currentGroup      = &defaultGroup;
599 	defaultAccessMask = 0xFFFFFFFF; // All bits set so that built-in functions/types will be available to all modules
600 
601 	msgCallback = 0;
602 	jitCompiler = 0;
603 
604 	// Create the global namespace
605 	defaultNamespace = AddNameSpace("");
606 
607 	requestCtxFunc   = 0;
608 	returnCtxFunc    = 0;
609 	ctxCallbackParam = 0;
610 
611 	// We must set the namespace in the built-in types explicitly as
612 	// this wasn't done by the default constructor. If we do not do
613 	// this we will get null pointer access in other parts of the code
614 	scriptTypeBehaviours.nameSpace     = defaultNamespace;
615 	functionBehaviours.nameSpace       = defaultNamespace;
616 
617 	// Reserve function id 0 for no function
618 	scriptFunctions.PushLast(0);
619 
620 	// Reserve the first typeIds for the primitive types
621 	typeIdSeqNbr = asTYPEID_DOUBLE + 1;
622 
623 	// Make sure typeId for the built-in primitives are defined according to asETypeIdFlags
624 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid,   false)) == asTYPEID_VOID   );
625 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool,   false)) == asTYPEID_BOOL   );
626 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8,   false)) == asTYPEID_INT8   );
627 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16,  false)) == asTYPEID_INT16  );
628 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt,    false)) == asTYPEID_INT32  );
629 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64,  false)) == asTYPEID_INT64  );
630 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8,  false)) == asTYPEID_UINT8  );
631 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)) == asTYPEID_UINT16 );
632 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt,   false)) == asTYPEID_UINT32 );
633 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)) == asTYPEID_UINT64 );
634 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat,  false)) == asTYPEID_FLOAT  );
635 	asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)) == asTYPEID_DOUBLE );
636 
637 	defaultArrayObjectType = 0;
638 
639 	RegisterScriptObject(this);
640 	RegisterScriptFunction(this);
641 }
642 
DeleteDiscardedModules()643 void asCScriptEngine::DeleteDiscardedModules()
644 {
645 	// TODO: redesign: Prevent more than one thread from entering this function at the same time.
646 	//                 If a thread is already doing the work for the clean-up the other thread should
647 	//                 simply return, as the first thread will continue.
648 
649 	ACQUIRESHARED(engineRWLock);
650 	asUINT maxCount = discardedModules.GetLength();
651 	RELEASESHARED(engineRWLock);
652 
653 	for( asUINT n = 0; n < maxCount; n++ )
654 	{
655 		ACQUIRESHARED(engineRWLock);
656 		asCModule *mod = discardedModules[n];
657 		RELEASESHARED(engineRWLock);
658 
659 		if( !mod->HasExternalReferences(shuttingDown) )
660 		{
661 			asDELETE(mod, asCModule);
662 			n--;
663 		}
664 
665 		ACQUIRESHARED(engineRWLock);
666 		// Determine the max count again, since another module may have been discarded during the processing
667 		maxCount = discardedModules.GetLength();
668 		RELEASESHARED(engineRWLock);
669 	}
670 
671 	// Go over the list of global properties, to see if it is possible to clean
672 	// up some variables that are no longer referred to by any functions
673 	for( asUINT n = 0; n < globalProperties.GetLength(); n++ )
674 	{
675 		asCGlobalProperty *prop = globalProperties[n];
676 		if( prop && prop->refCount.get() == 1 )
677 			RemoveGlobalProperty(prop);
678 	}
679 }
680 
~asCScriptEngine()681 asCScriptEngine::~asCScriptEngine()
682 {
683 	// TODO: clean-up: Clean up redundant code
684 
685 	inDestructor = true;
686 
687 	asASSERT(refCount.get() == 0);
688 
689 	// If ShutDown hasn't been called yet do it now
690 	if( !shuttingDown )
691 	{
692 		AddRef();
693 		ShutDownAndRelease();
694 	}
695 
696 	// Unravel the registered interface
697 	if( defaultArrayObjectType )
698 	{
699 		defaultArrayObjectType->ReleaseInternal();
700 		defaultArrayObjectType = 0;
701 	}
702 
703 	// Delete the functions for generated template types that may references object types
704 	for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ )
705 	{
706 		asCObjectType *templateType = templateInstanceTypes[n];
707 		if( templateInstanceTypes[n] )
708 			templateType->DestroyInternal();
709 	}
710 	for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ )
711 	{
712 		asCObjectType *type = listPatternTypes[n];
713 		if( type )
714 			type->ReleaseInternal();
715 	}
716 	listPatternTypes.SetLength(0);
717 
718 	// No script types must have survived
719 	asASSERT( sharedScriptTypes.GetLength() == 0 );
720 
721 	// It is allowed to create new references to the engine temporarily while destroying objects
722 	// but these references must be release immediately or else something is can go wrong later on
723 	if( refCount.get() > 0 )
724 		WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN);
725 
726 	mapTypeIdToTypeInfo.EraseAll();
727 
728 	// First remove what is not used, so that other groups can be deleted safely
729 	defaultGroup.RemoveConfiguration(this, true);
730 	while( configGroups.GetLength() )
731 	{
732 		// Delete config groups in the right order
733 		asCConfigGroup *grp = configGroups.PopLast();
734 		if( grp )
735 		{
736 			grp->RemoveConfiguration(this);
737 			asDELETE(grp,asCConfigGroup);
738 		}
739 	}
740 	// Remove what is remaining
741 	defaultGroup.RemoveConfiguration(this);
742 
743 	// Any remaining objects in templateInstanceTypes is from generated template instances
744 	for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ )
745 	{
746 		asCObjectType *templateType = templateInstanceTypes[n];
747 		if( templateInstanceTypes[n] )
748 			templateType->ReleaseInternal();
749 	}
750 	templateInstanceTypes.SetLength(0);
751 
752 	asCSymbolTable<asCGlobalProperty>::iterator it = registeredGlobalProps.List();
753 	for( ; it; it++ )
754 	{
755 		RemoveGlobalProperty(*it);
756 		(*it)->Release();
757 	}
758 	registeredGlobalProps.Clear();
759 
760 	for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ )
761 	{
762 		if( templateSubTypes[n] )
763 		{
764 			templateSubTypes[n]->DestroyInternal();
765 			templateSubTypes[n]->ReleaseInternal();
766 		}
767 	}
768 	templateSubTypes.SetLength(0);
769 	registeredTypeDefs.SetLength(0);
770 	registeredEnums.SetLength(0);
771 	registeredObjTypes.SetLength(0);
772 
773 	asCSymbolTable<asCScriptFunction>::iterator funcIt = registeredGlobalFuncs.List();
774 	for( ; funcIt; funcIt++ )
775 		(*funcIt)->ReleaseInternal();
776 	registeredGlobalFuncs.Clear();
777 
778 	scriptTypeBehaviours.ReleaseAllFunctions();
779 	functionBehaviours.ReleaseAllFunctions();
780 
781 	for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ )
782 		if( scriptFunctions[n] )
783 		{
784 			scriptFunctions[n]->DestroyInternal();
785 
786 			// Set the engine pointer to null to signal that the function is no longer part of the engine
787 			scriptFunctions[n]->engine = 0;
788 		}
789 	scriptFunctions.SetLength(0);
790 
791 	// Increase the internal ref count for these builtin object types, so the destructor is not called incorrectly
792 	scriptTypeBehaviours.AddRefInternal();
793 	functionBehaviours.AddRefInternal();
794 
795 	// Destroy the funcdefs
796 	// As funcdefs are shared between modules it shouldn't be a problem to keep the objects until the engine is released
797 	for( asUINT n = 0; n < funcDefs.GetLength(); n++ )
798 		if( funcDefs[n] )
799 		{
800 			funcDefs[n]->DestroyInternal();
801 			funcDefs[n]->ReleaseInternal();
802 		}
803 	funcDefs.SetLength(0);
804 
805 	// Free the global properties
806 	for( asUINT n = 0; n < globalProperties.GetLength(); n++ )
807 	{
808 		asCGlobalProperty *prop = globalProperties[n];
809 		if( prop )
810 		{
811 			asASSERT( prop->refCount.get() == 1 );
812 			RemoveGlobalProperty(prop);
813 		}
814 	}
815 
816 	// Free the script section names
817 	for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ )
818 		asDELETE(scriptSectionNames[n],asCString);
819 	scriptSectionNames.SetLength(0);
820 
821 	// Clean the user data
822 	for( asUINT n = 0; n < userData.GetLength(); n += 2 )
823 	{
824 		if( userData[n+1] )
825 		{
826 			for( asUINT c = 0; c < cleanEngineFuncs.GetLength(); c++ )
827 				if( cleanEngineFuncs[c].type == userData[n] )
828 					cleanEngineFuncs[c].cleanFunc(this);
829 		}
830 	}
831 
832 	// Free namespaces
833 	for( asUINT n = 0; n < nameSpaces.GetLength(); n++ )
834 		asDELETE(nameSpaces[n], asSNameSpace);
835 	nameSpaces.SetLength(0);
836 
837 	asCThreadManager::Unprepare();
838 }
839 
840 // interface
SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx,asRETURNCONTEXTFUNC_t returnCtx,void * param)841 int asCScriptEngine::SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param)
842 {
843 	// Both callbacks or neither must be set
844 	if( (requestCtx == 0 && returnCtx != 0) || (requestCtx != 0 && returnCtx == 0) )
845 		return asINVALID_ARG;
846 
847 	requestCtxFunc   = requestCtx;
848 	returnCtxFunc    = returnCtx;
849 	ctxCallbackParam = param;
850 
851 	return 0;
852 }
853 
854 // interface
RequestContext()855 asIScriptContext *asCScriptEngine::RequestContext()
856 {
857 	if( requestCtxFunc )
858 	{
859 		// The return callback must also exist
860 		asASSERT( returnCtxFunc );
861 
862 		asIScriptContext *ctx = requestCtxFunc(this, ctxCallbackParam);
863 		return ctx;
864 	}
865 
866 	// As fallback we create a new context
867 	return CreateContext();
868 }
869 
870 // internal
FindNewOwnerForSharedType(asCTypeInfo * in_type,asCModule * in_mod)871 asCModule *asCScriptEngine::FindNewOwnerForSharedType(asCTypeInfo *in_type, asCModule *in_mod)
872 {
873 	asASSERT( in_type->IsShared() );
874 
875 	if( in_type->module != in_mod)
876 		return in_type->module;
877 
878 	for( asUINT n = 0; n < scriptModules.GetLength(); n++ )
879 	{
880 		// TODO: optimize: If the modules already stored the shared types separately, this would be quicker
881 		int foundIdx = -1;
882 		asCModule *mod = scriptModules[n];
883 		if( mod == in_type->module ) continue;
884 		if( in_type->flags & asOBJ_ENUM )
885 			foundIdx = mod->enumTypes.IndexOf(CastToEnumType(in_type));
886 		else if (in_type->flags & asOBJ_TYPEDEF)
887 			foundIdx = mod->typeDefs.IndexOf(CastToTypedefType(in_type));
888 		else if (in_type->flags & asOBJ_FUNCDEF)
889 			foundIdx = mod->funcDefs.IndexOf(CastToFuncdefType(in_type));
890 		else
891 			foundIdx = mod->classTypes.IndexOf(CastToObjectType(in_type));
892 
893 		if( foundIdx >= 0 )
894 		{
895 			in_type->module = mod;
896 			break;
897 		}
898 	}
899 
900 	return in_type->module;
901 }
902 
903 // internal
FindNewOwnerForSharedFunc(asCScriptFunction * in_func,asCModule * in_mod)904 asCModule *asCScriptEngine::FindNewOwnerForSharedFunc(asCScriptFunction *in_func, asCModule *in_mod)
905 {
906 	asASSERT( in_func->IsShared() );
907 	asASSERT(!(in_func->funcType & asFUNC_FUNCDEF));
908 
909 	if( in_func->module != in_mod)
910 		return in_func->module;
911 
912 	for( asUINT n = 0; n < scriptModules.GetLength(); n++ )
913 	{
914 		// TODO: optimize: If the modules already stored the shared types separately, this would be quicker
915 		int foundIdx = -1;
916 		asCModule *mod = scriptModules[n];
917 		if( mod == in_func->module ) continue;
918 		foundIdx = mod->scriptFunctions.IndexOf(in_func);
919 
920 		if( foundIdx >= 0 )
921 		{
922 			in_func->module = mod;
923 			break;
924 		}
925 	}
926 
927 	return in_func->module;
928 }
929 
930 // interface
ReturnContext(asIScriptContext * ctx)931 void asCScriptEngine::ReturnContext(asIScriptContext *ctx)
932 {
933 	if( returnCtxFunc )
934 	{
935 		returnCtxFunc(this, ctx, ctxCallbackParam);
936 		return;
937 	}
938 
939 	// As fallback we just release the context
940 	if( ctx )
941 		ctx->Release();
942 }
943 
944 // interface
AddRef() const945 int asCScriptEngine::AddRef() const
946 {
947 	asASSERT( refCount.get() > 0 || inDestructor );
948 	return refCount.atomicInc();
949 }
950 
951 // interface
Release() const952 int asCScriptEngine::Release() const
953 {
954 	int r = refCount.atomicDec();
955 
956 	if( r == 0 )
957 	{
958 		// It is possible that some function will temporarily increment the engine ref count
959 		// during clean-up for example while destroying the objects in the garbage collector.
960 		if( !inDestructor )
961 			asDELETE(const_cast<asCScriptEngine*>(this),asCScriptEngine);
962 		return 0;
963 	}
964 
965 	return r;
966 }
967 
968 // interface
ShutDownAndRelease()969 int asCScriptEngine::ShutDownAndRelease()
970 {
971 	// Do a full garbage collection cycle to clean up any object that may still hold on to the engine
972 	GarbageCollect();
973 
974 	// Set the flag that the engine is being shutdown now. This will speed up
975 	// the process, and will also allow the engine to warn about invalid calls
976 	shuttingDown = true;
977 
978 	// Clear the context callbacks. If new context's are needed for the clean-up the engine will take care of this itself.
979 	// Context callbacks are normally used for pooling contexts, and if we allow new contexts to be created without being
980 	// immediately destroyed afterwards it means the engine's refcount will increase. This is turn may cause memory access
981 	// violations later on when the pool releases its contexts.
982 	SetContextCallbacks(0, 0, 0);
983 
984 	// The modules must be deleted first, as they may use
985 	// object types from the config groups
986 	for( asUINT n = (asUINT)scriptModules.GetLength(); n-- > 0; )
987 		if( scriptModules[n] )
988 			scriptModules[n]->Discard();
989 	scriptModules.SetLength(0);
990 
991 	// Do another full garbage collection to destroy the object types/functions
992 	// that may have been placed in the gc when destroying the modules
993 	GarbageCollect();
994 
995 	// Do another sweep to delete discarded modules, that may not have
996 	// been deleted earlier due to still having external references
997 	DeleteDiscardedModules();
998 
999 	// If the application hasn't registered GC behaviours for all types
1000 	// that can form circular references with script types, then there
1001 	// may still be objects in the GC.
1002 	gc.ReportAndReleaseUndestroyedObjects();
1003 
1004 	// Release the engine reference
1005 	return Release();
1006 }
1007 
1008 // internal
AddNameSpace(const char * name)1009 asSNameSpace *asCScriptEngine::AddNameSpace(const char *name)
1010 {
1011 	// First check if it doesn't exist already
1012 	asSNameSpace *ns = FindNameSpace(name);
1013 	if( ns ) return ns;
1014 
1015 	ns = asNEW(asSNameSpace);
1016 	if( ns == 0 )
1017 	{
1018 		// Out of memory
1019 		return 0;
1020 	}
1021 	ns->name = name;
1022 
1023 	nameSpaces.PushLast(ns);
1024 
1025 	return ns;
1026 }
1027 
1028 // internal
FindNameSpace(const char * name) const1029 asSNameSpace *asCScriptEngine::FindNameSpace(const char *name) const
1030 {
1031 	// TODO: optimize: Improve linear search
1032 	for( asUINT n = 0; n < nameSpaces.GetLength(); n++ )
1033 		if( nameSpaces[n]->name == name )
1034 			return nameSpaces[n];
1035 
1036 	return 0;
1037 }
1038 
1039 // interface
GetDefaultNamespace() const1040 const char *asCScriptEngine::GetDefaultNamespace() const
1041 {
1042 	return defaultNamespace->name.AddressOf();
1043 }
1044 
1045 // interface
SetDefaultNamespace(const char * nameSpace)1046 int asCScriptEngine::SetDefaultNamespace(const char *nameSpace)
1047 {
1048 	if( nameSpace == 0 )
1049 		return ConfigError(asINVALID_ARG, "SetDefaultNamespace", nameSpace, 0);
1050 
1051 	asCString ns = nameSpace;
1052 	if( ns != "" )
1053 	{
1054 		// Make sure the namespace is composed of alternating identifier and ::
1055 		size_t pos = 0;
1056 		bool expectIdentifier = true;
1057 		size_t len;
1058 		eTokenType t = ttIdentifier;
1059 
1060 		for( ; pos < ns.GetLength(); pos += len)
1061 		{
1062 			t = tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len);
1063 			if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) )
1064 				return ConfigError(asINVALID_DECLARATION, "SetDefaultNamespace", nameSpace, 0);
1065 
1066 			// Make sure parent namespaces are registred in case of nested namespaces
1067 			if (expectIdentifier)
1068 				AddNameSpace(ns.SubString(0, pos + len).AddressOf());
1069 
1070 			expectIdentifier = !expectIdentifier;
1071 		}
1072 
1073 		// If the namespace ends with :: then strip it off
1074 		if( t == ttScope )
1075 			ns.SetLength(ns.GetLength()-2);
1076 	}
1077 
1078 	defaultNamespace = AddNameSpace(ns.AddressOf());
1079 
1080 	return 0;
1081 }
1082 
1083 // interface
SetUserData(void * data,asPWORD type)1084 void *asCScriptEngine::SetUserData(void *data, asPWORD type)
1085 {
1086 	// As a thread might add a new new user data at the same time as another
1087 	// it is necessary to protect both read and write access to the userData member
1088 	ACQUIREEXCLUSIVE(engineRWLock);
1089 
1090 	// It is not intended to store a lot of different types of userdata,
1091 	// so a more complex structure like a associative map would just have
1092 	// more overhead than a simple array.
1093 	for( asUINT n = 0; n < userData.GetLength(); n += 2 )
1094 	{
1095 		if( userData[n] == type )
1096 		{
1097 			void *oldData = reinterpret_cast<void*>(userData[n+1]);
1098 			userData[n+1] = reinterpret_cast<asPWORD>(data);
1099 
1100 			RELEASEEXCLUSIVE(engineRWLock);
1101 
1102 			return oldData;
1103 		}
1104 	}
1105 
1106 	userData.PushLast(type);
1107 	userData.PushLast(reinterpret_cast<asPWORD>(data));
1108 
1109 	RELEASEEXCLUSIVE(engineRWLock);
1110 
1111 	return 0;
1112 }
1113 
1114 // interface
GetUserData(asPWORD type) const1115 void *asCScriptEngine::GetUserData(asPWORD type) const
1116 {
1117 	// There may be multiple threads reading, but when
1118 	// setting the user data nobody must be reading.
1119 	ACQUIRESHARED(engineRWLock);
1120 
1121 	for( asUINT n = 0; n < userData.GetLength(); n += 2 )
1122 	{
1123 		if( userData[n] == type )
1124 		{
1125 			RELEASESHARED(engineRWLock);
1126 			return reinterpret_cast<void*>(userData[n+1]);
1127 		}
1128 	}
1129 
1130 	RELEASESHARED(engineRWLock);
1131 
1132 	return 0;
1133 }
1134 
1135 // interface
SetMessageCallback(const asSFuncPtr & callback,void * obj,asDWORD callConv)1136 int asCScriptEngine::SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv)
1137 {
1138 	msgCallback = true;
1139 	msgCallbackObj = obj;
1140 	bool isObj = false;
1141 	if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST )
1142 	{
1143 		msgCallback = false;
1144 		return asNOT_SUPPORTED;
1145 	}
1146 	if( (unsigned)callConv >= asCALL_THISCALL )
1147 	{
1148 		isObj = true;
1149 		if( obj == 0 )
1150 		{
1151 			msgCallback = false;
1152 			return asINVALID_ARG;
1153 		}
1154 	}
1155 	int r = DetectCallingConvention(isObj, callback, callConv, 0, &msgCallbackFunc);
1156 	if( r < 0 ) msgCallback = false;
1157 	return r;
1158 }
1159 
1160 // interface
ClearMessageCallback()1161 int asCScriptEngine::ClearMessageCallback()
1162 {
1163 	msgCallback = false;
1164 	return 0;
1165 }
1166 
1167 // interface
WriteMessage(const char * section,int row,int col,asEMsgType type,const char * message)1168 int asCScriptEngine::WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message)
1169 {
1170 	// Validate input parameters
1171 	if( section == 0 ||
1172 		message == 0 )
1173 		return asINVALID_ARG;
1174 
1175 	// If there is no callback then there's nothing to do
1176 	if( !msgCallback )
1177 		return 0;
1178 
1179 	// If a pre-message has been set, then write that first
1180 	if( preMessage.isSet )
1181 	{
1182 		asSMessageInfo msg;
1183 		msg.section = preMessage.scriptname.AddressOf();
1184 		msg.row     = preMessage.r;
1185 		msg.col     = preMessage.c;
1186 		msg.type    = asMSGTYPE_INFORMATION;
1187 		msg.message = preMessage.message.AddressOf();
1188 
1189 		if( msgCallbackFunc.callConv < ICC_THISCALL )
1190 			CallGlobalFunction(&msg, msgCallbackObj, &msgCallbackFunc, 0);
1191 		else
1192 			CallObjectMethod(msgCallbackObj, &msg, &msgCallbackFunc, 0);
1193 
1194 		preMessage.isSet = false;
1195 	}
1196 
1197 	// Write the message to the callback
1198 	asSMessageInfo msg;
1199 	msg.section = section;
1200 	msg.row     = row;
1201 	msg.col     = col;
1202 	msg.type    = type;
1203 	msg.message = message;
1204 
1205 	if( msgCallbackFunc.callConv < ICC_THISCALL )
1206 		CallGlobalFunction(&msg, msgCallbackObj, &msgCallbackFunc, 0);
1207 	else
1208 		CallObjectMethod(msgCallbackObj, &msg, &msgCallbackFunc, 0);
1209 
1210 	return 0;
1211 }
1212 
SetJITCompiler(asIJITCompiler * compiler)1213 int asCScriptEngine::SetJITCompiler(asIJITCompiler *compiler)
1214 {
1215 	jitCompiler = compiler;
1216 	return asSUCCESS;
1217 }
1218 
GetJITCompiler() const1219 asIJITCompiler *asCScriptEngine::GetJITCompiler() const
1220 {
1221 	return jitCompiler;
1222 }
1223 
1224 // interface
ParseToken(const char * string,size_t stringLength,asUINT * tokenLength) const1225 asETokenClass asCScriptEngine::ParseToken(const char *string, size_t stringLength, asUINT *tokenLength) const
1226 {
1227 	if( stringLength == 0 )
1228 		stringLength = strlen(string);
1229 
1230 	size_t len;
1231 	asETokenClass tc;
1232 	tok.GetToken(string, stringLength, &len, &tc);
1233 
1234 	if( tokenLength )
1235 		*tokenLength = (asUINT)len;
1236 
1237 	return tc;
1238 }
1239 
1240 // interface
GetModule(const char * module,asEGMFlags flag)1241 asIScriptModule *asCScriptEngine::GetModule(const char *module, asEGMFlags flag)
1242 {
1243 	asCModule *mod = GetModule(module, false);
1244 
1245 	if( flag == asGM_ALWAYS_CREATE )
1246 	{
1247 		if( mod != 0 )
1248 			mod->Discard();
1249 
1250 		return GetModule(module, true);
1251 	}
1252 
1253 	if( mod == 0 && flag == asGM_CREATE_IF_NOT_EXISTS )
1254 		return GetModule(module, true);
1255 
1256 	return mod;
1257 }
1258 
1259 // interface
DiscardModule(const char * module)1260 int asCScriptEngine::DiscardModule(const char *module)
1261 {
1262 	asCModule *mod = GetModule(module, false);
1263 	if( mod == 0 ) return asNO_MODULE;
1264 
1265 	mod->Discard();
1266 
1267 	return 0;
1268 }
1269 
1270 // interface
GetModuleCount() const1271 asUINT asCScriptEngine::GetModuleCount() const
1272 {
1273 	ACQUIRESHARED(engineRWLock);
1274 	asUINT length = asUINT(scriptModules.GetLength());
1275 	RELEASESHARED(engineRWLock);
1276 	return length;
1277 }
1278 
1279 // interface
GetModuleByIndex(asUINT index) const1280 asIScriptModule *asCScriptEngine::GetModuleByIndex(asUINT index) const
1281 {
1282 	asIScriptModule *mod = 0;
1283 	ACQUIRESHARED(engineRWLock);
1284 	if( index < scriptModules.GetLength() )
1285 		mod = scriptModules[index];
1286 	RELEASESHARED(engineRWLock);
1287 	return mod;
1288 }
1289 
1290 // internal
GetFactoryIdByDecl(const asCObjectType * ot,const char * decl)1291 int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *decl)
1292 {
1293 	asCModule *mod = 0;
1294 
1295 	// Is this a script class?
1296 	if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size > 0 )
1297 		mod = scriptFunctions[ot->beh.factories[0]]->module;
1298 
1299 	asCBuilder bld(this, mod);
1300 
1301 	// Don't write parser errors to the message callback
1302 	bld.silent = true;
1303 
1304 	asCScriptFunction func(this, mod, asFUNC_DUMMY);
1305 	int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace);
1306 	if( r < 0 )
1307 		return asINVALID_DECLARATION;
1308 
1309 	// Search for matching factory function
1310 	int id = -1;
1311 	for( asUINT n = 0; n < ot->beh.factories.GetLength(); n++ )
1312 	{
1313 		asCScriptFunction *f = scriptFunctions[ot->beh.factories[n]];
1314 		if( f->IsSignatureEqual(&func) )
1315 		{
1316 			id = ot->beh.factories[n];
1317 			break;
1318 		}
1319 	}
1320 
1321 	if( id == -1 ) return asNO_FUNCTION;
1322 
1323 	return id;
1324 }
1325 
1326 
1327 // internal
GetMethodIdByDecl(const asCObjectType * ot,const char * decl,asCModule * mod)1328 int asCScriptEngine::GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod)
1329 {
1330 	asCBuilder bld(this, mod);
1331 
1332 	// Don't write parser errors to the message callback
1333 	bld.silent = true;
1334 
1335 	asCScriptFunction func(this, mod, asFUNC_DUMMY);
1336 
1337 	// Set the object type so that the signature can be properly compared
1338 	// This cast is OK, it will only be used for comparison
1339 	func.objectType = const_cast<asCObjectType*>(ot);
1340 	func.objectType->AddRefInternal();
1341 
1342 	int r = bld.ParseFunctionDeclaration(func.objectType, decl, &func, false);
1343 	if( r < 0 )
1344 		return asINVALID_DECLARATION;
1345 
1346 	// Search script functions for matching interface
1347 	int id = -1;
1348 	for( asUINT n = 0; n < ot->methods.GetLength(); ++n )
1349 	{
1350 		if( func.IsSignatureEqual(scriptFunctions[ot->methods[n]]) )
1351 		{
1352 			if( id == -1 )
1353 				id = ot->methods[n];
1354 			else
1355 				return asMULTIPLE_FUNCTIONS;
1356 		}
1357 	}
1358 
1359 	if( id == -1 ) return asNO_FUNCTION;
1360 
1361 	return id;
1362 }
1363 
1364 
1365 // internal
GetFunctionDeclaration(int funcId)1366 asCString asCScriptEngine::GetFunctionDeclaration(int funcId)
1367 {
1368 	asCString str;
1369 	asCScriptFunction *func = GetScriptFunction(funcId);
1370 	if( func )
1371 		str = func->GetDeclarationStr();
1372 
1373 	return str;
1374 }
1375 
1376 // internal
GetScriptFunction(int funcId) const1377 asCScriptFunction *asCScriptEngine::GetScriptFunction(int funcId) const
1378 {
1379 	if( funcId < 0 || funcId >= (int)scriptFunctions.GetLength() )
1380 		return 0;
1381 
1382 	return scriptFunctions[funcId];
1383 }
1384 
1385 
1386 // interface
CreateContext()1387 asIScriptContext *asCScriptEngine::CreateContext()
1388 {
1389 	asIScriptContext *ctx = 0;
1390 	CreateContext(&ctx, false);
1391 	return ctx;
1392 }
1393 
1394 // internal
CreateContext(asIScriptContext ** context,bool isInternal)1395 int asCScriptEngine::CreateContext(asIScriptContext **context, bool isInternal)
1396 {
1397 	*context = asNEW(asCContext)(this, !isInternal);
1398 	if( *context == 0 )
1399 		return asOUT_OF_MEMORY;
1400 
1401 	// We need to make sure the engine has been
1402 	// prepared before any context is executed
1403 	PrepareEngine();
1404 
1405 	return 0;
1406 }
1407 
1408 // interface
RegisterObjectProperty(const char * obj,const char * declaration,int byteOffset,int compositeOffset,bool isCompositeIndirect)1409 int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset, bool isCompositeIndirect)
1410 {
1411 	int r;
1412 	asCDataType dt;
1413 	asCBuilder bld(this, 0);
1414 	r = bld.ParseDataType(obj, &dt, defaultNamespace);
1415 	if( r < 0 )
1416 		return ConfigError(r, "RegisterObjectProperty", obj, declaration);
1417 
1418 	if (dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE)))
1419 		return ConfigError(asINVALID_OBJECT, "RegisterObjectProperty", obj, declaration);
1420 
1421 	// Don't allow modifying generated template instances
1422 	if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) )
1423 		return ConfigError(asINVALID_TYPE, "RegisterObjectProperty", obj, declaration);
1424 
1425 	// Verify that the correct config group is used
1426 	if( currentGroup->FindType(dt.GetTypeInfo()->name.AddressOf()) == 0 )
1427 		return ConfigError(asWRONG_CONFIG_GROUP, "RegisterObjectProperty", obj, declaration);
1428 
1429 	asCDataType type;
1430 	asCString name;
1431 
1432 	if( (r = bld.VerifyProperty(&dt, declaration, name, type, 0)) < 0 )
1433 		return ConfigError(r, "RegisterObjectProperty", obj, declaration);
1434 
1435 	// The VM currently only supports 16bit offsets
1436 	// TODO: The VM needs to have support for 32bit offsets. Probably with a second ADDSi instruction
1437 	//       However, when implementing this it is necessary for the bytecode serialization to support
1438 	//       the switch between the instructions upon loading bytecode as the offset may not be the
1439 	//       same on all platforms
1440 	if( byteOffset > 32767 || byteOffset < -32768 )
1441 		return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration);
1442 	// The composite offset must also obey the ADDSi restriction
1443 	if (compositeOffset > 32767 || compositeOffset < -32768)
1444 		return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration);
1445 
1446 	asCObjectProperty *prop = asNEW(asCObjectProperty);
1447 	if( prop == 0 )
1448 		return ConfigError(asOUT_OF_MEMORY, "RegisterObjectProperty", obj, declaration);
1449 
1450 	prop->name                = name;
1451 	prop->type                = type;
1452 	prop->byteOffset          = byteOffset;
1453 	prop->isPrivate           = false;
1454 	prop->isProtected         = false;
1455 	prop->compositeOffset     = compositeOffset;
1456 	prop->isCompositeIndirect = isCompositeIndirect;
1457 	prop->accessMask          = defaultAccessMask;
1458 
1459 	CastToObjectType(dt.GetTypeInfo())->properties.PushLast(prop);
1460 
1461 	// Add references to types so they are not released too early
1462 	if( type.GetTypeInfo() )
1463 	{
1464 		type.GetTypeInfo()->AddRefInternal();
1465 
1466 		// Add template instances to the config group
1467 		if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && !currentGroup->types.Exists(type.GetTypeInfo()) )
1468 			currentGroup->types.PushLast(type.GetTypeInfo());
1469 	}
1470 
1471 	currentGroup->AddReferencesForType(this, type.GetTypeInfo());
1472 
1473 	return asSUCCESS;
1474 }
1475 
1476 // interface
RegisterInterface(const char * name)1477 int asCScriptEngine::RegisterInterface(const char *name)
1478 {
1479 	if( name == 0 ) return ConfigError(asINVALID_NAME, "RegisterInterface", 0, 0);
1480 
1481 	// Verify if the name has been registered as a type already
1482 	if( GetRegisteredType(name, defaultNamespace) )
1483 		return asALREADY_REGISTERED;
1484 
1485 	// Use builder to parse the datatype
1486 	asCDataType dt;
1487 	asCBuilder bld(this, 0);
1488 	bool oldMsgCallback = msgCallback; msgCallback = false;
1489 	int r = bld.ParseDataType(name, &dt, defaultNamespace);
1490 	msgCallback = oldMsgCallback;
1491 	if( r >= 0 )
1492 	{
1493 		// If it is not in the defaultNamespace then the type was successfully parsed because
1494 		// it is declared in a parent namespace which shouldn't be treated as an error
1495 		if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace )
1496 			return ConfigError(asERROR, "RegisterInterface", name, 0);
1497 	}
1498 
1499 	// Make sure the name is not a reserved keyword
1500 	size_t tokenLen;
1501 	int token = tok.GetToken(name, strlen(name), &tokenLen);
1502 	if( token != ttIdentifier || strlen(name) != tokenLen )
1503 		return ConfigError(asINVALID_NAME, "RegisterInterface", name, 0);
1504 
1505 	r = bld.CheckNameConflict(name, 0, 0, defaultNamespace);
1506 	if( r < 0 )
1507 		return ConfigError(asNAME_TAKEN, "RegisterInterface", name, 0);
1508 
1509 	// Don't have to check against members of object
1510 	// types as they are allowed to use the names
1511 
1512 	// Register the object type for the interface
1513 	asCObjectType *st = asNEW(asCObjectType)(this);
1514 	if( st == 0 )
1515 		return ConfigError(asOUT_OF_MEMORY, "RegisterInterface", name, 0);
1516 
1517 	st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_SHARED;
1518 	st->size = 0; // Cannot be instantiated
1519 	st->name = name;
1520 	st->nameSpace = defaultNamespace;
1521 
1522 	// Use the default script class behaviours
1523 	st->beh.factory = 0;
1524 	st->beh.addref = scriptTypeBehaviours.beh.addref;
1525 	scriptFunctions[st->beh.addref]->AddRefInternal();
1526 	st->beh.release = scriptTypeBehaviours.beh.release;
1527 	scriptFunctions[st->beh.release]->AddRefInternal();
1528 	st->beh.copy = 0;
1529 
1530 	allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st);
1531 	registeredObjTypes.PushLast(st);
1532 
1533 	currentGroup->types.PushLast(st);
1534 
1535 	return GetTypeIdByDecl(name);
1536 }
1537 
1538 // interface
RegisterInterfaceMethod(const char * intf,const char * declaration)1539 int asCScriptEngine::RegisterInterfaceMethod(const char *intf, const char *declaration)
1540 {
1541 	// Verify that the correct config group is set.
1542 	if( currentGroup->FindType(intf) == 0 )
1543 		return ConfigError(asWRONG_CONFIG_GROUP, "RegisterInterfaceMethod", intf, declaration);
1544 
1545 	asCDataType dt;
1546 	asCBuilder bld(this, 0);
1547 	int r = bld.ParseDataType(intf, &dt, defaultNamespace);
1548 	if( r < 0 )
1549 		return ConfigError(r, "RegisterInterfaceMethod", intf, declaration);
1550 
1551 	asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_INTERFACE);
1552 	if( func == 0 )
1553 		return ConfigError(asOUT_OF_MEMORY, "RegisterInterfaceMethod", intf, declaration);
1554 
1555 	func->objectType = CastToObjectType(dt.GetTypeInfo());
1556 	func->objectType->AddRefInternal();
1557 
1558 	r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, false);
1559 	if( r < 0 )
1560 	{
1561 		func->funcType = asFUNC_DUMMY;
1562 		asDELETE(func,asCScriptFunction);
1563 		return ConfigError(asINVALID_DECLARATION, "RegisterInterfaceMethod", intf, declaration);
1564 	}
1565 
1566 	// Check name conflicts
1567 	r = bld.CheckNameConflictMember(dt.GetTypeInfo(), func->name.AddressOf(), 0, 0, false);
1568 	if( r < 0 )
1569 	{
1570 		func->funcType = asFUNC_DUMMY;
1571 		asDELETE(func,asCScriptFunction);
1572 		return ConfigError(asNAME_TAKEN, "RegisterInterfaceMethod", intf, declaration);
1573 	}
1574 
1575 	func->id = GetNextScriptFunctionId();
1576 	AddScriptFunction(func);
1577 
1578 	// The index into the interface's vftable chunk should be
1579 	// its index in the methods array.
1580 	func->vfTableIdx = int(func->objectType->methods.GetLength());
1581 
1582 	func->objectType->methods.PushLast(func->id);
1583 
1584 	func->ComputeSignatureId();
1585 
1586 	currentGroup->AddReferencesForFunc(this, func);
1587 
1588 	// Return function id as success
1589 	return func->id;
1590 }
1591 
RegisterObjectType(const char * name,int byteSize,asDWORD flags)1592 int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD flags)
1593 {
1594 	int r;
1595 
1596 	isPrepared = false;
1597 
1598 	// Verify flags
1599 	// Must have either asOBJ_REF or asOBJ_VALUE
1600 	if( flags & asOBJ_REF )
1601 	{
1602 		// Can optionally have the asOBJ_GC, asOBJ_NOHANDLE, asOBJ_SCOPED, or asOBJ_TEMPLATE flag set, but nothing else
1603 		if( flags & ~(asOBJ_REF | asOBJ_GC | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_TEMPLATE | asOBJ_NOCOUNT | asOBJ_IMPLICIT_HANDLE) )
1604 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1605 
1606 		// flags are exclusive
1607 		if( (flags & asOBJ_GC) && (flags & (asOBJ_NOHANDLE|asOBJ_SCOPED|asOBJ_NOCOUNT)) )
1608 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1609 		if( (flags & asOBJ_NOHANDLE) && (flags & (asOBJ_GC|asOBJ_SCOPED|asOBJ_NOCOUNT|asOBJ_IMPLICIT_HANDLE)) )
1610 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1611 		if( (flags & asOBJ_SCOPED) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_NOCOUNT|asOBJ_IMPLICIT_HANDLE)) )
1612 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1613 		if( (flags & asOBJ_NOCOUNT) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_SCOPED)) )
1614 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1615 
1616 		// Implicit handle is only allowed if the engine property for this is turned on
1617 		if( !ep.allowImplicitHandleTypes && (flags & asOBJ_IMPLICIT_HANDLE) )
1618 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1619 	}
1620 	else if( flags & asOBJ_VALUE )
1621 	{
1622 		// Cannot use reference flags
1623 		if( flags & (asOBJ_REF | asOBJ_GC | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_NOCOUNT | asOBJ_IMPLICIT_HANDLE) )
1624 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1625 
1626 		// Flags are exclusive
1627 		if( (flags & asOBJ_POD) && (flags & (asOBJ_ASHANDLE | asOBJ_TEMPLATE)) )
1628 			return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1629 
1630 		// If the app type is given, we must validate the flags
1631 		if( flags & asOBJ_APP_CLASS )
1632 		{
1633 			// Must not set the primitive or float flag
1634 			if( flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY) )
1635 				return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1636 		}
1637 		else
1638 		{
1639 			// Must not set the class properties, without the class flag
1640 			if( flags & (asOBJ_APP_CLASS_CONSTRUCTOR      |
1641 						 asOBJ_APP_CLASS_DESTRUCTOR       |
1642 						 asOBJ_APP_CLASS_ASSIGNMENT       |
1643 						 asOBJ_APP_CLASS_COPY_CONSTRUCTOR |
1644 						 asOBJ_APP_CLASS_ALLINTS          |
1645 						 asOBJ_APP_CLASS_ALLFLOATS) )
1646 			{
1647 				return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1648 			}
1649 		}
1650 
1651 		if( flags & asOBJ_APP_PRIMITIVE )
1652 		{
1653 			if( flags & (asOBJ_APP_CLASS |
1654 						 asOBJ_APP_FLOAT |
1655 						 asOBJ_APP_ARRAY) )
1656 				return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1657 		}
1658 		else if( flags & asOBJ_APP_FLOAT )
1659 		{
1660 			if( flags & (asOBJ_APP_CLASS     |
1661 						 asOBJ_APP_PRIMITIVE |
1662 						 asOBJ_APP_ARRAY) )
1663 				return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1664 		}
1665 		else if( flags & asOBJ_APP_ARRAY )
1666 		{
1667 			if( flags & (asOBJ_APP_CLASS     |
1668 						 asOBJ_APP_PRIMITIVE |
1669 						 asOBJ_APP_FLOAT) )
1670 				return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1671 		}
1672 	}
1673 	else
1674 		return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1675 
1676 	// Don't allow anything else than the defined flags
1677 #ifndef WIP_16BYTE_ALIGN
1678 	if( flags - (flags & asOBJ_MASK_VALID_FLAGS) )
1679 #else
1680 	if( flags - (flags & (asOBJ_MASK_VALID_FLAGS | asOBJ_APP_ALIGN16)) )
1681 #endif
1682 		return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1683 
1684 	// Value types must have a defined size
1685 	if( (flags & asOBJ_VALUE) && byteSize == 0 )
1686 	{
1687 		WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_VALUE_TYPE_MUST_HAVE_SIZE);
1688 		return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0);
1689 	}
1690 
1691 	// Verify type name
1692 	if( name == 0 )
1693 		return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0);
1694 
1695 	asCString typeName;
1696 	asCBuilder bld(this, 0);
1697 	if( flags & asOBJ_TEMPLATE )
1698 	{
1699 		asCArray<asCString> subtypeNames;
1700 		r = bld.ParseTemplateDecl(name, &typeName, subtypeNames);
1701 		if( r < 0 )
1702 			return ConfigError(r, "RegisterObjectType", name, 0);
1703 
1704 		// Verify that the template name hasn't been registered as a type already
1705 		if( GetRegisteredType(typeName, defaultNamespace) )
1706 			// This is not an irrepairable error, as it may just be that the same type is registered twice
1707 			return asALREADY_REGISTERED;
1708 
1709 		asCObjectType *type = asNEW(asCObjectType)(this);
1710 		if( type == 0 )
1711 			return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0);
1712 
1713 		type->name       = typeName;
1714 		type->nameSpace  = defaultNamespace;
1715 		type->size       = byteSize;
1716 #ifdef WIP_16BYTE_ALIGN
1717 		// TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries
1718 		type->alignment  = (flags & asOBJ_APP_ALIGN16) ? 16 : 4;
1719 #endif
1720 		type->flags      = flags;
1721 		type->accessMask = defaultAccessMask;
1722 
1723 		// Store it in the object types
1724 		allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
1725 		currentGroup->types.PushLast(type);
1726 		registeredObjTypes.PushLast(type);
1727 		registeredTemplateTypes.PushLast(type);
1728 
1729 		// Define the template subtypes
1730 		for( asUINT subTypeIdx = 0; subTypeIdx < subtypeNames.GetLength(); subTypeIdx++ )
1731 		{
1732 			asCTypeInfo *subtype = 0;
1733 			for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ )
1734 			{
1735 				if( templateSubTypes[n]->name == subtypeNames[subTypeIdx] )
1736 				{
1737 					subtype = templateSubTypes[n];
1738 					break;
1739 				}
1740 			}
1741 			if( subtype == 0 )
1742 			{
1743 				// Create the new subtype if not already existing
1744 				subtype = asNEW(asCTypeInfo)(this);
1745 				if( subtype == 0 )
1746 					return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0);
1747 
1748 				subtype->name      = subtypeNames[subTypeIdx];
1749 				subtype->size      = 0;
1750 				subtype->flags     = asOBJ_TEMPLATE_SUBTYPE;
1751 				templateSubTypes.PushLast(subtype);
1752 			}
1753 			type->templateSubTypes.PushLast(asCDataType::CreateType(subtype, false));
1754 			subtype->AddRefInternal();
1755 		}
1756 	}
1757 	else
1758 	{
1759 		typeName = name;
1760 
1761 		// Verify if the name has been registered as a type already
1762 		if( GetRegisteredType(typeName, defaultNamespace) )
1763 			// This is not an irrepairable error, as it may just be that the same type is registered twice
1764 			return asALREADY_REGISTERED;
1765 
1766 		// TODO: clean up: Is it really necessary to check here?
1767 		for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ )
1768 		{
1769 			if( templateInstanceTypes[n] &&
1770 				templateInstanceTypes[n]->name == typeName &&
1771 				templateInstanceTypes[n]->nameSpace == defaultNamespace )
1772 				// This is not an irrepairable error, as it may just be that the same type is registered twice
1773 				return asALREADY_REGISTERED;
1774 		}
1775 
1776 		// Keep the most recent template generated instance type, so we know what it was before parsing the datatype
1777 		asCObjectType *mostRecentTemplateInstanceType = 0;
1778 		asUINT originalSizeOfGeneratedTemplateTypes = (asUINT)generatedTemplateTypes.GetLength();
1779 		if( originalSizeOfGeneratedTemplateTypes )
1780 			mostRecentTemplateInstanceType = generatedTemplateTypes[originalSizeOfGeneratedTemplateTypes-1];
1781 
1782 		// Use builder to parse the datatype
1783 		asCDataType dt;
1784 		bool oldMsgCallback = msgCallback; msgCallback = false;
1785 		r = bld.ParseDataType(name, &dt, defaultNamespace);
1786 		msgCallback = oldMsgCallback;
1787 
1788 		// If the builder fails or the namespace is different than the default
1789 		// namespace, then the type name is new and it should be registered
1790 		if( r < 0 || dt.GetTypeInfo()->nameSpace != defaultNamespace )
1791 		{
1792 			// Make sure the name is not a reserved keyword
1793 			size_t tokenLen;
1794 			int token = tok.GetToken(name, typeName.GetLength(), &tokenLen);
1795 			if( token != ttIdentifier || typeName.GetLength() != tokenLen )
1796 				return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0);
1797 
1798 			r = bld.CheckNameConflict(name, 0, 0, defaultNamespace);
1799 			if( r < 0 )
1800 				return ConfigError(asNAME_TAKEN, "RegisterObjectType", name, 0);
1801 
1802 			// Don't have to check against members of object
1803 			// types as they are allowed to use the names
1804 
1805 			// Put the data type in the list
1806 			asCObjectType *type = asNEW(asCObjectType)(this);
1807 			if( type == 0 )
1808 				return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0);
1809 
1810 			type->name       = typeName;
1811 			type->nameSpace  = defaultNamespace;
1812 			type->size       = byteSize;
1813 #ifdef WIP_16BYTE_ALIGN
1814 			// TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries
1815 			type->alignment  = (flags & asOBJ_APP_ALIGN16) ? 16 : 4;
1816 #endif
1817 			type->flags      = flags;
1818 			type->accessMask = defaultAccessMask;
1819 
1820 			allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
1821 			registeredObjTypes.PushLast(type);
1822 
1823 			currentGroup->types.PushLast(type);
1824 		}
1825 		else
1826 		{
1827 			// The application is registering a template specialization so we
1828 			// need to replace the template instance type with the new type.
1829 
1830 			// TODO: Template: We don't require the lower dimensions to be registered first for registered template types
1831 			// int[][] must not be allowed to be registered
1832 			// if int[] hasn't been registered first
1833 			if( dt.GetSubType().IsTemplate() )
1834 				return ConfigError(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED, "RegisterObjectType", name, 0);
1835 
1836 			if( dt.IsReadOnly() ||
1837 				dt.IsReference() )
1838 				return ConfigError(asINVALID_TYPE, "RegisterObjectType", name, 0);
1839 
1840 			// Was the template instance type generated before?
1841 			if( generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) &&
1842 				generatedTemplateTypes[generatedTemplateTypes.GetLength()-1] == mostRecentTemplateInstanceType )
1843 			{
1844 				asCString str;
1845 				str.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, typeName.AddressOf());
1846 				WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1847 				return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0);
1848 			}
1849 
1850 			// If this is not a generated template instance type, then it means it is an
1851 			// already registered template specialization
1852 			if( !generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) )
1853 				return ConfigError(asALREADY_REGISTERED, "RegisterObjectType", name, 0);
1854 
1855 			// TODO: Add this again. The type is used by the factory stubs so we need to discount that
1856 			// Is the template instance type already being used?
1857 //			if( dt.GetTypeInfo()->GetRefCount() > 1 )
1858 //				return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0);
1859 
1860 			// Put the data type in the list
1861 			asCObjectType *type = asNEW(asCObjectType)(this);
1862 			if( type == 0 )
1863 				return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0);
1864 
1865 			type->name       = dt.GetTypeInfo()->name;
1866 			// The namespace will be the same as the original template type
1867 			type->nameSpace  = dt.GetTypeInfo()->nameSpace;
1868 			type->templateSubTypes.PushLast(dt.GetSubType());
1869 			for( asUINT s = 0; s < type->templateSubTypes.GetLength(); s++ )
1870 				if( type->templateSubTypes[s].GetTypeInfo() )
1871 					type->templateSubTypes[s].GetTypeInfo()->AddRefInternal();
1872 			type->size       = byteSize;
1873 #ifdef WIP_16BYTE_ALIGN
1874 			// TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries
1875 			type->alignment  = (flags & asOBJ_APP_ALIGN16) ? 16 : 4;
1876 #endif
1877 			type->flags      = flags;
1878 			type->accessMask = defaultAccessMask;
1879 
1880 			templateInstanceTypes.PushLast(type);
1881 
1882 			currentGroup->types.PushLast(type);
1883 
1884 			// Remove the template instance type, which will no longer be used.
1885 			// It is possible that multiple template instances are generated if
1886 			// they have any relationship, so all of them must be removed
1887 			while( generatedTemplateTypes.GetLength() > originalSizeOfGeneratedTemplateTypes )
1888 				RemoveTemplateInstanceType(generatedTemplateTypes[generatedTemplateTypes.GetLength()-1]);
1889 		}
1890 	}
1891 
1892 	// Return the type id as the success (except for template types)
1893 	if( flags & asOBJ_TEMPLATE )
1894 		return asSUCCESS;
1895 
1896 	return GetTypeIdByDecl(name);
1897 }
1898 
1899 // interface
RegisterObjectBehaviour(const char * datatype,asEBehaviours behaviour,const char * decl,const asSFuncPtr & funcPointer,asDWORD callConv,void * auxiliary,int compositeOffset,bool isCompositeIndirect)1900 int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect)
1901 {
1902 	if( datatype == 0 ) return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", datatype, decl);
1903 
1904 	// Determine the object type
1905 	asCBuilder bld(this, 0);
1906 	asCDataType type;
1907 	int r = bld.ParseDataType(datatype, &type, defaultNamespace);
1908 	if( r < 0 )
1909 		return ConfigError(r, "RegisterObjectBehaviour", datatype, decl);
1910 
1911 	if( type.GetTypeInfo() == 0 || (type.IsObjectHandle() && !(type.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE)) )
1912 		return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl);
1913 
1914 	// Don't allow application to modify built-in types
1915 	if( type.GetTypeInfo() == &functionBehaviours ||
1916 		type.GetTypeInfo() == &scriptTypeBehaviours )
1917 		return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl);
1918 
1919 	if( type.IsReadOnly() || type.IsReference() )
1920 		return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl);
1921 
1922 	// Don't allow modifying generated template instances
1923 	if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(type.GetTypeInfo())) )
1924 		return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl);
1925 
1926 	return RegisterBehaviourToObjectType(CastToObjectType(type.GetTypeInfo()), behaviour, decl, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect);
1927 }
1928 
1929 // internal
RegisterBehaviourToObjectType(asCObjectType * objectType,asEBehaviours behaviour,const char * decl,const asSFuncPtr & funcPointer,asDWORD callConv,void * auxiliary,int compositeOffset,bool isCompositeIndirect)1930 int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect)
1931 {
1932 #ifdef AS_MAX_PORTABILITY
1933 	if( callConv != asCALL_GENERIC )
1934 		return ConfigError(asNOT_SUPPORTED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
1935 #endif
1936 
1937 	asSSystemFunctionInterface internal;
1938 	bool isMethod = !(behaviour == asBEHAVE_FACTORY ||
1939 		              behaviour == asBEHAVE_LIST_FACTORY ||
1940 		              behaviour == asBEHAVE_TEMPLATE_CALLBACK);
1941 	int r = DetectCallingConvention(isMethod, funcPointer, callConv, auxiliary, &internal);
1942 	if( r < 0 )
1943 		return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
1944 
1945 	internal.compositeOffset = compositeOffset;
1946 	internal.isCompositeIndirect = isCompositeIndirect;
1947 	if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL )
1948 		return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
1949 
1950 	// TODO: cleanup: This is identical to what is in RegisterMethodToObjectType
1951 	// If the object type is a template, make sure there are no generated instances already
1952 	if( objectType->flags & asOBJ_TEMPLATE )
1953 	{
1954 		for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ )
1955 		{
1956 			asCObjectType *tmpl = generatedTemplateTypes[n];
1957 			if( tmpl->name == objectType->name &&
1958 				tmpl->nameSpace == objectType->nameSpace &&
1959 				!(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) )
1960 			{
1961 				asCString msg;
1962 				msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf());
1963 				WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf());
1964 				return ConfigError(asERROR, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
1965 			}
1966 		}
1967 	}
1968 
1969 	isPrepared = false;
1970 
1971 	asSTypeBehaviour *beh = &objectType->beh;
1972 
1973 	// Verify function declaration
1974 	asCScriptFunction func(this, 0, asFUNC_DUMMY);
1975 
1976 	bool expectListPattern = behaviour == asBEHAVE_LIST_FACTORY || behaviour == asBEHAVE_LIST_CONSTRUCT;
1977 	asCScriptNode *listPattern = 0;
1978 	asCBuilder bld(this, 0);
1979 	r = bld.ParseFunctionDeclaration(objectType, decl, &func, true, &internal.paramAutoHandles, &internal.returnAutoHandle, 0, expectListPattern ? &listPattern : 0);
1980 	if( r < 0 )
1981 	{
1982 		if( listPattern )
1983 			listPattern->Destroy(this);
1984 		return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
1985 	}
1986 	func.name.Format("$beh%d", behaviour);
1987 
1988 	if( behaviour != asBEHAVE_FACTORY && behaviour != asBEHAVE_LIST_FACTORY )
1989 	{
1990 		func.objectType = objectType;
1991 		func.objectType->AddRefInternal();
1992 	}
1993 
1994 	// Check if the method restricts that use of the template to value types or reference types
1995 	if( objectType->flags & asOBJ_TEMPLATE )
1996 	{
1997 		r = SetTemplateRestrictions(objectType, &func, "RegisterObjectBehaviour", decl);
1998 		if (r < 0)
1999 			return r;
2000 	}
2001 
2002 	if( behaviour == asBEHAVE_CONSTRUCT )
2003 	{
2004 		// Verify that the return type is void
2005 		if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
2006 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2007 
2008 		if( objectType->flags & asOBJ_SCRIPT_OBJECT )
2009 		{
2010 			// The script object is a special case
2011 			asASSERT(func.parameterTypes.GetLength() == 1);
2012 
2013 			beh->construct = AddBehaviourFunction(func, internal);
2014 			beh->factory   = beh->construct;
2015 			scriptFunctions[beh->factory]->AddRefInternal();
2016 			beh->constructors.PushLast(beh->construct);
2017 			beh->factories.PushLast(beh->factory);
2018 			func.id = beh->construct;
2019 		}
2020 		else
2021 		{
2022 			// Verify that it is a value type
2023 			if( !(func.objectType->flags & asOBJ_VALUE) )
2024 			{
2025 				WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2026 				return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2027 			}
2028 
2029 			// The templates take a hidden parameter with the object type
2030 			if( (objectType->flags & asOBJ_TEMPLATE) &&
2031 				(func.parameterTypes.GetLength() == 0 ||
2032 				 !func.parameterTypes[0].IsReference()) )
2033 			{
2034 				WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY);
2035 				return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2036 			}
2037 
2038 			// TODO: Verify that the same constructor hasn't been registered already
2039 
2040 			// Store all constructors in a list
2041 			func.id = AddBehaviourFunction(func, internal);
2042 			beh->constructors.PushLast(func.id);
2043 			if( func.parameterTypes.GetLength() == 0 ||
2044 				(func.parameterTypes.GetLength() == 1 && (objectType->flags & asOBJ_TEMPLATE)) )
2045 			{
2046 				beh->construct = func.id;
2047 			}
2048 			else if( func.parameterTypes.GetLength() == 1 )
2049 			{
2050 				// Is this the copy constructor?
2051 				asCDataType paramType = func.parameterTypes[0];
2052 
2053 				// If the parameter is object, and const reference for input or inout,
2054 				// and same type as this class, then this is a copy constructor.
2055 				if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() &&
2056 					(func.inOutFlags[0] & asTM_INREF) && paramType.GetTypeInfo() == objectType )
2057 					beh->copyconstruct = func.id;
2058 			}
2059 		}
2060 	}
2061 	else if( behaviour == asBEHAVE_DESTRUCT )
2062 	{
2063 		// Must be a value type
2064 		if( !(func.objectType->flags & asOBJ_VALUE) )
2065 		{
2066 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2067 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2068 		}
2069 
2070 		if( beh->destruct )
2071 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2072 
2073 		// Verify that the return type is void
2074 		if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
2075 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2076 
2077 		// Verify that there are no parameters
2078 		if( func.parameterTypes.GetLength() > 0 )
2079 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2080 
2081 		func.id = beh->destruct = AddBehaviourFunction(func, internal);
2082 	}
2083 	else if( behaviour == asBEHAVE_LIST_CONSTRUCT )
2084 	{
2085 		// Verify that the return type is void
2086 		if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
2087 		{
2088 			if( listPattern )
2089 				listPattern->Destroy(this);
2090 
2091 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2092 		}
2093 
2094 		// Verify that it is a value type
2095 		if( !(func.objectType->flags & asOBJ_VALUE) )
2096 		{
2097 			if( listPattern )
2098 				listPattern->Destroy(this);
2099 
2100 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2101 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2102 		}
2103 
2104 		// Verify the parameters
2105 		if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() )
2106 		{
2107 			if( listPattern )
2108 				listPattern->Destroy(this);
2109 
2110 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM);
2111 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2112 		}
2113 
2114 		// Don't accept duplicates
2115 		if( beh->listFactory )
2116 		{
2117 			if( listPattern )
2118 				listPattern->Destroy(this);
2119 
2120 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2121 		}
2122 
2123 		// Add the function
2124 		func.id = AddBehaviourFunction(func, internal);
2125 
2126 		// Re-use the listFactory member, as it is not possible to have both anyway
2127 		beh->listFactory = func.id;
2128 
2129 		// Store the list pattern for this function
2130 		r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern);
2131 
2132 		if( listPattern )
2133 			listPattern->Destroy(this);
2134 
2135 		if( r < 0 )
2136 			return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2137 	}
2138 	else if( behaviour == asBEHAVE_FACTORY || behaviour == asBEHAVE_LIST_FACTORY )
2139 	{
2140 		// Must be a ref type and must not have asOBJ_NOHANDLE
2141 		if( !(objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_NOHANDLE) )
2142 		{
2143 			if( listPattern )
2144 				listPattern->Destroy(this);
2145 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2146 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2147 		}
2148 
2149 		// Verify that the return type is a handle to the type
2150 		if( func.returnType != asCDataType::CreateObjectHandle(objectType, false) )
2151 		{
2152 			if( listPattern )
2153 				listPattern->Destroy(this);
2154 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2155 		}
2156 
2157 		// The templates take a hidden parameter with the object type
2158 		if( (objectType->flags & asOBJ_TEMPLATE) &&
2159 			(func.parameterTypes.GetLength() == 0 ||
2160 			 !func.parameterTypes[0].IsReference()) )
2161 		{
2162 			if( listPattern )
2163 				listPattern->Destroy(this);
2164 
2165 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY);
2166 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2167 		}
2168 
2169 		if( behaviour == asBEHAVE_LIST_FACTORY )
2170 		{
2171 			// Make sure the factory takes a reference as its last parameter
2172 			if( objectType->flags & asOBJ_TEMPLATE )
2173 			{
2174 				if( func.parameterTypes.GetLength() != 2 || !func.parameterTypes[1].IsReference() )
2175 				{
2176 					if( listPattern )
2177 						listPattern->Destroy(this);
2178 
2179 					WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_TEMPLATE_LIST_FACTORY_EXPECTS_2_REF_PARAMS);
2180 					return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2181 				}
2182 			}
2183 			else
2184 			{
2185 				if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() )
2186 				{
2187 					if( listPattern )
2188 						listPattern->Destroy(this);
2189 
2190 					WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM);
2191 					return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2192 				}
2193 			}
2194 		}
2195 
2196 		// TODO: Verify that the same factory function hasn't been registered already
2197 
2198 		// Don't accept duplicates
2199 		if( behaviour == asBEHAVE_LIST_FACTORY && beh->listFactory )
2200 		{
2201 			if( listPattern )
2202 				listPattern->Destroy(this);
2203 
2204 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2205 		}
2206 
2207 		// Store all factory functions in a list
2208 		func.id = AddBehaviourFunction(func, internal);
2209 
2210 		// The list factory is a special factory and isn't stored together with the rest
2211 		if( behaviour != asBEHAVE_LIST_FACTORY )
2212 			beh->factories.PushLast(func.id);
2213 
2214 		if( (func.parameterTypes.GetLength() == 0) ||
2215 			(func.parameterTypes.GetLength() == 1 && (objectType->flags & asOBJ_TEMPLATE)) )
2216 		{
2217 			beh->factory = func.id;
2218 		}
2219 		else if( (func.parameterTypes.GetLength() == 1) ||
2220 				 (func.parameterTypes.GetLength() == 2 && (objectType->flags & asOBJ_TEMPLATE)) )
2221 		{
2222 			if( behaviour == asBEHAVE_LIST_FACTORY )
2223 			{
2224 				beh->listFactory = func.id;
2225 
2226 				// Store the list pattern for this function
2227 				r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern);
2228 
2229 				if( listPattern )
2230 					listPattern->Destroy(this);
2231 
2232 				if( r < 0 )
2233 					return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2234 			}
2235 			else
2236 			{
2237 				// Is this the copy factory?
2238 				asCDataType paramType = func.parameterTypes[func.parameterTypes.GetLength()-1];
2239 
2240 				// If the parameter is object, and const reference for input,
2241 				// and same type as this class, then this is a copy constructor.
2242 				if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && func.inOutFlags[func.parameterTypes.GetLength()-1] == asTM_INREF && paramType.GetTypeInfo() == objectType )
2243 					beh->copyfactory = func.id;
2244 			}
2245 		}
2246 	}
2247 	else if( behaviour == asBEHAVE_ADDREF )
2248 	{
2249 		// Must be a ref type and must not have asOBJ_NOHANDLE, nor asOBJ_SCOPED
2250 		if( !(func.objectType->flags & asOBJ_REF) ||
2251 			(func.objectType->flags & asOBJ_NOHANDLE) ||
2252 			(func.objectType->flags & asOBJ_SCOPED) ||
2253 			(func.objectType->flags & asOBJ_NOCOUNT) )
2254 		{
2255 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2256 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2257 		}
2258 
2259 		if( beh->addref )
2260 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2261 
2262 		// Verify that the return type is void
2263 		if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
2264 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2265 
2266 		// Verify that there are no parameters
2267 		if( func.parameterTypes.GetLength() > 0 )
2268 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2269 
2270 		func.id = beh->addref = AddBehaviourFunction(func, internal);
2271 	}
2272 	else if( behaviour == asBEHAVE_RELEASE )
2273 	{
2274 		// Must be a ref type and must not have asOBJ_NOHANDLE
2275 		if( !(func.objectType->flags & asOBJ_REF) ||
2276 			(func.objectType->flags & asOBJ_NOHANDLE) ||
2277 			(func.objectType->flags & asOBJ_NOCOUNT) )
2278 		{
2279 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2280 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2281 		}
2282 
2283 		if( beh->release )
2284 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2285 
2286 		// Verify that the return type is void
2287 		if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
2288 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2289 
2290 		// Verify that there are no parameters
2291 		if( func.parameterTypes.GetLength() > 0 )
2292 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2293 
2294 		func.id = beh->release = AddBehaviourFunction(func, internal);
2295 	}
2296 	else if( behaviour == asBEHAVE_TEMPLATE_CALLBACK )
2297 	{
2298 		// Must be a template type
2299 		if( !(func.objectType->flags & asOBJ_TEMPLATE) )
2300 		{
2301 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2302 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2303 		}
2304 
2305 		if( beh->templateCallback )
2306 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2307 
2308 		// Verify that the return type is bool
2309 		if( func.returnType != asCDataType::CreatePrimitive(ttBool, false) )
2310 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2311 
2312 		// Verify that there are two parameters
2313 		if( func.parameterTypes.GetLength() != 2 )
2314 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2315 
2316 		// The first parameter must be an inref (to receive the object type), and
2317 		// the second must be a bool out ref (to return if the type should or shouldn't be garbage collected)
2318 		if( func.inOutFlags[0] != asTM_INREF || func.inOutFlags[1] != asTM_OUTREF || !func.parameterTypes[1].IsEqualExceptRef(asCDataType::CreatePrimitive(ttBool, false)) )
2319 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2320 
2321 		func.id = beh->templateCallback = AddBehaviourFunction(func, internal);
2322 	}
2323 	else if( behaviour >= asBEHAVE_FIRST_GC &&
2324 		     behaviour <= asBEHAVE_LAST_GC )
2325 	{
2326 		// Only allow GC behaviours for types registered to be garbage collected
2327 		if( !(func.objectType->flags & asOBJ_GC) )
2328 		{
2329 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2330 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2331 		}
2332 
2333 		// Verify parameter count
2334 		if( (behaviour == asBEHAVE_GETREFCOUNT ||
2335 			 behaviour == asBEHAVE_SETGCFLAG   ||
2336 			 behaviour == asBEHAVE_GETGCFLAG) &&
2337 			func.parameterTypes.GetLength() != 0 )
2338 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2339 
2340 		if( (behaviour == asBEHAVE_ENUMREFS ||
2341 			 behaviour == asBEHAVE_RELEASEREFS) &&
2342 			func.parameterTypes.GetLength() != 1 )
2343 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2344 
2345 		// Verify return type
2346 		if( behaviour == asBEHAVE_GETREFCOUNT &&
2347 			func.returnType != asCDataType::CreatePrimitive(ttInt, false) )
2348 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2349 
2350 		if( behaviour == asBEHAVE_GETGCFLAG &&
2351 			func.returnType != asCDataType::CreatePrimitive(ttBool, false) )
2352 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2353 
2354 		if( (behaviour == asBEHAVE_SETGCFLAG ||
2355 			 behaviour == asBEHAVE_ENUMREFS  ||
2356 			 behaviour == asBEHAVE_RELEASEREFS) &&
2357 			func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
2358 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2359 
2360 		if( behaviour == asBEHAVE_GETREFCOUNT )
2361 			func.id = beh->gcGetRefCount = AddBehaviourFunction(func, internal);
2362 		else if( behaviour == asBEHAVE_SETGCFLAG )
2363 			func.id = beh->gcSetFlag = AddBehaviourFunction(func, internal);
2364 		else if( behaviour == asBEHAVE_GETGCFLAG )
2365 			func.id = beh->gcGetFlag = AddBehaviourFunction(func, internal);
2366 		else if( behaviour == asBEHAVE_ENUMREFS )
2367 			func.id = beh->gcEnumReferences = AddBehaviourFunction(func, internal);
2368 		else if( behaviour == asBEHAVE_RELEASEREFS )
2369 			func.id = beh->gcReleaseAllReferences = AddBehaviourFunction(func, internal);
2370 	}
2371 	else if ( behaviour == asBEHAVE_GET_WEAKREF_FLAG )
2372 	{
2373 		// This behaviour is only allowed for reference types
2374 		if( !(func.objectType->flags & asOBJ_REF) )
2375 		{
2376 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2377 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2378 		}
2379 
2380 		// Don't allow it if the type is registered with nohandle or scoped
2381 		if( func.objectType->flags & (asOBJ_NOHANDLE|asOBJ_SCOPED) )
2382 		{
2383 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
2384 			return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2385 		}
2386 
2387 		// Verify that the return type is a reference since it needs to return a pointer to an asISharedBool
2388 		if( !func.returnType.IsReference() )
2389 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2390 
2391 		// Verify that there are no parameters
2392 		if( func.parameterTypes.GetLength() != 0 )
2393 			return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2394 
2395 		if( beh->getWeakRefFlag )
2396 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2397 
2398 		func.id = beh->getWeakRefFlag = AddBehaviourFunction(func, internal);
2399 	}
2400 	else
2401 	{
2402 		asASSERT(false);
2403 
2404 		return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2405 	}
2406 
2407 	if( func.id < 0 )
2408 		return ConfigError(func.id, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
2409 
2410 	// Return function id as success
2411 	return func.id;
2412 }
2413 
SetTemplateRestrictions(asCObjectType * templateType,asCScriptFunction * func,const char * caller,const char * decl)2414 int asCScriptEngine::SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl)
2415 {
2416 	asASSERT(templateType->flags & asOBJ_TEMPLATE);
2417 
2418 	for (asUINT subTypeIdx = 0; subTypeIdx < templateType->templateSubTypes.GetLength(); subTypeIdx++)
2419 	{
2420 		if (func->returnType.GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo())
2421 		{
2422 			if (func->returnType.IsObjectHandle())
2423 				templateType->acceptValueSubType = false;
2424 			else if (!func->returnType.IsReference())
2425 				templateType->acceptRefSubType = false;
2426 
2427 			// Can't support template subtypes by value, since each type is treated differently in the ABI
2428 			if (!func->returnType.IsObjectHandle() && !func->returnType.IsReference())
2429 				return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl);
2430 		}
2431 
2432 		for (asUINT n = 0; n < func->parameterTypes.GetLength(); n++)
2433 		{
2434 			if (func->parameterTypes[n].GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo())
2435 			{
2436 				// TODO: If unsafe references are allowed, then inout references allow value types
2437 				if (func->parameterTypes[n].IsObjectHandle() || (func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF))
2438 					templateType->acceptValueSubType = false;
2439 				else if (!func->parameterTypes[n].IsReference())
2440 					templateType->acceptRefSubType = false;
2441 
2442 				// Can't support template subtypes by value, since each type is treated differently in the ABI
2443 				if (!func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference())
2444 					return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl);
2445 			}
2446 		}
2447 	}
2448 
2449 	return asSUCCESS;
2450 }
2451 
VerifyVarTypeNotInFunction(asCScriptFunction * func)2452 int asCScriptEngine::VerifyVarTypeNotInFunction(asCScriptFunction *func)
2453 {
2454 	// Don't allow var type in this function
2455 	if( func->returnType.GetTokenType() == ttQuestion )
2456 		return asINVALID_DECLARATION;
2457 
2458 	for( unsigned int n = 0; n < func->parameterTypes.GetLength(); n++ )
2459 		if( func->parameterTypes[n].GetTokenType() == ttQuestion )
2460 			return asINVALID_DECLARATION;
2461 
2462 	return 0;
2463 }
2464 
AddBehaviourFunction(asCScriptFunction & func,asSSystemFunctionInterface & internal)2465 int asCScriptEngine::AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal)
2466 {
2467 	asUINT n;
2468 
2469 	int id = GetNextScriptFunctionId();
2470 
2471 	asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal);
2472 	if( newInterface == 0 )
2473 		return asOUT_OF_MEMORY;
2474 
2475 	asCScriptFunction *f = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM);
2476 	if( f == 0 )
2477 	{
2478 		asDELETE(newInterface, asSSystemFunctionInterface);
2479 		return asOUT_OF_MEMORY;
2480 	}
2481 
2482 	asASSERT(func.name != "" && func.name != "f");
2483 	f->name           = func.name;
2484 	f->sysFuncIntf    = newInterface;
2485 	f->returnType     = func.returnType;
2486 	f->objectType     = func.objectType;
2487 	if( f->objectType )
2488 		f->objectType->AddRefInternal();
2489 	f->id             = id;
2490 	f->SetReadOnly(func.IsReadOnly());
2491 	f->accessMask     = defaultAccessMask;
2492 	f->parameterTypes = func.parameterTypes;
2493 	f->parameterNames = func.parameterNames;
2494 	f->inOutFlags     = func.inOutFlags;
2495 	for( n = 0; n < func.defaultArgs.GetLength(); n++ )
2496 		if( func.defaultArgs[n] )
2497 			f->defaultArgs.PushLast(asNEW(asCString)(*func.defaultArgs[n]));
2498 		else
2499 			f->defaultArgs.PushLast(0);
2500 
2501 	AddScriptFunction(f);
2502 
2503 	// If parameter type from other groups are used, add references
2504 	currentGroup->AddReferencesForFunc(this, f);
2505 
2506 	return id;
2507 }
2508 
2509 // interface
RegisterGlobalProperty(const char * declaration,void * pointer)2510 int asCScriptEngine::RegisterGlobalProperty(const char *declaration, void *pointer)
2511 {
2512 	// Don't accept a null pointer
2513 	if( pointer == 0 )
2514 		return ConfigError(asINVALID_ARG, "RegisterGlobalProperty", declaration, 0);
2515 
2516 	asCDataType type;
2517 	asCString name;
2518 
2519 	int r;
2520 	asCBuilder bld(this, 0);
2521 	if( (r = bld.VerifyProperty(0, declaration, name, type, defaultNamespace)) < 0 )
2522 		return ConfigError(r, "RegisterGlobalProperty", declaration, 0);
2523 
2524 	// Don't allow registering references as global properties
2525 	if( type.IsReference() )
2526 		return ConfigError(asINVALID_TYPE, "RegisterGlobalProperty", declaration, 0);
2527 
2528 	// Store the property info
2529 	asCGlobalProperty *prop = AllocateGlobalProperty();
2530 	prop->name        = name;
2531 	prop->nameSpace   = defaultNamespace;
2532 	prop->type        = type;
2533 	prop->accessMask  = defaultAccessMask;
2534 
2535 	prop->SetRegisteredAddress(pointer);
2536 	varAddressMap.Insert(prop->GetAddressOfValue(), prop);
2537 
2538 	registeredGlobalProps.Put(prop);
2539 	prop->AddRef();
2540 	currentGroup->globalProps.PushLast(prop);
2541 
2542 	currentGroup->AddReferencesForType(this, type.GetTypeInfo());
2543 
2544 	return asSUCCESS;
2545 }
2546 
2547 // internal
AllocateGlobalProperty()2548 asCGlobalProperty *asCScriptEngine::AllocateGlobalProperty()
2549 {
2550 	asCGlobalProperty *prop = asNEW(asCGlobalProperty);
2551 	if( prop == 0 )
2552 	{
2553 		// Out of memory
2554 		return 0;
2555 	}
2556 
2557 	// First check the availability of a free slot
2558 	if( freeGlobalPropertyIds.GetLength() )
2559 	{
2560 		prop->id = freeGlobalPropertyIds.PopLast();
2561 		globalProperties[prop->id] = prop;
2562 		return prop;
2563 	}
2564 
2565 	prop->id = (asUINT)globalProperties.GetLength();
2566 	globalProperties.PushLast(prop);
2567 	return prop;
2568 }
2569 
2570 // internal
RemoveGlobalProperty(asCGlobalProperty * prop)2571 void asCScriptEngine::RemoveGlobalProperty(asCGlobalProperty *prop)
2572 {
2573 	int index = globalProperties.IndexOf(prop);
2574 	if( index >= 0 )
2575 	{
2576 		freeGlobalPropertyIds.PushLast(index);
2577 		globalProperties[index] = 0;
2578 
2579 		asSMapNode<void*, asCGlobalProperty*> *node;
2580 		varAddressMap.MoveTo(&node, prop->GetAddressOfValue());
2581 		asASSERT(node);
2582 		if( node )
2583 			varAddressMap.Erase(node);
2584 
2585 		prop->Release();
2586 	}
2587 }
2588 
2589 // interface
GetGlobalPropertyCount() const2590 asUINT asCScriptEngine::GetGlobalPropertyCount() const
2591 {
2592 	return asUINT(registeredGlobalProps.GetSize());
2593 }
2594 
2595 // interface
2596 // TODO: If the typeId ever encodes the const flag, then the isConst parameter should be removed
GetGlobalPropertyByIndex(asUINT index,const char ** name,const char ** nameSpace,int * typeId,bool * isConst,const char ** configGroup,void ** pointer,asDWORD * accessMask) const2597 int asCScriptEngine::GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst, const char **configGroup, void **pointer, asDWORD *accessMask) const
2598 {
2599 	const asCGlobalProperty *prop = registeredGlobalProps.Get(index);
2600 	if( !prop )
2601 		return asINVALID_ARG;
2602 
2603 	if( name )       *name       = prop->name.AddressOf();
2604 	if( nameSpace )  *nameSpace  = prop->nameSpace->name.AddressOf();
2605 	if( typeId )     *typeId     = GetTypeIdFromDataType(prop->type);
2606 	if( isConst )    *isConst    = prop->type.IsReadOnly();
2607 	if( pointer )    *pointer    = prop->GetRegisteredAddress();
2608 	if( accessMask ) *accessMask = prop->accessMask;
2609 
2610 	if( configGroup )
2611 	{
2612 		asCConfigGroup *group = FindConfigGroupForGlobalVar(index);
2613 		if( group )
2614 			*configGroup = group->groupName.AddressOf();
2615 		else
2616 			*configGroup = 0;
2617 	}
2618 
2619 	return asSUCCESS;
2620 }
2621 
2622 // interface
GetGlobalPropertyIndexByName(const char * name) const2623 int asCScriptEngine::GetGlobalPropertyIndexByName(const char *name) const
2624 {
2625 	asSNameSpace *ns = defaultNamespace;
2626 
2627 	// Find the global var id
2628 	while( ns )
2629 	{
2630 		int id = registeredGlobalProps.GetFirstIndex(ns, name);
2631 		if( id >= 0 )
2632 			return id;
2633 
2634 		// Recursively search parent namespace
2635 		ns = GetParentNameSpace(ns);
2636 	}
2637 
2638 	return asNO_GLOBAL_VAR;
2639 }
2640 
2641 // interface
GetGlobalPropertyIndexByDecl(const char * decl) const2642 int asCScriptEngine::GetGlobalPropertyIndexByDecl(const char *decl) const
2643 {
2644 	// This const cast is OK. The builder won't modify the engine
2645 	asCBuilder bld(const_cast<asCScriptEngine*>(this), 0);
2646 
2647 	// Don't write parser errors to the message callback
2648 	bld.silent = true;
2649 
2650 	asCString name;
2651 	asSNameSpace *ns;
2652 	asCDataType dt;
2653 	int r = bld.ParseVariableDeclaration(decl, defaultNamespace, name, ns, dt);
2654 	if( r < 0 )
2655 		return r;
2656 
2657 	// Search for a match
2658 	while( ns )
2659 	{
2660 		int id = registeredGlobalProps.GetFirstIndex(ns, name, asCCompGlobPropType(dt));
2661 		if( id >= 0 )
2662 			return id;
2663 
2664 		ns = GetParentNameSpace(ns);
2665 	}
2666 
2667 	return asNO_GLOBAL_VAR;
2668 }
2669 
2670 // interface
RegisterObjectMethod(const char * obj,const char * declaration,const asSFuncPtr & funcPointer,asDWORD callConv,void * auxiliary,int compositeOffset,bool isCompositeIndirect)2671 int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect)
2672 {
2673 	if( obj == 0 )
2674 		return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration);
2675 
2676 	// Determine the object type
2677 	asCDataType dt;
2678 	asCBuilder bld(this, 0);
2679 	int r = bld.ParseDataType(obj, &dt, defaultNamespace);
2680 	if( r < 0 )
2681 		return ConfigError(r, "RegisterObjectMethod", obj, declaration);
2682 
2683 	// Don't allow application to modify primitives or handles
2684 	if( dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE)))
2685 		return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration);
2686 
2687 	// Don't allow application to modify built-in types or funcdefs
2688 	if( dt.GetTypeInfo() == &functionBehaviours ||
2689 		dt.GetTypeInfo() == &scriptTypeBehaviours ||
2690 		CastToFuncdefType(dt.GetTypeInfo()) )
2691 		return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration);
2692 
2693 	// Don't allow modifying generated template instances
2694 	if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) )
2695 		return ConfigError(asINVALID_TYPE, "RegisterObjectMethod", obj, declaration);
2696 
2697 	return RegisterMethodToObjectType(CastToObjectType(dt.GetTypeInfo()), declaration, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect);
2698 }
2699 
2700 // internal
RegisterMethodToObjectType(asCObjectType * objectType,const char * declaration,const asSFuncPtr & funcPointer,asDWORD callConv,void * auxiliary,int compositeOffset,bool isCompositeIndirect)2701 int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect)
2702 {
2703 #ifdef AS_MAX_PORTABILITY
2704 	if( callConv != asCALL_GENERIC )
2705 		return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2706 #endif
2707 
2708 	asSSystemFunctionInterface internal;
2709 	int r = DetectCallingConvention(true, funcPointer, callConv, auxiliary, &internal);
2710 	if( r < 0 )
2711 		return ConfigError(r, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2712 
2713 	internal.compositeOffset = compositeOffset;
2714 	internal.isCompositeIndirect = isCompositeIndirect;
2715 	if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL )
2716 		return ConfigError(asINVALID_ARG, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2717 
2718 	// TODO: cleanup: This is identical to what is in RegisterMethodToObjectType
2719 	// If the object type is a template, make sure there are no generated instances already
2720 	if( objectType->flags & asOBJ_TEMPLATE )
2721 	{
2722 		for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ )
2723 		{
2724 			asCObjectType *tmpl = generatedTemplateTypes[n];
2725 			if( tmpl->name == objectType->name &&
2726 				tmpl->nameSpace == objectType->nameSpace &&
2727 				!(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) )
2728 			{
2729 				asCString msg;
2730 				msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf());
2731 				WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf());
2732 				return ConfigError(asERROR, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2733 			}
2734 		}
2735 	}
2736 
2737 	isPrepared = false;
2738 
2739 	// Put the system function in the list of system functions
2740 	asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal);
2741 	if( newInterface == 0 )
2742 		return ConfigError(asOUT_OF_MEMORY, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2743 
2744 	asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM);
2745 	if( func == 0 )
2746 	{
2747 		asDELETE(newInterface, asSSystemFunctionInterface);
2748 		return ConfigError(asOUT_OF_MEMORY, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2749 	}
2750 
2751 	func->sysFuncIntf = newInterface;
2752 	func->objectType  = objectType;
2753 	func->objectType->AddRefInternal();
2754 
2755 	asCBuilder bld(this, 0);
2756 	r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle);
2757 	if( r < 0 )
2758 	{
2759 		// Set as dummy function before deleting
2760 		func->funcType = asFUNC_DUMMY;
2761 		asDELETE(func,asCScriptFunction);
2762 		return ConfigError(asINVALID_DECLARATION, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2763 	}
2764 
2765 	// Check name conflicts
2766 	r = bld.CheckNameConflictMember(objectType, func->name.AddressOf(), 0, 0, false);
2767 	if( r < 0 )
2768 	{
2769 		func->funcType = asFUNC_DUMMY;
2770 		asDELETE(func,asCScriptFunction);
2771 		return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2772 	}
2773 
2774 	// Check against duplicate methods
2775 	if( func->name == "opConv" || func->name == "opImplConv" || func->name == "opCast" || func->name == "opImplCast" )
2776 	{
2777 		// opConv and opCast are special methods that the compiler differentiates between by the return type
2778 		for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ )
2779 		{
2780 			asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]];
2781 			if( f->name == func->name &&
2782 				f->IsSignatureExceptNameEqual(func) )
2783 			{
2784 				func->funcType = asFUNC_DUMMY;
2785 				asDELETE(func,asCScriptFunction);
2786 				return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2787 			}
2788 		}
2789 	}
2790 	else
2791 	{
2792 		for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ )
2793 		{
2794 			asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]];
2795 			if( f->name == func->name &&
2796 				f->IsSignatureExceptNameAndReturnTypeEqual(func) )
2797 			{
2798 				func->funcType = asFUNC_DUMMY;
2799 				asDELETE(func,asCScriptFunction);
2800 				return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2801 			}
2802 		}
2803 	}
2804 
2805 	func->id = GetNextScriptFunctionId();
2806 	func->objectType->methods.PushLast(func->id);
2807 	func->accessMask = defaultAccessMask;
2808 	AddScriptFunction(func);
2809 
2810 	// If parameter type from other groups are used, add references
2811 	currentGroup->AddReferencesForFunc(this, func);
2812 
2813 	// Check if the method restricts that use of the template to value types or reference types
2814 	if( func->objectType->flags & asOBJ_TEMPLATE )
2815 	{
2816 		r = SetTemplateRestrictions(func->objectType, func, "RegisterObjectMethod", declaration);
2817 		if (r < 0)
2818 			return r;
2819 	}
2820 
2821 	// TODO: beh.copy member will be removed, so this is not necessary
2822 	// Is this the default copy behaviour?
2823 	if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && !func->IsReadOnly() &&
2824 		((objectType->flags & asOBJ_SCRIPT_OBJECT) || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateType(func->objectType, false))) )
2825 	{
2826 		if( func->objectType->beh.copy != 0 )
2827 			return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration);
2828 
2829 		func->objectType->beh.copy = func->id;
2830 		func->AddRefInternal();
2831 	}
2832 
2833 	// Return the function id as success
2834 	return func->id;
2835 }
2836 
2837 // interface
RegisterGlobalFunction(const char * declaration,const asSFuncPtr & funcPointer,asDWORD callConv,void * auxiliary)2838 int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary)
2839 {
2840 #ifdef AS_MAX_PORTABILITY
2841 	if( callConv != asCALL_GENERIC )
2842 		return ConfigError(asNOT_SUPPORTED, "RegisterGlobalFunction", declaration, 0);
2843 #endif
2844 
2845 	asSSystemFunctionInterface internal;
2846 	int r = DetectCallingConvention(false, funcPointer, callConv, auxiliary, &internal);
2847 	if( r < 0 )
2848 		return ConfigError(r, "RegisterGlobalFunction", declaration, 0);
2849 
2850 	isPrepared = false;
2851 
2852 	// Put the system function in the list of system functions
2853 	asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal);
2854 	if( newInterface == 0 )
2855 		return ConfigError(asOUT_OF_MEMORY, "RegisterGlobalFunction", declaration, 0);
2856 
2857 	asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM);
2858 	if( func == 0 )
2859 	{
2860 		asDELETE(newInterface, asSSystemFunctionInterface);
2861 		return ConfigError(asOUT_OF_MEMORY, "RegisterGlobalFunction", declaration, 0);
2862 	}
2863 
2864 	func->sysFuncIntf = newInterface;
2865 
2866 	asCBuilder bld(this, 0);
2867 	r = bld.ParseFunctionDeclaration(0, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle, defaultNamespace);
2868 	if( r < 0 )
2869 	{
2870 		// Set as dummy function before deleting
2871 		func->funcType = asFUNC_DUMMY;
2872 		asDELETE(func,asCScriptFunction);
2873 		return ConfigError(asINVALID_DECLARATION, "RegisterGlobalFunction", declaration, 0);
2874 	}
2875 
2876 	// TODO: namespace: What if the declaration defined an explicit namespace?
2877 	func->nameSpace = defaultNamespace;
2878 
2879 	// Check name conflicts
2880 	r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace);
2881 	if( r < 0 )
2882 	{
2883 		// Set as dummy function before deleting
2884 		func->funcType = asFUNC_DUMMY;
2885 		asDELETE(func,asCScriptFunction);
2886 		return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0);
2887 	}
2888 
2889 	// Make sure the function is not identical to a previously registered function
2890 	asUINT n;
2891 	const asCArray<unsigned int> &idxs = registeredGlobalFuncs.GetIndexes(func->nameSpace, func->name);
2892 	for( n = 0; n < idxs.GetLength(); n++ )
2893 	{
2894 		asCScriptFunction *f = registeredGlobalFuncs.Get(idxs[n]);
2895 		if( f->IsSignatureExceptNameAndReturnTypeEqual(func) )
2896 		{
2897 			func->funcType = asFUNC_DUMMY;
2898 			asDELETE(func,asCScriptFunction);
2899 			return ConfigError(asALREADY_REGISTERED, "RegisterGlobalFunction", declaration, 0);
2900 		}
2901 	}
2902 
2903 	func->id = GetNextScriptFunctionId();
2904 	AddScriptFunction(func);
2905 
2906 	currentGroup->scriptFunctions.PushLast(func);
2907 	func->accessMask = defaultAccessMask;
2908 	registeredGlobalFuncs.Put(func);
2909 
2910 	// If parameter type from other groups are used, add references
2911 	currentGroup->AddReferencesForFunc(this, func);
2912 
2913 	// Return the function id as success
2914 	return func->id;
2915 }
2916 
2917 // interface
GetGlobalFunctionCount() const2918 asUINT asCScriptEngine::GetGlobalFunctionCount() const
2919 {
2920 	// Don't count the builtin delegate factory
2921 	return asUINT(registeredGlobalFuncs.GetSize()-1);
2922 }
2923 
2924 // interface
GetGlobalFunctionByIndex(asUINT index) const2925 asIScriptFunction *asCScriptEngine::GetGlobalFunctionByIndex(asUINT index) const
2926 {
2927 	// Don't count the builtin delegate factory
2928 	index++;
2929 
2930 	if( index >= registeredGlobalFuncs.GetSize() )
2931 		return 0;
2932 
2933 	return static_cast<asIScriptFunction*>(const_cast<asCScriptFunction*>(registeredGlobalFuncs.Get(index)));
2934 }
2935 
2936 // interface
GetGlobalFunctionByDecl(const char * decl) const2937 asIScriptFunction *asCScriptEngine::GetGlobalFunctionByDecl(const char *decl) const
2938 {
2939 	asCBuilder bld(const_cast<asCScriptEngine*>(this), 0);
2940 
2941 	// Don't write parser errors to the message callback
2942 	bld.silent = true;
2943 
2944 	asCScriptFunction func(const_cast<asCScriptEngine*>(this), 0, asFUNC_DUMMY);
2945 	int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace);
2946 	if( r < 0 )
2947 		return 0;
2948 
2949 	asSNameSpace *ns = defaultNamespace;
2950 	// Search script functions for matching interface
2951 	while( ns )
2952 	{
2953 		asIScriptFunction *f = 0;
2954 		const asCArray<unsigned int> &idxs = registeredGlobalFuncs.GetIndexes(ns, func.name);
2955 		for( unsigned int n = 0; n < idxs.GetLength(); n++ )
2956 		{
2957 			const asCScriptFunction *funcPtr = registeredGlobalFuncs.Get(idxs[n]);
2958 			if( funcPtr->objectType == 0 &&
2959 				func.returnType                 == funcPtr->returnType &&
2960 				func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength()
2961 				)
2962 			{
2963 				bool match = true;
2964 				for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p )
2965 				{
2966 					if( func.parameterTypes[p] != funcPtr->parameterTypes[p] )
2967 					{
2968 						match = false;
2969 						break;
2970 					}
2971 				}
2972 
2973 				if( match )
2974 				{
2975 					if( f == 0 )
2976 						f = const_cast<asCScriptFunction*>(funcPtr);
2977 					else
2978 						// Multiple functions
2979 						return 0;
2980 				}
2981 			}
2982 		}
2983 
2984 		if( f )
2985 			return f;
2986 
2987 		// Recursively search parent namespaces
2988 		ns = GetParentNameSpace(ns);
2989 	}
2990 
2991 	return 0;
2992 }
2993 
2994 
GetRegisteredType(const asCString & type,asSNameSpace * ns) const2995 asCTypeInfo *asCScriptEngine::GetRegisteredType(const asCString &type, asSNameSpace *ns) const
2996 {
2997 	asSMapNode<asSNameSpaceNamePair, asCTypeInfo *> *cursor;
2998 	if( allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(ns, type)) )
2999 		return cursor->value;
3000 
3001 	return 0;
3002 }
3003 
3004 
3005 
3006 
PrepareEngine()3007 void asCScriptEngine::PrepareEngine()
3008 {
3009 	if( isPrepared ) return;
3010 	if( configFailed ) return;
3011 
3012 	asUINT n;
3013 	for( n = 0; n < scriptFunctions.GetLength(); n++ )
3014 	{
3015 		// Determine the host application interface
3016 		if( scriptFunctions[n] && scriptFunctions[n]->funcType == asFUNC_SYSTEM )
3017 		{
3018 			if( scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_FUNC ||
3019 				scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_METHOD )
3020 				PrepareSystemFunctionGeneric(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this);
3021 			else
3022 				PrepareSystemFunction(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this);
3023 		}
3024 	}
3025 
3026 	// Validate object type registrations
3027 	for( n = 0; n < registeredObjTypes.GetLength(); n++ )
3028 	{
3029 		asCObjectType *type = registeredObjTypes[n];
3030 		if( type && !(type->flags & asOBJ_SCRIPT_OBJECT) )
3031 		{
3032 			bool missingBehaviour = false;
3033 			const char *infoMsg = 0;
3034 
3035 			// Verify that GC types have all behaviours
3036 			if( type->flags & asOBJ_GC )
3037 			{
3038 				if( type->beh.addref                 == 0 ||
3039 					type->beh.release                == 0 ||
3040 					type->beh.gcGetRefCount          == 0 ||
3041 					type->beh.gcSetFlag              == 0 ||
3042 					type->beh.gcGetFlag              == 0 ||
3043 					type->beh.gcEnumReferences       == 0 ||
3044 					type->beh.gcReleaseAllReferences == 0 )
3045 				{
3046 					infoMsg = TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR;
3047 					missingBehaviour = true;
3048 				}
3049 			}
3050 			// Verify that scoped ref types have the release behaviour
3051 			else if( type->flags & asOBJ_SCOPED )
3052 			{
3053 				if( type->beh.release == 0 )
3054 				{
3055 					infoMsg = TXT_SCOPE_REQUIRE_REL_BEHAVIOUR;
3056 					missingBehaviour = true;
3057 				}
3058 			}
3059 			// Verify that ref types have add ref and release behaviours
3060 			else if( (type->flags & asOBJ_REF) &&
3061 				     !(type->flags & asOBJ_NOHANDLE) &&
3062 					 !(type->flags & asOBJ_NOCOUNT) )
3063 			{
3064 				if( type->beh.addref  == 0 ||
3065 					type->beh.release == 0 )
3066 				{
3067 					infoMsg = TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR;
3068 					missingBehaviour = true;
3069 				}
3070 			}
3071 			// Verify that non-pod value types have the constructor and destructor registered
3072 			else if( (type->flags & asOBJ_VALUE) &&
3073 				     !(type->flags & asOBJ_POD) )
3074 			{
3075 				if( type->beh.constructors.GetLength() == 0 ||
3076 					type->beh.destruct  == 0 )
3077 				{
3078 					infoMsg = TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR;
3079 					missingBehaviour = true;
3080 				}
3081 			}
3082 
3083 			if( missingBehaviour )
3084 			{
3085 				asCString str;
3086 				str.Format(TXT_TYPE_s_IS_MISSING_BEHAVIOURS, type->name.AddressOf());
3087 				WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
3088 				WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, infoMsg);
3089 				ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
3090 			}
3091 		}
3092 	}
3093 
3094 	isPrepared = true;
3095 }
3096 
ConfigError(int err,const char * funcName,const char * arg1,const char * arg2)3097 int asCScriptEngine::ConfigError(int err, const char *funcName, const char *arg1, const char *arg2)
3098 {
3099 	configFailed = true;
3100 	if( funcName )
3101 	{
3102 		asCString str;
3103 		if( arg1 )
3104 		{
3105 			if( arg2 )
3106 				str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_d, funcName, arg1, arg2, err);
3107 			else
3108 				str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, funcName, arg1, err);
3109 		}
3110 		else
3111 			str.Format(TXT_FAILED_IN_FUNC_s_d, funcName, err);
3112 
3113 		WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
3114 	}
3115 	return err;
3116 }
3117 
3118 // interface
RegisterDefaultArrayType(const char * type)3119 int asCScriptEngine::RegisterDefaultArrayType(const char *type)
3120 {
3121 	asCBuilder bld(this, 0);
3122 	asCDataType dt;
3123 	int r = bld.ParseDataType(type, &dt, defaultNamespace);
3124 	if( r < 0 ) return r;
3125 
3126 	if( dt.GetTypeInfo() == 0 ||
3127 		!(dt.GetTypeInfo()->GetFlags() & asOBJ_TEMPLATE) )
3128 		return asINVALID_TYPE;
3129 
3130 	defaultArrayObjectType = CastToObjectType(dt.GetTypeInfo());
3131 	defaultArrayObjectType->AddRefInternal();
3132 
3133 	return 0;
3134 }
3135 
3136 // interface
GetDefaultArrayTypeId() const3137 int asCScriptEngine::GetDefaultArrayTypeId() const
3138 {
3139 	if( defaultArrayObjectType )
3140 		return GetTypeIdFromDataType(asCDataType::CreateType(defaultArrayObjectType, false));
3141 
3142 	return asINVALID_TYPE;
3143 }
3144 
3145 // interface
RegisterStringFactory(const char * datatype,asIStringFactory * factory)3146 int asCScriptEngine::RegisterStringFactory(const char *datatype, asIStringFactory *factory)
3147 {
3148 	if (factory == 0)
3149 		return ConfigError(asINVALID_ARG, "RegisterStringFactory", datatype, 0);
3150 
3151 	// Parse the data type
3152 	asCBuilder bld(this, 0);
3153 	asCDataType dt;
3154 	int r = bld.ParseDataType(datatype, &dt, defaultNamespace, true);
3155 	if (r < 0)
3156 		return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0);
3157 
3158 	// Validate the type. It must not be reference or handle
3159 	if (dt.IsReference() || dt.IsObjectHandle())
3160 		return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0);
3161 
3162 	// All string literals will be treated as const
3163 	dt.MakeReadOnly(true);
3164 
3165 	stringType = dt;
3166 	stringFactory = factory;
3167 
3168 	return asSUCCESS;
3169 }
3170 
3171 // interface
GetStringFactoryReturnTypeId(asDWORD * flags) const3172 int asCScriptEngine::GetStringFactoryReturnTypeId(asDWORD *flags) const
3173 {
3174 	if( stringFactory == 0 )
3175 		return asNO_FUNCTION;
3176 
3177 	if( flags )
3178 		*flags = 0;
3179 	return GetTypeIdFromDataType(stringType);
3180 }
3181 
3182 // internal
GetModule(const char * name,bool create)3183 asCModule *asCScriptEngine::GetModule(const char *name, bool create)
3184 {
3185 	// Accept null as well as zero-length string
3186 	if( name == 0 ) name = "";
3187 
3188 	asCModule *retModule = 0;
3189 
3190 	ACQUIRESHARED(engineRWLock);
3191 	if( lastModule && lastModule->name == name )
3192 		retModule = lastModule;
3193 	else
3194 	{
3195 		// TODO: optimize: Improve linear search
3196 		for( asUINT n = 0; n < scriptModules.GetLength(); ++n )
3197 			if( scriptModules[n] && scriptModules[n]->name == name )
3198 			{
3199 				retModule = scriptModules[n];
3200 				break;
3201 			}
3202 	}
3203 	RELEASESHARED(engineRWLock);
3204 
3205 	if( retModule )
3206 	{
3207 		ACQUIREEXCLUSIVE(engineRWLock);
3208 		lastModule = retModule;
3209 		RELEASEEXCLUSIVE(engineRWLock);
3210 
3211 		return retModule;
3212 	}
3213 
3214 	if( create )
3215 	{
3216 		retModule = asNEW(asCModule)(name, this);
3217 		if( retModule == 0 )
3218 		{
3219 			// Out of memory
3220 			return 0;
3221 		}
3222 
3223 		ACQUIREEXCLUSIVE(engineRWLock);
3224 		scriptModules.PushLast(retModule);
3225 		lastModule = retModule;
3226 		RELEASEEXCLUSIVE(engineRWLock);
3227 	}
3228 
3229 	return retModule;
3230 }
3231 
GetModuleFromFuncId(int id)3232 asCModule *asCScriptEngine::GetModuleFromFuncId(int id)
3233 {
3234 	if( id < 0 ) return 0;
3235 	if( id >= (int)scriptFunctions.GetLength() ) return 0;
3236 	asCScriptFunction *func = scriptFunctions[id];
3237 	if( func == 0 ) return 0;
3238 	return func->module;
3239 }
3240 
3241 // internal
RequestBuild()3242 int asCScriptEngine::RequestBuild()
3243 {
3244 	ACQUIREEXCLUSIVE(engineRWLock);
3245 	if( isBuilding )
3246 	{
3247 		RELEASEEXCLUSIVE(engineRWLock);
3248 		return asBUILD_IN_PROGRESS;
3249 	}
3250 	isBuilding = true;
3251 	RELEASEEXCLUSIVE(engineRWLock);
3252 
3253 	return 0;
3254 }
3255 
3256 // internal
BuildCompleted()3257 void asCScriptEngine::BuildCompleted()
3258 {
3259 	// Always free up pooled memory after a completed build
3260 	memoryMgr.FreeUnusedMemory();
3261 
3262 	isBuilding = false;
3263 }
3264 
RemoveTemplateInstanceType(asCObjectType * t)3265 void asCScriptEngine::RemoveTemplateInstanceType(asCObjectType *t)
3266 {
3267 	// If there is a module that still owns the generated type, then don't remove it
3268 	if( t->module )
3269 		return;
3270 
3271 	// Don't remove it if there are external refernces
3272 	if( t->externalRefCount.get() )
3273 		return;
3274 
3275 	// Only remove the template instance type if no config group is using it
3276 	if( defaultGroup.generatedTemplateInstances.Exists(t) )
3277 		return;
3278 	for( asUINT n = 0; n < configGroups.GetLength(); n++ )
3279 		if( configGroups[n]->generatedTemplateInstances.Exists(t) )
3280 			return;
3281 
3282 	t->DestroyInternal();
3283 	templateInstanceTypes.RemoveValue(t);
3284 	generatedTemplateTypes.RemoveValue(t);
3285 	t->ReleaseInternal();
3286 }
3287 
3288 // internal
GetTemplateInstanceType(asCObjectType * templateType,asCArray<asCDataType> & subTypes,asCModule * requestingModule)3289 asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateType, asCArray<asCDataType> &subTypes, asCModule *requestingModule)
3290 {
3291 	asUINT n;
3292 
3293 	// Is there any template instance type or template specialization already with this subtype?
3294 	for( n = 0; n < templateInstanceTypes.GetLength(); n++ )
3295 	{
3296 		asCObjectType *type = templateInstanceTypes[n];
3297 		if( type &&
3298 			type->name == templateType->name &&
3299 			type->templateSubTypes == subTypes )
3300 		{
3301 			// If the template instance is generated, then the module should hold a reference
3302 			// to it so the config group can determine see that the template type is in use.
3303 			// Template specializations will be treated as normal types
3304 			if( requestingModule && generatedTemplateTypes.Exists(type) )
3305 			{
3306 				if( type->module == 0 )
3307 				{
3308 					// Set the ownership of this template type
3309 					// It may be without ownership if it was previously created from application with for example GetTypeInfoByDecl
3310 					type->module = requestingModule;
3311 				}
3312 				if( !requestingModule->templateInstances.Exists(type) )
3313 				{
3314 					requestingModule->templateInstances.PushLast(type);
3315 					type->AddRefInternal();
3316 				}
3317 			}
3318 
3319 			return templateInstanceTypes[n];
3320 		}
3321 	}
3322 
3323 	// No previous template instance exists
3324 
3325 	// Make sure this template supports the subtype
3326 	for( n = 0; n < subTypes.GetLength(); n++ )
3327 	{
3328 		if( !templateType->acceptValueSubType && (subTypes[n].IsPrimitive() || (subTypes[n].GetTypeInfo()->flags & asOBJ_VALUE)) )
3329 			return 0;
3330 
3331 		if( !templateType->acceptRefSubType && (subTypes[n].IsObject() && (subTypes[n].GetTypeInfo()->flags & asOBJ_REF)) )
3332 			return 0;
3333 	}
3334 
3335 	// Create a new template instance type based on the templateType
3336 	asCObjectType *ot = asNEW(asCObjectType)(this);
3337 	if( ot == 0 )
3338 	{
3339 		// Out of memory
3340 		return 0;
3341 	}
3342 
3343 	ot->templateSubTypes = subTypes;
3344 	ot->flags            = templateType->flags;
3345 	ot->size             = templateType->size;
3346 	ot->name             = templateType->name;
3347 	ot->nameSpace        = templateType->nameSpace;
3348 
3349 	// If the template is being requested from a module, then the module should hold a reference to the type
3350 	if( requestingModule )
3351 	{
3352 		// Set the ownership of this template type
3353 		ot->module = requestingModule;
3354 		requestingModule->templateInstances.PushLast(ot);
3355 		ot->AddRefInternal();
3356 	}
3357 	else
3358 	{
3359 		// If the template type is not requested directly from a module, then set the ownership
3360 		// of it to the same module as one of the subtypes. If none of the subtypes are owned by]
3361 		// any module, the template instance will be without ownership and can be removed from the
3362 		// engine at any time (unless the application holds an external reference).
3363 		for( n = 0; n < subTypes.GetLength(); n++ )
3364 		{
3365 			if( subTypes[n].GetTypeInfo() )
3366 			{
3367 				ot->module = subTypes[n].GetTypeInfo()->module;
3368 				if( ot->module )
3369 				{
3370 					ot->module->templateInstances.PushLast(ot);
3371 					ot->AddRefInternal();
3372 					break;
3373 				}
3374 			}
3375 		}
3376 	}
3377 
3378 	// Before filling in the methods, call the template instance callback behaviour to validate the type
3379 	if( templateType->beh.templateCallback )
3380 	{
3381 		// If the validation is deferred then the validation will be done later,
3382 		// so it is necessary to continue the preparation of the template instance type
3383 		if( !deferValidationOfTemplateTypes )
3384 		{
3385 			asCScriptFunction *callback = scriptFunctions[templateType->beh.templateCallback];
3386 
3387 			bool dontGarbageCollect = false;
3388 			if( !CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) )
3389 			{
3390 				// The type cannot be instantiated
3391 				ot->templateSubTypes.SetLength(0);
3392 				if( ot->module )
3393 				{
3394 					ot->module->templateInstances.RemoveValue(ot);
3395 					ot->ReleaseInternal();
3396 				}
3397 				ot->ReleaseInternal();
3398 				return 0;
3399 			}
3400 
3401 			// If the callback said this template instance won't be garbage collected then remove the flag
3402 			if( dontGarbageCollect )
3403 				ot->flags &= ~asOBJ_GC;
3404 		}
3405 
3406 		ot->beh.templateCallback = templateType->beh.templateCallback;
3407 		scriptFunctions[ot->beh.templateCallback]->AddRefInternal();
3408 	}
3409 
3410 	ot->methods = templateType->methods;
3411 	for( n = 0; n < ot->methods.GetLength(); n++ )
3412 		scriptFunctions[ot->methods[n]]->AddRefInternal();
3413 
3414 	if( templateType->flags & asOBJ_REF )
3415 	{
3416 		// Store the real factory in the constructor. This is used by the CreateScriptObject function.
3417 		// Otherwise it wouldn't be necessary to store the real factory ids.
3418 		ot->beh.construct = templateType->beh.factory;
3419 		ot->beh.constructors = templateType->beh.factories;
3420 	}
3421 	else
3422 	{
3423 		ot->beh.construct = templateType->beh.construct;
3424 		ot->beh.constructors = templateType->beh.constructors;
3425 	}
3426 	for( n = 0; n < ot->beh.constructors.GetLength(); n++ )
3427 		scriptFunctions[ot->beh.constructors[n]]->AddRefInternal();
3428 
3429 
3430 	// Before proceeding with the generation of the template functions for the template instance it is necessary
3431 	// to include the new template instance type in the list of known types, otherwise it is possible that we get
3432 	// a infinite recursive loop as the template instance type is requested again during the generation of the
3433 	// template functions.
3434 	templateInstanceTypes.PushLast(ot);
3435 
3436 	// Store the template instance types that have been created automatically by the engine from a template type
3437 	// The object types in templateInstanceTypes that are not also in generatedTemplateTypes are registered template specializations
3438 	generatedTemplateTypes.PushLast(ot);
3439 
3440 	// Any child funcdefs must be copied to the template instance (with adjustments in case of template subtypes)
3441 	// This must be done before resolving other methods, to make sure the other methods that may refer to the
3442 	// templated funcdef will resolve to the new funcdef
3443 	for (n = 0; n < templateType->childFuncDefs.GetLength(); n++)
3444 	{
3445 		asCFuncdefType *funcdef = GenerateNewTemplateFuncdef(templateType, ot, templateType->childFuncDefs[n]);
3446 		funcdef->parentClass = ot;
3447 		ot->childFuncDefs.PushLast(funcdef);
3448 	}
3449 
3450 	// As the new template type is instantiated the engine should
3451 	// generate new functions to substitute the ones with the template subtype.
3452 	for( n = 0; n < ot->beh.constructors.GetLength(); n++ )
3453 	{
3454 		int funcId = ot->beh.constructors[n];
3455 		asCScriptFunction *func = scriptFunctions[funcId];
3456 
3457 		if( GenerateNewTemplateFunction(templateType, ot, func, &func) )
3458 		{
3459 			// Release the old function, the new one already has its ref count set to 1
3460 			scriptFunctions[funcId]->ReleaseInternal();
3461 			ot->beh.constructors[n] = func->id;
3462 
3463 			if( ot->beh.construct == funcId )
3464 				ot->beh.construct = func->id;
3465 		}
3466 	}
3467 
3468 	ot->beh.factory = 0;
3469 
3470 	if( templateType->flags & asOBJ_REF )
3471 	{
3472 		// Generate factory stubs for each of the factories
3473 		for( n = 0; n < ot->beh.constructors.GetLength(); n++ )
3474 		{
3475 			asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, ot->beh.constructors[n]);
3476 
3477 			ot->beh.factories.PushLast(func->id);
3478 
3479 			// Set the default factory as well
3480 			if( ot->beh.constructors[n] == ot->beh.construct )
3481 				ot->beh.factory = func->id;
3482 		}
3483 	}
3484 	else
3485 	{
3486 		// Generate factory stubs for each of the constructors
3487 		for( n = 0; n < ot->beh.constructors.GetLength(); n++ )
3488 		{
3489 			asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, ot->beh.constructors[n]);
3490 
3491 			if( ot->beh.constructors[n] == ot->beh.construct )
3492 				ot->beh.construct = func->id;
3493 
3494 			// Release previous constructor
3495 			scriptFunctions[ot->beh.constructors[n]]->ReleaseInternal();
3496 
3497 			ot->beh.constructors[n] = func->id;
3498 		}
3499 	}
3500 
3501 	// Generate stub for the list factory as well
3502 	if( templateType->beh.listFactory )
3503 	{
3504 		asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, templateType->beh.listFactory);
3505 
3506 		// Rename the function to easily identify it in LoadByteCode
3507 		func->name = "$list";
3508 
3509 		ot->beh.listFactory = func->id;
3510 	}
3511 
3512 	ot->beh.addref = templateType->beh.addref;
3513 	if( scriptFunctions[ot->beh.addref] ) scriptFunctions[ot->beh.addref]->AddRefInternal();
3514 	ot->beh.release = templateType->beh.release;
3515 	if( scriptFunctions[ot->beh.release] ) scriptFunctions[ot->beh.release]->AddRefInternal();
3516 	ot->beh.destruct = templateType->beh.destruct;
3517 	if( scriptFunctions[ot->beh.destruct] ) scriptFunctions[ot->beh.destruct]->AddRefInternal();
3518 	ot->beh.copy = templateType->beh.copy;
3519 	if( scriptFunctions[ot->beh.copy] ) scriptFunctions[ot->beh.copy]->AddRefInternal();
3520 	ot->beh.gcGetRefCount = templateType->beh.gcGetRefCount;
3521 	if( scriptFunctions[ot->beh.gcGetRefCount] ) scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal();
3522 	ot->beh.gcSetFlag = templateType->beh.gcSetFlag;
3523 	if( scriptFunctions[ot->beh.gcSetFlag] ) scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal();
3524 	ot->beh.gcGetFlag = templateType->beh.gcGetFlag;
3525 	if( scriptFunctions[ot->beh.gcGetFlag] ) scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal();
3526 	ot->beh.gcEnumReferences = templateType->beh.gcEnumReferences;
3527 	if( scriptFunctions[ot->beh.gcEnumReferences] ) scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal();
3528 	ot->beh.gcReleaseAllReferences = templateType->beh.gcReleaseAllReferences;
3529 	if( scriptFunctions[ot->beh.gcReleaseAllReferences] ) scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal();
3530 	ot->beh.getWeakRefFlag = templateType->beh.getWeakRefFlag;
3531 	if( scriptFunctions[ot->beh.getWeakRefFlag] ) scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal();
3532 
3533 	// As the new template type is instantiated, the engine should
3534 	// generate new functions to substitute the ones with the template subtype.
3535 	for( n = 0; n < ot->methods.GetLength(); n++ )
3536 	{
3537 		int funcId = ot->methods[n];
3538 		asCScriptFunction *func = scriptFunctions[funcId];
3539 
3540 		if( GenerateNewTemplateFunction(templateType, ot, func, &func) )
3541 		{
3542 			// Release the old function, the new one already has its ref count set to 1
3543 			scriptFunctions[funcId]->ReleaseInternal();
3544 			ot->methods[n] = func->id;
3545 		}
3546 	}
3547 
3548 	// Increase ref counter for sub type if it is an object type
3549 	for( n = 0; n < ot->templateSubTypes.GetLength(); n++ )
3550 		if( ot->templateSubTypes[n].GetTypeInfo() )
3551 			ot->templateSubTypes[n].GetTypeInfo()->AddRefInternal();
3552 
3553 	// Copy the properties to the template instance
3554 	for( n = 0; n < templateType->properties.GetLength(); n++ )
3555 	{
3556 		asCObjectProperty *prop = templateType->properties[n];
3557 		ot->properties.PushLast(asNEW(asCObjectProperty)(*prop));
3558 		if( prop->type.GetTypeInfo() )
3559 			prop->type.GetTypeInfo()->AddRefInternal();
3560 	}
3561 
3562 	return ot;
3563 }
3564 
3565 // interface
GetWeakRefFlagOfScriptObject(void * obj,const asITypeInfo * type) const3566 asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const
3567 {
3568 	// Make sure it is not a null pointer
3569 	if( obj == 0 || type == 0 ) return 0;
3570 
3571 	const asCObjectType *objType = static_cast<const asCObjectType *>(type);
3572 	asILockableSharedBool *dest = 0;
3573 	if( objType->beh.getWeakRefFlag )
3574 	{
3575 		// Call the getweakrefflag behaviour
3576 		dest = reinterpret_cast<asILockableSharedBool*>(CallObjectMethodRetPtr(obj, objType->beh.getWeakRefFlag));
3577 	}
3578 	return dest;
3579 }
3580 
3581 // internal
3582 // orig is the parameter type that is to be replaced
3583 // tmpl is the registered template. Used to find which subtype is being replaced
3584 // ot is the new template instance that is being created. Used to find the target type
DetermineTypeForTemplate(const asCDataType & orig,asCObjectType * tmpl,asCObjectType * ot)3585 asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot)
3586 {
3587 	asCDataType dt;
3588 	if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) )
3589 	{
3590 		bool found = false;
3591 		for( asUINT n = 0; n < tmpl->templateSubTypes.GetLength(); n++ )
3592 		{
3593 			if( orig.GetTypeInfo() == tmpl->templateSubTypes[n].GetTypeInfo() )
3594 			{
3595 				found = true;
3596 				dt = ot->templateSubTypes[n];
3597 				if( orig.IsObjectHandle() && !ot->templateSubTypes[n].IsObjectHandle() )
3598 				{
3599 					dt.MakeHandle(true, true);
3600 					asASSERT(dt.IsObjectHandle());
3601 					if( orig.IsHandleToConst() )
3602 						dt.MakeHandleToConst(true);
3603 					dt.MakeReference(orig.IsReference());
3604 					dt.MakeReadOnly(orig.IsReadOnly());
3605 				}
3606 				else
3607 				{
3608 					// The target type is a handle, then check if the application
3609 					// wants this handle to be to a const object. This is done by
3610 					// flagging the type with 'if_handle_then_const' in the declaration.
3611 					if (dt.IsObjectHandle() && orig.HasIfHandleThenConst())
3612 						dt.MakeHandleToConst(true);
3613 
3614 					dt.MakeReference(orig.IsReference());
3615 					dt.MakeReadOnly(ot->templateSubTypes[n].IsReadOnly() || orig.IsReadOnly());
3616 				}
3617 				break;
3618 			}
3619 		}
3620 		asASSERT( found );
3621 		UNUSED_VAR( found );
3622 	}
3623 	else if( orig.GetTypeInfo() == tmpl )
3624 	{
3625 		if( orig.IsObjectHandle() )
3626 			dt = asCDataType::CreateObjectHandle(ot, false);
3627 		else
3628 			dt = asCDataType::CreateType(ot, false);
3629 
3630 		dt.MakeReference(orig.IsReference());
3631 		dt.MakeReadOnly(orig.IsReadOnly());
3632 	}
3633 	else if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
3634 	{
3635 		// The type is itself a template, so it is necessary to find the correct template instance type
3636 		asCArray<asCDataType> tmplSubTypes;
3637 		asCObjectType *origType = CastToObjectType(orig.GetTypeInfo());
3638 		bool needInstance = true;
3639 
3640 		// Find the matching replacements for the subtypes
3641 		for( asUINT n = 0; n < origType->templateSubTypes.GetLength(); n++ )
3642 		{
3643 			if( origType->templateSubTypes[n].GetTypeInfo() == 0 ||
3644 				!(origType->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) )
3645 			{
3646 				// The template is already an instance so we shouldn't attempt to create another instance
3647 				needInstance = false;
3648 				break;
3649 			}
3650 
3651 			for( asUINT m = 0; m < tmpl->templateSubTypes.GetLength(); m++ )
3652 				if( origType->templateSubTypes[n].GetTypeInfo() == tmpl->templateSubTypes[m].GetTypeInfo() )
3653 					tmplSubTypes.PushLast(ot->templateSubTypes[m]);
3654 
3655 			if( tmplSubTypes.GetLength() != n+1 )
3656 			{
3657 				asASSERT( false );
3658 				return orig;
3659 			}
3660 		}
3661 
3662 		asCObjectType *ntype = origType;
3663 		if( needInstance )
3664 		{
3665 			// Always find the original template type when creating a new template instance otherwise the
3666 			// generation will fail since it will attempt to create factory stubs when they already exists, etc
3667 			for( asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++ )
3668 				if( registeredTemplateTypes[n]->name == origType->name )
3669 				{
3670 					origType = registeredTemplateTypes[n];
3671 					break;
3672 				}
3673 
3674 			ntype = GetTemplateInstanceType(origType, tmplSubTypes, ot->module);
3675 			if( ntype == 0 )
3676 			{
3677 				// It not possible to instantiate the subtype
3678 				asASSERT( false );
3679 				ntype = tmpl;
3680 			}
3681 		}
3682 
3683 		if( orig.IsObjectHandle() )
3684 			dt = asCDataType::CreateObjectHandle(ntype, false);
3685 		else
3686 			dt = asCDataType::CreateType(ntype, false);
3687 
3688 		dt.MakeReference(orig.IsReference());
3689 		dt.MakeReadOnly(orig.IsReadOnly());
3690 	}
3691 	else if (orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(orig.GetTypeInfo())->parentClass == tmpl)
3692 	{
3693 		// The type is a child funcdef. Find the corresponding child funcdef in the template instance
3694 		for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++)
3695 		{
3696 			if (ot->childFuncDefs[n]->name == orig.GetTypeInfo()->name)
3697 			{
3698 				dt = orig;
3699 				dt.SetTypeInfo(ot->childFuncDefs[n]);
3700 			}
3701 		}
3702 	}
3703 	else
3704 		dt = orig;
3705 
3706 	return dt;
3707 }
3708 
3709 // internal
GenerateTemplateFactoryStub(asCObjectType * templateType,asCObjectType * ot,int factoryId)3710 asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *ot, int factoryId)
3711 {
3712 	asCScriptFunction *factory = scriptFunctions[factoryId];
3713 
3714 	// By first instantiating the function as a dummy and then changing it to be a script function
3715 	// I avoid having it added to the garbage collector. As it is known that this object will stay
3716 	// alive until the template instance is no longer used there is no need to have the GC check
3717 	// this function all the time.
3718 	asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_DUMMY);
3719 	if( func == 0 )
3720 	{
3721 		// Out of memory
3722 		return 0;
3723 	}
3724 
3725 	func->funcType = asFUNC_SCRIPT;
3726 	func->AllocateScriptFunctionData();
3727 	func->id = GetNextScriptFunctionId();
3728 	AddScriptFunction(func);
3729 
3730 	func->SetShared(true);
3731 	if( templateType->flags & asOBJ_REF )
3732 	{
3733 		func->name = "$fact";
3734 		func->returnType = asCDataType::CreateObjectHandle(ot, false);
3735 	}
3736 	else
3737 	{
3738 		func->name = "$beh0";
3739 		func->returnType = factory->returnType; // constructors return nothing
3740 		func->objectType = ot;
3741 		func->objectType->AddRefInternal();
3742 	}
3743 
3744 	// Skip the first parameter as this is the object type pointer that the stub will add
3745 	func->parameterTypes.SetLength(factory->parameterTypes.GetLength()-1);
3746 	func->parameterNames.SetLength(factory->parameterNames.GetLength()-1);
3747 	func->inOutFlags.SetLength(factory->inOutFlags.GetLength()-1);
3748 	func->defaultArgs.SetLength(factory->defaultArgs.GetLength()-1);
3749 	for( asUINT p = 1; p < factory->parameterTypes.GetLength(); p++ )
3750 	{
3751 		func->parameterTypes[p-1] = factory->parameterTypes[p];
3752 		func->parameterNames[p-1] = factory->parameterNames[p];
3753 		func->inOutFlags[p-1] = factory->inOutFlags[p];
3754 		func->defaultArgs[p-1] = factory->defaultArgs[p] ? asNEW(asCString)(*factory->defaultArgs[p]) : 0;
3755 	}
3756 	func->scriptData->objVariablesOnHeap = 0;
3757 
3758 	// Generate the bytecode for the factory stub
3759 	asUINT bcLength = asBCTypeSize[asBCInfo[asBC_OBJTYPE].type] +
3760 	                  asBCTypeSize[asBCInfo[asBC_CALLSYS].type] +
3761 	                  asBCTypeSize[asBCInfo[asBC_RET].type];
3762 
3763 	if( ep.includeJitInstructions )
3764 		bcLength += asBCTypeSize[asBCInfo[asBC_JitEntry].type];
3765 	if( templateType->flags & asOBJ_VALUE )
3766 		bcLength += asBCTypeSize[asBCInfo[asBC_SwapPtr].type];
3767 
3768 	func->scriptData->byteCode.SetLength(bcLength);
3769 	asDWORD *bc = func->scriptData->byteCode.AddressOf();
3770 
3771 	if( ep.includeJitInstructions )
3772 	{
3773 		*(asBYTE*)bc = asBC_JitEntry;
3774 		*(asPWORD*)(bc+1) = 0;
3775 		bc += asBCTypeSize[asBCInfo[asBC_JitEntry].type];
3776 	}
3777 
3778 	*(asBYTE*)bc = asBC_OBJTYPE;
3779 	*(asPWORD*)(bc+1) = (asPWORD)ot;
3780 	bc += asBCTypeSize[asBCInfo[asBC_OBJTYPE].type];
3781 	if( templateType->flags & asOBJ_VALUE )
3782 	{
3783 		// Swap the object pointer with the object type
3784 		*(asBYTE*)bc = asBC_SwapPtr;
3785 		bc += asBCTypeSize[asBCInfo[asBC_SwapPtr].type];
3786 	}
3787 	*(asBYTE*)bc = asBC_CALLSYS;
3788 	*(asDWORD*)(bc+1) = factoryId;
3789 	bc += asBCTypeSize[asBCInfo[asBC_CALLSYS].type];
3790 	*(asBYTE*)bc = asBC_RET;
3791 	*(((asWORD*)bc)+1) = (asWORD)func->GetSpaceNeededForArguments() + (func->objectType ? AS_PTR_SIZE : 0);
3792 
3793 	func->AddReferences();
3794 	func->scriptData->stackNeeded = AS_PTR_SIZE;
3795 
3796 	// Tell the virtual machine not to clean up the object on exception
3797 	func->dontCleanUpOnException = true;
3798 
3799 	func->JITCompile();
3800 
3801 	// Need to translate the list pattern too so the VM and compiler will know the correct type of the members
3802 	if( factory->listPattern )
3803 	{
3804 		asSListPatternNode *n = factory->listPattern;
3805 		asSListPatternNode *last = 0;
3806 		while( n )
3807 		{
3808 			asSListPatternNode *newNode = n->Duplicate();
3809 			if( newNode->type == asLPT_TYPE )
3810 			{
3811 				asSListPatternDataTypeNode *typeNode = reinterpret_cast<asSListPatternDataTypeNode*>(newNode);
3812 				typeNode->dataType = DetermineTypeForTemplate(typeNode->dataType, templateType, ot);
3813 			}
3814 
3815 			if( last )
3816 				last->next = newNode;
3817 			else
3818 				func->listPattern = newNode;
3819 
3820 			last = newNode;
3821 
3822 			n = n->next;
3823 		}
3824 	}
3825 
3826 	return func;
3827 }
3828 
RequireTypeReplacement(asCDataType & type,asCObjectType * templateType)3829 bool asCScriptEngine::RequireTypeReplacement(asCDataType &type, asCObjectType *templateType)
3830 {
3831 	if( type.GetTypeInfo() == templateType ) return true;
3832 	if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) return true;
3833 	if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
3834 	{
3835 		asCObjectType *ot = CastToObjectType(type.GetTypeInfo());
3836 		for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ )
3837 			if( ot->templateSubTypes[n].GetTypeInfo() &&
3838 				ot->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE )
3839 				return true;
3840 	}
3841 	if (type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(type.GetTypeInfo())->parentClass == templateType)
3842 		return true;
3843 
3844 	return false;
3845 }
3846 
GenerateNewTemplateFunction(asCObjectType * templateType,asCObjectType * ot,asCScriptFunction * func,asCScriptFunction ** newFunc)3847 bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *ot, asCScriptFunction *func, asCScriptFunction **newFunc)
3848 {
3849 	bool needNewFunc = false;
3850 	if( RequireTypeReplacement(func->returnType, templateType) )
3851 		needNewFunc = true;
3852 	else
3853 	{
3854 		for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ )
3855 		{
3856 			if( RequireTypeReplacement(func->parameterTypes[p], templateType) )
3857 			{
3858 				needNewFunc = true;
3859 				break;
3860 			}
3861 		}
3862 	}
3863 
3864 	if( !needNewFunc )
3865 		return false;
3866 
3867 	asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcType);
3868 	if( func2 == 0 )
3869 	{
3870 		// Out of memory
3871 		return false;
3872 	}
3873 
3874 	func2->name     = func->name;
3875 
3876 	func2->returnType = DetermineTypeForTemplate(func->returnType, templateType, ot);
3877 	func2->parameterTypes.SetLength(func->parameterTypes.GetLength());
3878 	for (asUINT p = 0; p < func->parameterTypes.GetLength(); p++)
3879 		func2->parameterTypes[p] = DetermineTypeForTemplate(func->parameterTypes[p], templateType, ot);
3880 
3881 	for (asUINT n = 0; n < func->defaultArgs.GetLength(); n++)
3882 		if (func->defaultArgs[n])
3883 			func2->defaultArgs.PushLast(asNEW(asCString)(*func->defaultArgs[n]));
3884 		else
3885 			func2->defaultArgs.PushLast(0);
3886 
3887 	// TODO: template: Must be careful when instantiating templates for garbage collected types
3888 	//                 If the template hasn't been registered with the behaviours, it shouldn't
3889 	//                 permit instantiation of garbage collected types that in turn may refer to
3890 	//                 this instance.
3891 
3892 	func2->parameterNames = func->parameterNames;
3893 	func2->inOutFlags = func->inOutFlags;
3894 	func2->SetReadOnly(func->IsReadOnly());
3895 	func2->objectType = ot;
3896 	func2->objectType->AddRefInternal();
3897 	func2->sysFuncIntf = asNEW(asSSystemFunctionInterface)(*func->sysFuncIntf);
3898 
3899 	// Adjust the clean up instructions
3900 	if( func2->sysFuncIntf->callConv == ICC_GENERIC_FUNC ||
3901 		func2->sysFuncIntf->callConv == ICC_GENERIC_METHOD )
3902 		PrepareSystemFunctionGeneric(func2, func2->sysFuncIntf, this);
3903 	else
3904 		PrepareSystemFunction(func2, func2->sysFuncIntf, this);
3905 
3906 	func2->id       = GetNextScriptFunctionId();
3907 	AddScriptFunction(func2);
3908 
3909 	// Return the new function
3910 	*newFunc = func2;
3911 
3912 	return true;
3913 }
3914 
GenerateNewTemplateFuncdef(asCObjectType * templateType,asCObjectType * ot,asCFuncdefType * func)3915 asCFuncdefType *asCScriptEngine::GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *ot, asCFuncdefType *func)
3916 {
3917 	// TODO: Only generate the new funcdef if it used the template subtypes.
3918 	//       Remember to also update the clean up in asCObjectType::DestroyInternal so it doesn't delete
3919 	//       child funcdefs that have not been created specificially for the template instance.
3920 	//       Perhaps a new funcdef is always needed, since the funcdef will have a reference to the
3921 	//       parent class (in this case the template instance).
3922 
3923 	asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcdef->funcType);
3924 	if (func2 == 0)
3925 	{
3926 		// Out of memory
3927 		return 0;
3928 	}
3929 
3930 	func2->name = func->name;
3931 
3932 	func2->returnType = DetermineTypeForTemplate(func->funcdef->returnType, templateType, ot);
3933 	func2->parameterTypes.SetLength(func->funcdef->parameterTypes.GetLength());
3934 	for (asUINT p = 0; p < func->funcdef->parameterTypes.GetLength(); p++)
3935 		func2->parameterTypes[p] = DetermineTypeForTemplate(func->funcdef->parameterTypes[p], templateType, ot);
3936 
3937 	// TODO: template: Must be careful when instantiating templates for garbage collected types
3938 	//                 If the template hasn't been registered with the behaviours, it shouldn't
3939 	//                 permit instantiation of garbage collected types that in turn may refer to
3940 	//                 this instance.
3941 
3942 	func2->inOutFlags = func->funcdef->inOutFlags;
3943 	func2->SetReadOnly(func->funcdef->IsReadOnly());
3944 	asASSERT(func->funcdef->objectType == 0);
3945 	asASSERT(func->funcdef->sysFuncIntf == 0);
3946 
3947 	func2->id = GetNextScriptFunctionId();
3948 	AddScriptFunction(func2);
3949 
3950 	asCFuncdefType *fdt2 = asNEW(asCFuncdefType)(this, func2);
3951 	funcDefs.PushLast(fdt2); // don't increase refCount as the constructor already set it to 1
3952 
3953 	// Return the new function
3954 	return fdt2;
3955 }
3956 
CallObjectMethod(void * obj,int func) const3957 void asCScriptEngine::CallObjectMethod(void *obj, int func) const
3958 {
3959 	asCScriptFunction *s = scriptFunctions[func];
3960 	asASSERT( s != 0 );
3961 	CallObjectMethod(obj, s->sysFuncIntf, s);
3962 }
3963 
CallObjectMethod(void * obj,asSSystemFunctionInterface * i,asCScriptFunction * s) const3964 void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asCScriptFunction *s) const
3965 {
3966 #if defined(__GNUC__) || defined(AS_PSVITA)
3967 	if( i->callConv == ICC_GENERIC_METHOD )
3968 	{
3969 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
3970 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
3971 		f(&gen);
3972 	}
3973 	else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL )
3974 	{
3975 		// For virtual thiscalls we must call the method as a true class method
3976 		// so that the compiler will lookup the function address in the vftable
3977 		union
3978 		{
3979 			asSIMPLEMETHOD_t mthd;
3980 			struct
3981 			{
3982 				asFUNCTION_t func;
3983 				asPWORD baseOffset;  // Same size as the pointer
3984 			} f;
3985 		} p;
3986 
3987 		obj = (void*) ((char*) obj +  i->compositeOffset);
3988 		if(i->isCompositeIndirect)
3989 			obj = *((void**)obj);
3990 
3991 		p.f.func = (asFUNCTION_t)(i->func);
3992 		p.f.baseOffset = asPWORD(i->baseOffset);
3993 		void (asCSimpleDummy::*f)() = p.mthd;
3994 		(((asCSimpleDummy*)obj)->*f)();
3995 	}
3996 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
3997 	{
3998 		void (*f)(void *) = (void (*)(void *))(i->func);
3999 		f(obj);
4000 	}
4001 #else
4002 #ifndef AS_NO_CLASS_METHODS
4003 	if( i->callConv == ICC_THISCALL )
4004 	{
4005 		union
4006 		{
4007 			asSIMPLEMETHOD_t mthd;
4008 			asFUNCTION_t func;
4009 		} p;
4010 		p.func = (asFUNCTION_t)(i->func);
4011 		void (asCSimpleDummy::*f)() = p.mthd;
4012 
4013 		obj = (void*) ((char*) obj +  i->compositeOffset);
4014 		if(i->isCompositeIndirect)
4015 			obj = *((void**)obj);
4016 
4017 		obj = (void*)(asPWORD(obj) + i->baseOffset);
4018 		(((asCSimpleDummy*)obj)->*f)();
4019 	}
4020 	else
4021 #endif
4022 	if( i->callConv == ICC_GENERIC_METHOD )
4023 	{
4024 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
4025 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4026 		f(&gen);
4027 	}
4028 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
4029 	{
4030 		void (*f)(void *) = (void (*)(void *))(i->func);
4031 		f(obj);
4032 	}
4033 #endif
4034 }
4035 
CallObjectMethodRetBool(void * obj,int func) const4036 bool asCScriptEngine::CallObjectMethodRetBool(void *obj, int func) const
4037 {
4038 	asCScriptFunction *s = scriptFunctions[func];
4039 	asASSERT( s != 0 );
4040 	asSSystemFunctionInterface *i = s->sysFuncIntf;
4041 
4042 #if defined(__GNUC__) || defined(AS_PSVITA)
4043 	if( i->callConv == ICC_GENERIC_METHOD )
4044 	{
4045 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
4046 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4047 		f(&gen);
4048 		return *(bool*)gen.GetReturnPointer();
4049 	}
4050 	else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL )
4051 	{
4052 		// For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
4053 		union
4054 		{
4055 			asSIMPLEMETHOD_t mthd;
4056 			struct
4057 			{
4058 				asFUNCTION_t func;
4059 				asPWORD baseOffset;
4060 			} f;
4061 		} p;
4062 
4063 		obj = (void*) ((char*) obj +  i->compositeOffset);
4064 		if(i->isCompositeIndirect)
4065 			obj = *((void**)obj);
4066 
4067 		p.f.func = (asFUNCTION_t)(i->func);
4068 		p.f.baseOffset = asPWORD(i->baseOffset);
4069 		bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())(p.mthd);
4070 		return (((asCSimpleDummy*)obj)->*f)();
4071 	}
4072 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
4073 	{
4074 		bool (*f)(void *) = (bool (*)(void *))(i->func);
4075 		return f(obj);
4076 	}
4077 #else
4078 #ifndef AS_NO_CLASS_METHODS
4079 	if( i->callConv == ICC_THISCALL )
4080 	{
4081 		union
4082 		{
4083 			asSIMPLEMETHOD_t mthd;
4084 			asFUNCTION_t func;
4085 		} p;
4086 		p.func = (asFUNCTION_t)(i->func);
4087 		bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())p.mthd;
4088 
4089 		obj = (void*) ((char*) obj +  i->compositeOffset);
4090 		if(i->isCompositeIndirect)
4091 			obj = *((void**)obj);
4092 
4093 		obj = (void*)(asPWORD(obj) + i->baseOffset);
4094 		return (((asCSimpleDummy*)obj)->*f)();
4095 	}
4096 	else
4097 #endif
4098 	if( i->callConv == ICC_GENERIC_METHOD )
4099 	{
4100 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
4101 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4102 		f(&gen);
4103 		return *(bool*)gen.GetReturnPointer();
4104 	}
4105 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
4106 	{
4107 		bool (*f)(void *) = (bool (*)(void *))(i->func);
4108 		return f(obj);
4109 	}
4110 #endif
4111 }
4112 
CallObjectMethodRetInt(void * obj,int func) const4113 int asCScriptEngine::CallObjectMethodRetInt(void *obj, int func) const
4114 {
4115 	asCScriptFunction *s = scriptFunctions[func];
4116 	asASSERT( s != 0 );
4117 	asSSystemFunctionInterface *i = s->sysFuncIntf;
4118 
4119 #if defined(__GNUC__) || defined(AS_PSVITA)
4120 	if( i->callConv == ICC_GENERIC_METHOD )
4121 	{
4122 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
4123 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4124 		f(&gen);
4125 		return *(int*)gen.GetReturnPointer();
4126 	}
4127 	else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL )
4128 	{
4129 		// For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
4130 		union
4131 		{
4132 			asSIMPLEMETHOD_t mthd;
4133 			struct
4134 			{
4135 				asFUNCTION_t func;
4136 				asPWORD baseOffset;
4137 			} f;
4138 		} p;
4139 		p.f.func = (asFUNCTION_t)(i->func);
4140 		p.f.baseOffset = asPWORD(i->baseOffset);
4141 
4142 		obj = (void*) ((char*) obj +  i->compositeOffset);
4143 		if(i->isCompositeIndirect)
4144 			obj = *((void**)obj);
4145 
4146 		int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())(p.mthd);
4147 		return (((asCSimpleDummy*)obj)->*f)();
4148 	}
4149 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
4150 	{
4151 		int (*f)(void *) = (int (*)(void *))(i->func);
4152 		return f(obj);
4153 	}
4154 #else
4155 #ifndef AS_NO_CLASS_METHODS
4156 	if( i->callConv == ICC_THISCALL )
4157 	{
4158 		union
4159 		{
4160 			asSIMPLEMETHOD_t mthd;
4161 			asFUNCTION_t func;
4162 		} p;
4163 		p.func = (asFUNCTION_t)(i->func);
4164 		int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())p.mthd;
4165 
4166 		obj = (void*) ((char*) obj +  i->compositeOffset);
4167 		if(i->isCompositeIndirect)
4168 			obj = *((void**)obj);
4169 
4170 		obj = (void*)(asPWORD(obj) + i->baseOffset);
4171 		return (((asCSimpleDummy*)obj)->*f)();
4172 	}
4173 	else
4174 #endif
4175 	if( i->callConv == ICC_GENERIC_METHOD )
4176 	{
4177 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
4178 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4179 		f(&gen);
4180 		return *(int*)gen.GetReturnPointer();
4181 	}
4182 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
4183 	{
4184 		int (*f)(void *) = (int (*)(void *))(i->func);
4185 		return f(obj);
4186 	}
4187 #endif
4188 }
4189 
CallObjectMethodRetPtr(void * obj,int func) const4190 void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const
4191 {
4192 	asCScriptFunction *s = scriptFunctions[func];
4193 	asASSERT( s != 0 );
4194 	asSSystemFunctionInterface *i = s->sysFuncIntf;
4195 
4196 #if defined(__GNUC__) || defined(AS_PSVITA)
4197 	if( i->callConv == ICC_GENERIC_METHOD )
4198 	{
4199 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
4200 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4201 		f(&gen);
4202 		return *(void**)gen.GetReturnPointer();
4203 	}
4204 	else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL )
4205 	{
4206 		// For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
4207 		union
4208 		{
4209 			asSIMPLEMETHOD_t mthd;
4210 			struct
4211 			{
4212 				asFUNCTION_t func;
4213 				asPWORD baseOffset;
4214 			} f;
4215 		} p;
4216 		p.f.func = (asFUNCTION_t)(i->func);
4217 		p.f.baseOffset = asPWORD(i->baseOffset);
4218 
4219 		obj = (void*) ((char*) obj +  i->compositeOffset);
4220 		if(i->isCompositeIndirect)
4221 			obj = *((void**)obj);
4222 
4223 		void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())(p.mthd);
4224 		return (((asCSimpleDummy*)obj)->*f)();
4225 	}
4226 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
4227 	{
4228 		void *(*f)(void *) = (void *(*)(void *))(i->func);
4229 		return f(obj);
4230 	}
4231 #else
4232 #ifndef AS_NO_CLASS_METHODS
4233 	if( i->callConv == ICC_THISCALL )
4234 	{
4235 		union
4236 		{
4237 			asSIMPLEMETHOD_t mthd;
4238 			asFUNCTION_t func;
4239 		} p;
4240 		p.func = (asFUNCTION_t)(i->func);
4241 		void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())p.mthd;
4242 
4243 		obj = (void*) ((char*) obj +  i->compositeOffset);
4244 		if(i->isCompositeIndirect)
4245 			obj = *((void**)obj);
4246 
4247 		obj = (void*)(asPWORD(obj) + i->baseOffset);
4248 		return (((asCSimpleDummy*)obj)->*f)();
4249 	}
4250 	else
4251 #endif
4252 	if( i->callConv == ICC_GENERIC_METHOD )
4253 	{
4254 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, 0);
4255 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4256 		f(&gen);
4257 		return *(void **)gen.GetReturnPointer();
4258 	}
4259 	else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
4260 	{
4261 		void *(*f)(void *) = (void *(*)(void *))(i->func);
4262 		return f(obj);
4263 	}
4264 #endif
4265 }
4266 
CallObjectMethodRetPtr(void * obj,int param1,asCScriptFunction * func) const4267 void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const
4268 {
4269 	asASSERT( obj != 0 );
4270 	asASSERT( func != 0 );
4271 	asSSystemFunctionInterface *i = func->sysFuncIntf;
4272 
4273 #ifndef AS_NO_CLASS_METHODS
4274 	if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL )
4275 	{
4276 #if defined(__GNUC__) || defined(AS_PSVITA)
4277 		// For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
4278 		union
4279 		{
4280 			asSIMPLEMETHOD_t mthd;
4281 			struct
4282 			{
4283 				asFUNCTION_t func;
4284 				asPWORD baseOffset;
4285 			} f;
4286 		} p;
4287 		p.f.func = (asFUNCTION_t)(i->func);
4288 		p.f.baseOffset = asPWORD(i->baseOffset);
4289 
4290 		obj = (void*) ((char*) obj +  i->compositeOffset);
4291 		if(i->isCompositeIndirect)
4292 			obj = *((void**)obj);
4293 
4294 		void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))(p.mthd);
4295 		return (((asCSimpleDummy*)obj)->*f)(param1);
4296 #else
4297 		union
4298 		{
4299 			asSIMPLEMETHOD_t mthd;
4300 			asFUNCTION_t func;
4301 		} p;
4302 		p.func = (asFUNCTION_t)(i->func);
4303 		void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))p.mthd;
4304 
4305 		obj = (void*) ((char*) obj +  i->compositeOffset);
4306 		if(i->isCompositeIndirect)
4307 			obj = *((void**)obj);
4308 
4309 		obj = (void*)(asPWORD(obj) + i->baseOffset);
4310 		return (((asCSimpleDummy*)obj)->*f)(param1);
4311 #endif
4312 	}
4313 	else
4314 #endif
4315 	if( i->callConv == ICC_GENERIC_METHOD )
4316 	{
4317 		asCGeneric gen(const_cast<asCScriptEngine*>(this), func, obj, reinterpret_cast<asDWORD*>(&param1));
4318 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4319 		f(&gen);
4320 		return *(void **)gen.GetReturnPointer();
4321 	}
4322 	else if( i->callConv == ICC_CDECL_OBJLAST )
4323 	{
4324 		void *(*f)(int, void *) = (void *(*)(int, void *))(i->func);
4325 		return f(param1, obj);
4326 	}
4327 	else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/
4328 	{
4329 		void *(*f)(void *, int) = (void *(*)(void *, int))(i->func);
4330 		return f(obj, param1);
4331 	}
4332 }
4333 
CallGlobalFunctionRetPtr(int func) const4334 void *asCScriptEngine::CallGlobalFunctionRetPtr(int func) const
4335 {
4336 	asCScriptFunction *s = scriptFunctions[func];
4337 	asASSERT( s != 0 );
4338 	return CallGlobalFunctionRetPtr(s->sysFuncIntf, s);
4339 }
4340 
CallGlobalFunctionRetPtr(int func,void * param1) const4341 void *asCScriptEngine::CallGlobalFunctionRetPtr(int func, void *param1) const
4342 {
4343 	asCScriptFunction *s = scriptFunctions[func];
4344 	asASSERT( s != 0 );
4345 	return CallGlobalFunctionRetPtr(s->sysFuncIntf, s, param1);
4346 }
4347 
CallGlobalFunctionRetPtr(asSSystemFunctionInterface * i,asCScriptFunction * s) const4348 void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s) const
4349 {
4350 	if( i->callConv == ICC_CDECL )
4351 	{
4352 		void *(*f)() = (void *(*)())(i->func);
4353 		return f();
4354 	}
4355 	else if( i->callConv == ICC_STDCALL )
4356 	{
4357 		typedef void *(STDCALL *func_t)();
4358 		func_t f = (func_t)(i->func);
4359 		return f();
4360 	}
4361 	else
4362 	{
4363 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, 0, 0);
4364 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4365 		f(&gen);
4366 		return *(void**)gen.GetReturnPointer();
4367 	}
4368 }
4369 
CallGlobalFunctionRetPtr(asSSystemFunctionInterface * i,asCScriptFunction * s,void * param1) const4370 void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s, void *param1) const
4371 {
4372 	if( i->callConv == ICC_CDECL )
4373 	{
4374 		void *(*f)(void *) = (void *(*)(void *))(i->func);
4375 		return f(param1);
4376 	}
4377 	else if( i->callConv == ICC_STDCALL )
4378 	{
4379 		typedef void *(STDCALL *func_t)(void *);
4380 		func_t f = (func_t)(i->func);
4381 		return f(param1);
4382 	}
4383 	else
4384 	{
4385 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, 0, (asDWORD*)&param1);
4386 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4387 		f(&gen);
4388 		return *(void**)gen.GetReturnPointer();
4389 	}
4390 }
4391 
CallObjectMethod(void * obj,void * param,int func) const4392 void asCScriptEngine::CallObjectMethod(void *obj, void *param, int func) const
4393 {
4394 	asCScriptFunction *s = scriptFunctions[func];
4395 	asASSERT( s != 0 );
4396 	CallObjectMethod(obj, param, s->sysFuncIntf, s);
4397 }
4398 
CallObjectMethod(void * obj,void * param,asSSystemFunctionInterface * i,asCScriptFunction * s) const4399 void asCScriptEngine::CallObjectMethod(void *obj, void *param, asSSystemFunctionInterface *i, asCScriptFunction *s) const
4400 {
4401 #if defined(__GNUC__) || defined(AS_PSVITA)
4402 	if( i->callConv == ICC_CDECL_OBJLAST )
4403 	{
4404 		void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
4405 		f(param, obj);
4406 	}
4407 	else if( i->callConv == ICC_GENERIC_METHOD )
4408 	{
4409 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, (asDWORD*)&param);
4410 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4411 		f(&gen);
4412 	}
4413 	else if( i->callConv == ICC_VIRTUAL_THISCALL || i->callConv == ICC_THISCALL )
4414 	{
4415 		// For virtual thiscalls we must call the method as a true class method
4416 		// so that the compiler will lookup the function address in the vftable
4417 		union
4418 		{
4419 			asSIMPLEMETHOD_t mthd;
4420 			struct
4421 			{
4422 				asFUNCTION_t func;
4423 				asPWORD baseOffset;  // Same size as the pointer
4424 			} f;
4425 		} p;
4426 		p.f.func = (asFUNCTION_t)(i->func);
4427 		p.f.baseOffset = asPWORD(i->baseOffset);
4428 
4429 		obj = (void*) ((char*) obj +  i->compositeOffset);
4430 		if(i->isCompositeIndirect)
4431 			obj = *((void**)obj);
4432 
4433 		void (asCSimpleDummy::*f)(void*) = (void (asCSimpleDummy::*)(void*))(p.mthd);
4434 		(((asCSimpleDummy*)obj)->*f)(param);
4435 	}
4436 	else /*if( i->callConv == ICC_CDECL_OBJFIRST */
4437 	{
4438 		void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
4439 		f(obj, param);
4440 	}
4441 #else
4442 #ifndef AS_NO_CLASS_METHODS
4443 	if( i->callConv == ICC_THISCALL )
4444 	{
4445 		union
4446 		{
4447 			asSIMPLEMETHOD_t mthd;
4448 			asFUNCTION_t func;
4449 		} p;
4450 		p.func = (asFUNCTION_t)(i->func);
4451 		void (asCSimpleDummy::*f)(void *) = (void (asCSimpleDummy::*)(void *))(p.mthd);
4452 
4453 		obj = (void*) ((char*) obj +  i->compositeOffset);
4454 		if(i->isCompositeIndirect)
4455 			obj = *((void**)obj);
4456 
4457 		obj = (void*)(asPWORD(obj) + i->baseOffset);
4458 		(((asCSimpleDummy*)obj)->*f)(param);
4459 	}
4460 	else
4461 #endif
4462 	if( i->callConv == ICC_CDECL_OBJLAST )
4463 	{
4464 		void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
4465 		f(param, obj);
4466 	}
4467 	else if( i->callConv == ICC_GENERIC_METHOD )
4468 	{
4469 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, obj, (asDWORD*)&param);
4470 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4471 		f(&gen);
4472 	}
4473 	else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/
4474 	{
4475 		void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
4476 		f(obj, param);
4477 	}
4478 #endif
4479 }
4480 
CallGlobalFunction(void * param1,void * param2,asSSystemFunctionInterface * i,asCScriptFunction * s) const4481 void asCScriptEngine::CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s) const
4482 {
4483 	if( i->callConv == ICC_CDECL )
4484 	{
4485 		void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
4486 		f(param1, param2);
4487 	}
4488 	else if( i->callConv == ICC_STDCALL )
4489 	{
4490 		typedef void (STDCALL *func_t)(void *, void *);
4491 		func_t f = (func_t)(i->func);
4492 		f(param1, param2);
4493 	}
4494 	else
4495 	{
4496 		// We must guarantee the order of the arguments which is why we copy them to this
4497 		// array. Otherwise the compiler may put them anywhere it likes, or even keep them
4498 		// in the registers which causes problem.
4499 		void *params[2] = {param1, param2};
4500 
4501 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, 0, (asDWORD*)&params);
4502 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4503 		f(&gen);
4504 	}
4505 }
4506 
CallGlobalFunctionRetBool(void * param1,void * param2,asSSystemFunctionInterface * i,asCScriptFunction * s) const4507 bool asCScriptEngine::CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s) const
4508 {
4509 	if( i->callConv == ICC_CDECL )
4510 	{
4511 		bool (*f)(void *, void *) = (bool (*)(void *, void *))(i->func);
4512 		return f(param1, param2);
4513 	}
4514 	else if( i->callConv == ICC_STDCALL )
4515 	{
4516 		typedef bool (STDCALL *func_t)(void *, void *);
4517 		func_t f = (func_t)(i->func);
4518 		return f(param1, param2);
4519 	}
4520 	else
4521 	{
4522 		// TODO: When simulating a 64bit environment by defining AS_64BIT_PTR on a 32bit platform this code
4523 		//       fails, because the stack given to asCGeneric is not prepared with two 64bit arguments.
4524 
4525 		// We must guarantee the order of the arguments which is why we copy them to this
4526 		// array. Otherwise the compiler may put them anywhere it likes, or even keep them
4527 		// in the registers which causes problem.
4528 		void *params[2] = {param1, param2};
4529 		asCGeneric gen(const_cast<asCScriptEngine*>(this), s, 0, (asDWORD*)params);
4530 		void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
4531 		f(&gen);
4532 		return *(bool*)gen.GetReturnPointer();
4533 	}
4534 }
4535 
CallAlloc(const asCObjectType * type) const4536 void *asCScriptEngine::CallAlloc(const asCObjectType *type) const
4537 {
4538 	// Allocate 4 bytes as the smallest size. Otherwise CallSystemFunction may try to
4539 	// copy a DWORD onto a smaller memory block, in case the object type is return in registers.
4540 
4541 	// Pad to the next even 4 bytes to avoid asBC_CPY writing outside of allocated buffer for registered POD types
4542 	asUINT size = type->size;
4543 	if( size & 0x3 )
4544 		size += 4 - (size & 0x3);
4545 
4546 #ifndef WIP_16BYTE_ALIGN
4547 #if defined(AS_DEBUG)
4548 	return ((asALLOCFUNCDEBUG_t)userAlloc)(size, __FILE__, __LINE__);
4549 #else
4550 	return userAlloc(size);
4551 #endif
4552 #else
4553 #if defined(AS_DEBUG)
4554 	return ((asALLOCALIGNEDFUNCDEBUG_t)userAllocAligned)(size, type->alignment, __FILE__, __LINE__);
4555 #else
4556 	return userAllocAligned(size, type->alignment);
4557 #endif
4558 #endif
4559 }
4560 
CallFree(void * obj) const4561 void asCScriptEngine::CallFree(void *obj) const
4562 {
4563 #ifndef WIP_16BYTE_ALIGN
4564 	userFree(obj);
4565 #else
4566 	userFreeAligned(obj);
4567 #endif
4568 }
4569 
4570 // interface
NotifyGarbageCollectorOfNewObject(void * obj,asITypeInfo * type)4571 int asCScriptEngine::NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type)
4572 {
4573 	return gc.AddScriptObjectToGC(obj, static_cast<asCObjectType*>(type));
4574 }
4575 
4576 // interface
GetObjectInGC(asUINT idx,asUINT * seqNbr,void ** obj,asITypeInfo ** type)4577 int asCScriptEngine::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type)
4578 {
4579 	return gc.GetObjectInGC(idx, seqNbr, obj, type);
4580 }
4581 
4582 // interface
GarbageCollect(asDWORD flags,asUINT iterations)4583 int asCScriptEngine::GarbageCollect(asDWORD flags, asUINT iterations)
4584 {
4585 	int r = gc.GarbageCollect(flags, iterations);
4586 
4587 	if( r == 0 )
4588 	{
4589 		// Delete any modules that have been discarded previously but not
4590 		// removed due to being referred to by objects in the garbage collector
4591 		DeleteDiscardedModules();
4592 	}
4593 
4594 	return r;
4595 }
4596 
4597 // interface
GetGCStatistics(asUINT * currentSize,asUINT * totalDestroyed,asUINT * totalDetected,asUINT * newObjects,asUINT * totalNewDestroyed) const4598 void asCScriptEngine::GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const
4599 {
4600 	gc.GetStatistics(currentSize, totalDestroyed, totalDetected, newObjects, totalNewDestroyed);
4601 }
4602 
4603 // interface
GCEnumCallback(void * reference)4604 void asCScriptEngine::GCEnumCallback(void *reference)
4605 {
4606 	gc.GCEnumCallback(reference);
4607 }
4608 
4609 
GetTypeIdFromDataType(const asCDataType & dtIn) const4610 int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const
4611 {
4612 	if( dtIn.IsNullHandle() ) return asTYPEID_VOID;
4613 
4614 	if( dtIn.GetTypeInfo() == 0 )
4615 	{
4616 		// Primitives have pre-fixed typeIds
4617 		switch( dtIn.GetTokenType() )
4618 		{
4619 		case ttVoid:   return asTYPEID_VOID;
4620 		case ttBool:   return asTYPEID_BOOL;
4621 		case ttInt8:   return asTYPEID_INT8;
4622 		case ttInt16:  return asTYPEID_INT16;
4623 		case ttInt:    return asTYPEID_INT32;
4624 		case ttInt64:  return asTYPEID_INT64;
4625 		case ttUInt8:  return asTYPEID_UINT8;
4626 		case ttUInt16: return asTYPEID_UINT16;
4627 		case ttUInt:   return asTYPEID_UINT32;
4628 		case ttUInt64: return asTYPEID_UINT64;
4629 		case ttFloat:  return asTYPEID_FLOAT;
4630 		case ttDouble: return asTYPEID_DOUBLE;
4631 		default:
4632 			// All types should be covered by the above. The variable type is not really a type
4633 			asASSERT(dtIn.GetTokenType() == ttQuestion);
4634 			return -1;
4635 		}
4636 	}
4637 
4638 	int typeId = -1;
4639 	asCTypeInfo *ot = dtIn.GetTypeInfo();
4640 	asASSERT(ot != &functionBehaviours);
4641 	// Object's hold the typeId themselves
4642 	typeId = ot->typeId;
4643 
4644 	if( typeId == -1 )
4645 	{
4646 		ACQUIREEXCLUSIVE(engineRWLock);
4647 		// Make sure another thread didn't determine the typeId while we were waiting for the lock
4648 		if( ot->typeId == -1 )
4649 		{
4650 			typeId = typeIdSeqNbr++;
4651 			if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT;
4652 			else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE;
4653 			else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this?
4654 			else typeId |= asTYPEID_APPOBJECT;
4655 
4656 			ot->typeId = typeId;
4657 
4658 			mapTypeIdToTypeInfo.Insert(typeId, ot);
4659 		}
4660 		RELEASEEXCLUSIVE(engineRWLock);
4661 	}
4662 
4663 	// Add flags according to the requested type
4664 	if( dtIn.GetTypeInfo() && !(dtIn.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
4665 	{
4666 		// The ASHANDLE types behave like handles, but are really
4667 		// value types so the typeId is never returned as a handle
4668 		if( dtIn.IsObjectHandle() )
4669 			typeId |= asTYPEID_OBJHANDLE;
4670 		if( dtIn.IsHandleToConst() )
4671 			typeId |= asTYPEID_HANDLETOCONST;
4672 	}
4673 
4674 	return typeId;
4675 }
4676 
GetDataTypeFromTypeId(int typeId) const4677 asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const
4678 {
4679 	int baseId = typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR);
4680 
4681 	if( typeId <= asTYPEID_DOUBLE )
4682 	{
4683 		eTokenType type[] = {ttVoid, ttBool, ttInt8, ttInt16, ttInt, ttInt64, ttUInt8, ttUInt16, ttUInt, ttUInt64, ttFloat, ttDouble};
4684 		return asCDataType::CreatePrimitive(type[typeId], false);
4685 	}
4686 
4687 	// First check if the typeId is an object type
4688 	asCTypeInfo *ot = 0;
4689 	ACQUIRESHARED(engineRWLock);
4690 	asSMapNode<int,asCTypeInfo*> *cursor = 0;
4691 	if( mapTypeIdToTypeInfo.MoveTo(&cursor, baseId) )
4692 		ot = mapTypeIdToTypeInfo.GetValue(cursor);
4693 	RELEASESHARED(engineRWLock);
4694 
4695 	if( ot )
4696 	{
4697 		asCDataType dt = asCDataType::CreateType(ot, false);
4698 		if( typeId & asTYPEID_OBJHANDLE )
4699 			dt.MakeHandle(true, true);
4700 		if( typeId & asTYPEID_HANDLETOCONST )
4701 			dt.MakeHandleToConst(true);
4702 
4703 		return dt;
4704 	}
4705 
4706 	return asCDataType();
4707 }
4708 
GetObjectTypeFromTypeId(int typeId) const4709 asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId) const
4710 {
4711 	asCDataType dt = GetDataTypeFromTypeId(typeId);
4712 	return CastToObjectType(dt.GetTypeInfo());
4713 }
4714 
RemoveFromTypeIdMap(asCTypeInfo * type)4715 void asCScriptEngine::RemoveFromTypeIdMap(asCTypeInfo *type)
4716 {
4717 	ACQUIREEXCLUSIVE(engineRWLock);
4718 	asSMapNode<int,asCTypeInfo*> *cursor = 0;
4719 	mapTypeIdToTypeInfo.MoveFirst(&cursor);
4720 	while( cursor )
4721 	{
4722 		if(mapTypeIdToTypeInfo.GetValue(cursor) == type )
4723 		{
4724 			mapTypeIdToTypeInfo.Erase(cursor);
4725 			break;
4726 		}
4727 		mapTypeIdToTypeInfo.MoveNext(&cursor, cursor);
4728 	}
4729 	RELEASEEXCLUSIVE(engineRWLock);
4730 }
4731 
4732 // interface
GetTypeInfoByDecl(const char * decl) const4733 asITypeInfo *asCScriptEngine::GetTypeInfoByDecl(const char *decl) const
4734 {
4735 	asCDataType dt;
4736 	// This cast is ok, because we are not changing anything in the engine
4737 	asCBuilder bld(const_cast<asCScriptEngine*>(this), 0);
4738 
4739 	// Don't write parser errors to the message callback
4740 	bld.silent = true;
4741 
4742 	int r = bld.ParseDataType(decl, &dt, defaultNamespace);
4743 	if (r < 0)
4744 		return 0;
4745 
4746 	return dt.GetTypeInfo();
4747 }
4748 
4749 // interface
GetTypeIdByDecl(const char * decl) const4750 int asCScriptEngine::GetTypeIdByDecl(const char *decl) const
4751 {
4752 	asCDataType dt;
4753 	// This cast is ok, because we are not changing anything in the engine
4754 	asCBuilder bld(const_cast<asCScriptEngine*>(this), 0);
4755 
4756 	// Don't write parser errors to the message callback
4757 	bld.silent = true;
4758 
4759 	int r = bld.ParseDataType(decl, &dt, defaultNamespace);
4760 	if( r < 0 )
4761 		return asINVALID_TYPE;
4762 
4763 	return GetTypeIdFromDataType(dt);
4764 }
4765 
4766 // interface
GetTypeDeclaration(int typeId,bool includeNamespace) const4767 const char *asCScriptEngine::GetTypeDeclaration(int typeId, bool includeNamespace) const
4768 {
4769 	asCDataType dt = GetDataTypeFromTypeId(typeId);
4770 
4771 	asCString *tempString = &asCThreadManager::GetLocalData()->string;
4772 	*tempString = dt.Format(defaultNamespace, includeNamespace);
4773 
4774 	return tempString->AddressOf();
4775 }
4776 
4777 // interface
GetSizeOfPrimitiveType(int typeId) const4778 int asCScriptEngine::GetSizeOfPrimitiveType(int typeId) const
4779 {
4780 	asCDataType dt = GetDataTypeFromTypeId(typeId);
4781 	if( !dt.IsPrimitive() ) return 0;
4782 
4783 	return dt.GetSizeInMemoryBytes();
4784 }
4785 
4786 // interface
RefCastObject(void * obj,asITypeInfo * fromType,asITypeInfo * toType,void ** newPtr,bool useOnlyImplicitCast)4787 int asCScriptEngine::RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast)
4788 {
4789 	if( newPtr == 0 ) return asINVALID_ARG;
4790 	*newPtr = 0;
4791 
4792 	if( fromType == 0 || toType == 0 ) return asINVALID_ARG;
4793 
4794 	// A null-pointer can always be cast to another type, so it will always be successful
4795 	if( obj == 0 )
4796 		return asSUCCESS;
4797 
4798 	if( fromType == toType )
4799 	{
4800 		*newPtr = obj;
4801 		AddRefScriptObject(*newPtr, toType);
4802 		return asSUCCESS;
4803 	}
4804 
4805 	// Check for funcdefs
4806 	if ((fromType->GetFlags() & asOBJ_FUNCDEF) && (toType->GetFlags() & asOBJ_FUNCDEF))
4807 	{
4808 		asCFuncdefType *fromFunc = CastToFuncdefType(reinterpret_cast<asCTypeInfo*>(fromType));
4809 		asCFuncdefType *toFunc = CastToFuncdefType(reinterpret_cast<asCTypeInfo*>(toType));
4810 
4811 		if (fromFunc && toFunc && fromFunc->funcdef->IsSignatureExceptNameEqual(toFunc->funcdef))
4812 		{
4813 			*newPtr = obj;
4814 			AddRefScriptObject(*newPtr, toType);
4815 			return asSUCCESS;
4816 		}
4817 
4818 		return asSUCCESS;
4819 	}
4820 
4821 	// Look for ref cast behaviours
4822 	asCScriptFunction *universalCastFunc = 0;
4823 	asCObjectType *from = reinterpret_cast<asCObjectType*>(fromType);
4824 	for( asUINT n = 0; n < from->methods.GetLength(); n++ )
4825 	{
4826 		asCScriptFunction *func = scriptFunctions[from->methods[n]];
4827 		if( func->name == "opImplCast" ||
4828 			(!useOnlyImplicitCast && func->name == "opCast") )
4829 		{
4830 			if( func->returnType.GetTypeInfo() == toType )
4831 			{
4832 				*newPtr = CallObjectMethodRetPtr(obj, func->id);
4833 				// The ref cast behaviour returns a handle with incremented
4834 				// ref counter, so there is no need to call AddRef explicitly
4835 				// unless the function is registered with autohandle
4836 				if( func->sysFuncIntf->returnAutoHandle )
4837 					AddRefScriptObject(*newPtr, toType);
4838 				return asSUCCESS;
4839 			}
4840 			else
4841 			{
4842 				asASSERT( func->returnType.GetTokenType() == ttVoid &&
4843 						  func->parameterTypes.GetLength() == 1 &&
4844 						  func->parameterTypes[0].GetTokenType() == ttQuestion );
4845 				universalCastFunc = func;
4846 			}
4847 		}
4848 	}
4849 
4850 	// One last chance if the object has a void opCast(?&out) behaviour
4851 	if( universalCastFunc )
4852 	{
4853 		// TODO: Add proper error handling
4854 		asIScriptContext *ctx = RequestContext();
4855 		ctx->Prepare(universalCastFunc);
4856 		ctx->SetObject(obj);
4857 		ctx->SetArgVarType(0, newPtr, toType->GetTypeId() | asTYPEID_OBJHANDLE);
4858 		ctx->Execute();
4859 		ReturnContext(ctx);
4860 
4861 		// The opCast(?&out) method already incremented the
4862 		// refCount so there is no need to do it manually
4863 		return asSUCCESS;
4864 	}
4865 
4866 	// For script classes and interfaces there is a quick route
4867 	if( (fromType->GetFlags() & asOBJ_SCRIPT_OBJECT) && (toType->GetFlags() & asOBJ_SCRIPT_OBJECT) )
4868 	{
4869 		if( fromType == toType )
4870 		{
4871 			*newPtr = obj;
4872 			reinterpret_cast<asCScriptObject*>(*newPtr)->AddRef();
4873 			return asSUCCESS;
4874 		}
4875 
4876 		// Up casts to base class or interface can be done implicitly
4877 		if( fromType->DerivesFrom(toType) ||
4878 			fromType->Implements(toType) )
4879 		{
4880 			*newPtr = obj;
4881 			reinterpret_cast<asCScriptObject*>(*newPtr)->AddRef();
4882 			return asSUCCESS;
4883 		}
4884 		// Down casts to derived class or from interface can only be done explicitly
4885 		if( !useOnlyImplicitCast )
4886 		{
4887 			// Get the true type of the object so the explicit cast can evaluate all possibilities
4888 			asITypeInfo *trueType = reinterpret_cast<asCScriptObject*>(obj)->GetObjectType();
4889 			if (trueType->DerivesFrom(toType) ||
4890 				trueType->Implements(toType))
4891 			{
4892 				*newPtr = obj;
4893 				reinterpret_cast<asCScriptObject*>(*newPtr)->AddRef();
4894 				return asSUCCESS;
4895 			}
4896 		}
4897 	}
4898 
4899 	// The cast is not available, but it is still a success
4900 	return asSUCCESS;
4901 }
4902 
4903 // interface
CreateScriptObject(const asITypeInfo * type)4904 void *asCScriptEngine::CreateScriptObject(const asITypeInfo *type)
4905 {
4906 	if( type == 0 ) return 0;
4907 
4908 	asCObjectType *objType = const_cast<asCObjectType*>(reinterpret_cast<const asCObjectType *>(type));
4909 	void *ptr = 0;
4910 
4911 	// Check that there is a default factory for ref types
4912 	if( objType->beh.factory == 0 && (objType->flags & asOBJ_REF) )
4913 	{
4914 		asCString str;
4915 		str.Format(TXT_FAILED_IN_FUNC_s_d, "CreateScriptObject", asNO_FUNCTION);
4916 		WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
4917 		return 0;
4918 	}
4919 
4920 	// Construct the object
4921 	if( objType->flags & asOBJ_SCRIPT_OBJECT )
4922 	{
4923 		// Call the script class' default factory with a context
4924 		ptr = ScriptObjectFactory(objType, this);
4925 	}
4926 	else if( (objType->flags & asOBJ_TEMPLATE) && (objType->flags & asOBJ_REF) )
4927 	{
4928 		// The registered factory that takes the object type is moved
4929 		// to the construct behaviour when the type is instantiated
4930 #ifdef AS_NO_EXCEPTIONS
4931 		ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType);
4932 #else
4933 		try
4934 		{
4935 			ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType);
4936 		}
4937 		catch (...)
4938 		{
4939 			asIScriptContext *ctx = asGetActiveContext();
4940 			if (ctx)
4941 				ctx->SetException(TXT_EXCEPTION_CAUGHT);
4942 		}
4943 #endif
4944 	}
4945 	else if( objType->flags & asOBJ_REF )
4946 	{
4947 		// Call the default factory directly
4948 #ifdef AS_NO_EXCEPTIONS
4949 		ptr = CallGlobalFunctionRetPtr(objType->beh.factory);
4950 #else
4951 		try
4952 		{
4953 			ptr = CallGlobalFunctionRetPtr(objType->beh.factory);
4954 		}
4955 		catch(...)
4956 		{
4957 			asIScriptContext *ctx = asGetActiveContext();
4958 			if( ctx )
4959 				ctx->SetException(TXT_EXCEPTION_CAUGHT);
4960 		}
4961 #endif
4962 	}
4963 	else
4964 	{
4965 		// Make sure there is a default constructor or that it is a POD type
4966 		if( objType->beh.construct == 0 && !(objType->flags & asOBJ_POD) )
4967 		{
4968 			asCString str;
4969 			str.Format(TXT_FAILED_IN_FUNC_s_d, "CreateScriptObject", asNO_FUNCTION);
4970 			WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
4971 			return 0;
4972 		}
4973 
4974 		// Manually allocate the memory, then call the default constructor
4975 		ptr = CallAlloc(objType);
4976 		int funcIndex = objType->beh.construct;
4977 		if (funcIndex)
4978 		{
4979 			if (objType->flags & asOBJ_TEMPLATE)
4980 			{
4981 				// Templates of value types create script functions as the constructors
4982 				CallScriptObjectMethod(ptr, funcIndex);
4983 			}
4984 			else
4985 			{
4986 #ifdef AS_NO_EXCEPTIONS
4987 				CallObjectMethod(ptr, funcIndex);
4988 #else
4989 				try
4990 				{
4991 					CallObjectMethod(ptr, funcIndex);
4992 				}
4993 				catch (...)
4994 				{
4995 					asIScriptContext *ctx = asGetActiveContext();
4996 					if (ctx)
4997 						ctx->SetException(TXT_EXCEPTION_CAUGHT);
4998 
4999 					// Free the memory
5000 					CallFree(ptr);
5001 					ptr = 0;
5002 				}
5003 #endif
5004 			}
5005 		}
5006 	}
5007 
5008 	return ptr;
5009 }
5010 
5011 // internal
CallScriptObjectMethod(void * obj,int funcId)5012 int asCScriptEngine::CallScriptObjectMethod(void *obj, int funcId)
5013 {
5014 	asIScriptContext *ctx = 0;
5015 	int r = 0;
5016 	bool isNested = false;
5017 
5018 	// Use nested call in the context if there is an active context
5019 	ctx = asGetActiveContext();
5020 	if (ctx)
5021 	{
5022 		// It may not always be possible to reuse the current context,
5023 		// in which case we'll have to create a new one any way.
5024 		if (ctx->GetEngine() == this && ctx->PushState() == asSUCCESS)
5025 			isNested = true;
5026 		else
5027 			ctx = 0;
5028 	}
5029 
5030 	if (ctx == 0)
5031 	{
5032 		// Request a context from the engine
5033 		ctx = RequestContext();
5034 		if (ctx == 0)
5035 		{
5036 			// TODO: How to best report this failure?
5037 			return asERROR;
5038 		}
5039 	}
5040 
5041 	r = ctx->Prepare(scriptFunctions[funcId]);
5042 	if (r < 0)
5043 	{
5044 		if (isNested)
5045 			ctx->PopState();
5046 		else
5047 			ReturnContext(ctx);
5048 		// TODO: How to best report this failure?
5049 		return asERROR;
5050 	}
5051 
5052 	// Set the object
5053 	ctx->SetObject(obj);
5054 
5055 	for (;;)
5056 	{
5057 		r = ctx->Execute();
5058 
5059 		// We can't allow this execution to be suspended
5060 		// so resume the execution immediately
5061 		if (r != asEXECUTION_SUSPENDED)
5062 			break;
5063 	}
5064 
5065 	if (r != asEXECUTION_FINISHED)
5066 	{
5067 		if (isNested)
5068 		{
5069 			ctx->PopState();
5070 
5071 			// If the execution was aborted or an exception occurred,
5072 			// then we should forward that to the outer execution.
5073 			if (r == asEXECUTION_EXCEPTION)
5074 			{
5075 				// TODO: How to improve this exception
5076 				ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL);
5077 			}
5078 			else if (r == asEXECUTION_ABORTED)
5079 				ctx->Abort();
5080 		}
5081 		else
5082 			ReturnContext(ctx);
5083 
5084 		// TODO: How to best report the error?
5085 		return asERROR;
5086 	}
5087 
5088 	if (isNested)
5089 		ctx->PopState();
5090 	else
5091 		ReturnContext(ctx);
5092 
5093 	return asSUCCESS;
5094 }
5095 
5096 // interface
CreateUninitializedScriptObject(const asITypeInfo * type)5097 void *asCScriptEngine::CreateUninitializedScriptObject(const asITypeInfo *type)
5098 {
5099 	// This function only works for script classes. Registered types cannot be created this way.
5100 	if( type == 0 || !(type->GetFlags() & asOBJ_SCRIPT_OBJECT) )
5101 		return 0;
5102 
5103 	asCObjectType *objType = const_cast<asCObjectType*>(reinterpret_cast<const asCObjectType*>(type));
5104 
5105 	// Construct the object, but do not call the actual constructor that initializes the members
5106 	// The initialization will be done by the application afterwards, e.g. through serialization.
5107 	asCScriptObject *obj = reinterpret_cast<asCScriptObject*>(CallAlloc(objType));
5108 
5109 	// Pre-initialize the memory so there are no invalid pointers
5110 	ScriptObject_ConstructUnitialized(objType, obj);
5111 
5112 	return obj;
5113 }
5114 
5115 // interface
CreateScriptObjectCopy(void * origObj,const asITypeInfo * type)5116 void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo *type)
5117 {
5118 	if( origObj == 0 || type == 0 ) return 0;
5119 
5120 	void *newObj = 0;
5121 
5122 	const asCObjectType *ot = reinterpret_cast<const asCObjectType*>(type);
5123 	// TODO: runtime optimize: Should call copy factory for ref types too
5124 	if( ot->beh.copyconstruct )
5125 	{
5126 		// Manually allocate the memory, then call the copy constructor
5127 		newObj = CallAlloc(ot);
5128 #ifdef AS_NO_EXCEPTIONS
5129 		CallObjectMethod(newObj, origObj, ot->beh.copyconstruct);
5130 #else
5131 		try
5132 		{
5133 			CallObjectMethod(newObj, origObj, ot->beh.copyconstruct);
5134 		}
5135 		catch(...)
5136 		{
5137 			asIScriptContext *ctx = asGetActiveContext();
5138 			if( ctx )
5139 				ctx->SetException(TXT_EXCEPTION_CAUGHT);
5140 
5141 			// Free the memory
5142 			CallFree(newObj);
5143 			newObj = 0;
5144 		}
5145 #endif
5146 	}
5147 	else
5148 	{
5149 		// Allocate the object and then do a value assign
5150 		newObj = CreateScriptObject(type);
5151 		if( newObj == 0 ) return 0;
5152 
5153 		AssignScriptObject(newObj, origObj, type);
5154 	}
5155 
5156 	return newObj;
5157 }
5158 
5159 // internal
ConstructScriptObjectCopy(void * mem,void * obj,asCObjectType * type)5160 void asCScriptEngine::ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type)
5161 {
5162 	if( type == 0 || mem == 0 || obj == 0 ) return;
5163 
5164 	// This function is only meant to be used for value types
5165 	asASSERT( type->flags & asOBJ_VALUE );
5166 
5167 	// Call the copy constructor if available, else call the default constructor followed by the opAssign
5168 	int funcIndex = type->beh.copyconstruct;
5169 	if( funcIndex )
5170 	{
5171 		CallObjectMethod(mem, obj, funcIndex);
5172 	}
5173 	else
5174 	{
5175 		funcIndex = type->beh.construct;
5176 		if( funcIndex )
5177 			CallObjectMethod(mem, funcIndex);
5178 
5179 		AssignScriptObject(mem, obj, type);
5180 	}
5181 }
5182 
5183 // interface
AssignScriptObject(void * dstObj,void * srcObj,const asITypeInfo * type)5184 int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type)
5185 {
5186 	// TODO: Warn about invalid call in message stream
5187 	// TODO: Should a script exception be set in case a context is active?
5188 	if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG;
5189 
5190 	const asCObjectType *objType = reinterpret_cast<const asCObjectType*>(type);
5191 
5192 	// If value assign for ref types has been disabled, then don't do anything if the type is a ref type
5193 	if( ep.disallowValueAssignForRefType && (objType->flags & asOBJ_REF) && !(objType->flags & asOBJ_SCOPED) )
5194 		return asNOT_SUPPORTED;
5195 
5196 	// Must not copy if the opAssign is not available and the object is not a POD object
5197 	if( objType->beh.copy )
5198 	{
5199 		asCScriptFunction *func = scriptFunctions[objType->beh.copy];
5200 		if( func->funcType == asFUNC_SYSTEM )
5201 			CallObjectMethod(dstObj, srcObj, objType->beh.copy);
5202 		else
5203 		{
5204 			// Call the script class' opAssign method
5205 			asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT );
5206 			reinterpret_cast<asCScriptObject*>(dstObj)->CopyFrom(reinterpret_cast<asCScriptObject*>(srcObj));
5207 		}
5208 	}
5209 	else if( objType->size && (objType->flags & asOBJ_POD) )
5210 	{
5211 		memcpy(dstObj, srcObj, objType->size);
5212 	}
5213 
5214 	return asSUCCESS;
5215 }
5216 
5217 // interface
AddRefScriptObject(void * obj,const asITypeInfo * type)5218 void asCScriptEngine::AddRefScriptObject(void *obj, const asITypeInfo *type)
5219 {
5220 	// Make sure it is not a null pointer
5221 	if( obj == 0 || type == 0 ) return;
5222 
5223 	const asCTypeInfo *ti = static_cast<const asCTypeInfo*>(type);
5224 	if (ti->flags & asOBJ_FUNCDEF)
5225 	{
5226 		CallObjectMethod(obj, functionBehaviours.beh.addref);
5227 	}
5228 	else
5229 	{
5230 		asCObjectType *objType = CastToObjectType(const_cast<asCTypeInfo*>(ti));
5231 		if (objType && objType->beh.addref)
5232 		{
5233 			// Call the addref behaviour
5234 			CallObjectMethod(obj, objType->beh.addref);
5235 		}
5236 	}
5237 }
5238 
5239 // interface
ReleaseScriptObject(void * obj,const asITypeInfo * type)5240 void asCScriptEngine::ReleaseScriptObject(void *obj, const asITypeInfo *type)
5241 {
5242 	// Make sure it is not a null pointer
5243 	if( obj == 0 || type == 0 ) return;
5244 
5245 	const asCTypeInfo *ti = static_cast<const asCTypeInfo*>(type);
5246 	if (ti->flags & asOBJ_FUNCDEF)
5247 	{
5248 		CallObjectMethod(obj, functionBehaviours.beh.release);
5249 	}
5250 	else
5251 	{
5252 		asCObjectType *objType = CastToObjectType(const_cast<asCTypeInfo*>(ti));
5253 		if (objType && objType->flags & asOBJ_REF)
5254 		{
5255 			asASSERT((objType->flags & asOBJ_NOCOUNT) || objType->beh.release);
5256 			if (objType->beh.release)
5257 			{
5258 				// Call the release behaviour
5259 				CallObjectMethod(obj, objType->beh.release);
5260 			}
5261 		}
5262 		else if( objType )
5263 		{
5264 			// Call the destructor
5265 			if (objType->beh.destruct)
5266 				CallObjectMethod(obj, objType->beh.destruct);
5267 			else if (objType->flags & asOBJ_LIST_PATTERN)
5268 				DestroyList((asBYTE*)obj, objType);
5269 
5270 			// We'll have to trust that the memory for the object was allocated with CallAlloc.
5271 			// This is true if the object was created in the context, or with CreateScriptObject.
5272 
5273 			// Then free the memory
5274 			CallFree(obj);
5275 		}
5276 	}
5277 }
5278 
5279 // interface
BeginConfigGroup(const char * groupName)5280 int asCScriptEngine::BeginConfigGroup(const char *groupName)
5281 {
5282 	// Make sure the group name doesn't already exist
5283 	for( asUINT n = 0; n < configGroups.GetLength(); n++ )
5284 	{
5285 		if( configGroups[n]->groupName == groupName )
5286 			return asNAME_TAKEN;
5287 	}
5288 
5289 	if( currentGroup != &defaultGroup )
5290 		return asNOT_SUPPORTED;
5291 
5292 	asCConfigGroup *group = asNEW(asCConfigGroup)();
5293 	if( group == 0 )
5294 		return asOUT_OF_MEMORY;
5295 
5296 	group->groupName = groupName;
5297 
5298 	configGroups.PushLast(group);
5299 	currentGroup = group;
5300 
5301 	return 0;
5302 }
5303 
5304 // interface
EndConfigGroup()5305 int asCScriptEngine::EndConfigGroup()
5306 {
5307 	// Raise error if trying to end the default config
5308 	if( currentGroup == &defaultGroup )
5309 		return asERROR;
5310 
5311 	currentGroup = &defaultGroup;
5312 
5313 	return 0;
5314 }
5315 
5316 // interface
RemoveConfigGroup(const char * groupName)5317 int asCScriptEngine::RemoveConfigGroup(const char *groupName)
5318 {
5319 	// It is not allowed to remove a group that is still in use.
5320 
5321 	// It would be possible to change the code in such a way that
5322 	// the group could be removed even though it was still in use,
5323 	// but that would cause severe negative impact on runtime
5324 	// performance, since the VM would then have to be able handle
5325 	// situations where the types, functions, and global variables
5326 	// can be removed at any time.
5327 
5328 	for( asUINT n = 0; n < configGroups.GetLength(); n++ )
5329 	{
5330 		if( configGroups[n]->groupName == groupName )
5331 		{
5332 			asCConfigGroup *group = configGroups[n];
5333 
5334 			// Remove any unused generated template instances
5335 			// before verifying if the config group is still in use.
5336 			// RemoveTemplateInstanceType() checks if the instance is in use
5337 			for( asUINT g = generatedTemplateTypes.GetLength(); g-- > 0; )
5338 				RemoveTemplateInstanceType(generatedTemplateTypes[g]);
5339 
5340 			// Make sure the group isn't referenced by anyone
5341 			if( group->refCount > 0 )
5342 				return asCONFIG_GROUP_IS_IN_USE;
5343 
5344 			// Verify if any objects registered in this group is still alive
5345 			if( group->HasLiveObjects() )
5346 				return asCONFIG_GROUP_IS_IN_USE;
5347 
5348 			// Remove the group from the list
5349 			if( n == configGroups.GetLength() - 1 )
5350 				configGroups.PopLast();
5351 			else
5352 				configGroups[n] = configGroups.PopLast();
5353 
5354 			// Remove the configurations registered with this group
5355 			group->RemoveConfiguration(this);
5356 
5357 			asDELETE(group,asCConfigGroup);
5358 		}
5359 	}
5360 
5361 	return 0;
5362 }
5363 
FindConfigGroupForFunction(int funcId) const5364 asCConfigGroup *asCScriptEngine::FindConfigGroupForFunction(int funcId) const
5365 {
5366 	for( asUINT n = 0; n < configGroups.GetLength(); n++ )
5367 	{
5368 		// Check global functions
5369 		asUINT m;
5370 		for( m = 0; m < configGroups[n]->scriptFunctions.GetLength(); m++ )
5371 		{
5372 			if( configGroups[n]->scriptFunctions[m]->id == funcId )
5373 				return configGroups[n];
5374 		}
5375 	}
5376 
5377 	return 0;
5378 }
5379 
5380 
FindConfigGroupForGlobalVar(int gvarId) const5381 asCConfigGroup *asCScriptEngine::FindConfigGroupForGlobalVar(int gvarId) const
5382 {
5383 	for( asUINT n = 0; n < configGroups.GetLength(); n++ )
5384 	{
5385 		for( asUINT m = 0; m < configGroups[n]->globalProps.GetLength(); m++ )
5386 		{
5387 			if( int(configGroups[n]->globalProps[m]->id) == gvarId )
5388 				return configGroups[n];
5389 		}
5390 	}
5391 
5392 	return 0;
5393 }
5394 
FindConfigGroupForTypeInfo(const asCTypeInfo * objType) const5395 asCConfigGroup *asCScriptEngine::FindConfigGroupForTypeInfo(const asCTypeInfo *objType) const
5396 {
5397 	for( asUINT n = 0; n < configGroups.GetLength(); n++ )
5398 	{
5399 		for( asUINT m = 0; m < configGroups[n]->types.GetLength(); m++ )
5400 		{
5401 			if( configGroups[n]->types[m] == objType )
5402 				return configGroups[n];
5403 		}
5404 	}
5405 
5406 	return 0;
5407 }
5408 
FindConfigGroupForFuncDef(const asCFuncdefType * funcDef) const5409 asCConfigGroup *asCScriptEngine::FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const
5410 {
5411 	for( asUINT n = 0; n < configGroups.GetLength(); n++ )
5412 	{
5413 		asCFuncdefType *f = const_cast<asCFuncdefType*>(funcDef);
5414 		if( configGroups[n]->types.Exists(f) )
5415 			return configGroups[n];
5416 	}
5417 
5418 	return 0;
5419 }
5420 
5421 // interface
SetDefaultAccessMask(asDWORD defaultMask)5422 asDWORD asCScriptEngine::SetDefaultAccessMask(asDWORD defaultMask)
5423 {
5424 	asDWORD old = defaultAccessMask;
5425 	defaultAccessMask = defaultMask;
5426 	return old;
5427 }
5428 
GetNextScriptFunctionId()5429 int asCScriptEngine::GetNextScriptFunctionId()
5430 {
5431 	// This function only returns the next function id that
5432 	// should be used. It doesn't update the internal arrays.
5433 	if( freeScriptFunctionIds.GetLength() )
5434 		return freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1];
5435 
5436 	return (int)scriptFunctions.GetLength();
5437 }
5438 
AddScriptFunction(asCScriptFunction * func)5439 void asCScriptEngine::AddScriptFunction(asCScriptFunction *func)
5440 {
5441 	// Update the internal arrays with the function id that is now used
5442 	if( freeScriptFunctionIds.GetLength() && freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1] == func->id )
5443 		freeScriptFunctionIds.PopLast();
5444 
5445 	if( asUINT(func->id) == scriptFunctions.GetLength() )
5446 		scriptFunctions.PushLast(func);
5447 	else
5448 	{
5449 		// The slot should be empty or already set with the function, which happens if an existing shared function is reused
5450 		asASSERT( scriptFunctions[func->id] == 0 || scriptFunctions[func->id] == func );
5451 		scriptFunctions[func->id] = func;
5452 	}
5453 }
5454 
RemoveScriptFunction(asCScriptFunction * func)5455 void asCScriptEngine::RemoveScriptFunction(asCScriptFunction *func)
5456 {
5457 	if( func == 0 || func->id < 0 ) return;
5458 	int id = func->id & ~FUNC_IMPORTED;
5459 	if( func->funcType == asFUNC_IMPORTED )
5460 	{
5461 		if( id >= (int)importedFunctions.GetLength() ) return;
5462 
5463 		if( importedFunctions[id] )
5464 		{
5465 			// Remove the function from the list of script functions
5466 			if( id == (int)importedFunctions.GetLength() - 1 )
5467 			{
5468 				importedFunctions.PopLast();
5469 			}
5470 			else
5471 			{
5472 				importedFunctions[id] = 0;
5473 				freeImportedFunctionIdxs.PushLast(id);
5474 			}
5475 		}
5476 	}
5477 	else
5478 	{
5479 		if( id >= (int)scriptFunctions.GetLength() ) return;
5480 		asASSERT( func == scriptFunctions[id] );
5481 
5482 		if( scriptFunctions[id] )
5483 		{
5484 			// Remove the function from the list of script functions
5485 			if( id == (int)scriptFunctions.GetLength() - 1 )
5486 			{
5487 				scriptFunctions.PopLast();
5488 			}
5489 			else
5490 			{
5491 				scriptFunctions[id] = 0;
5492 				freeScriptFunctionIds.PushLast(id);
5493 			}
5494 
5495 			// Is the function used as signature id?
5496 			if( func->signatureId == id )
5497 			{
5498 				// Remove the signature id
5499 				signatureIds.RemoveValue(func);
5500 
5501 				// Update all functions using the signature id
5502 				int newSigId = 0;
5503 				for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ )
5504 				{
5505 					if( scriptFunctions[n] && scriptFunctions[n]->signatureId == id )
5506 					{
5507 						if( newSigId == 0 )
5508 						{
5509 							newSigId = scriptFunctions[n]->id;
5510 							signatureIds.PushLast(scriptFunctions[n]);
5511 						}
5512 
5513 						scriptFunctions[n]->signatureId = newSigId;
5514 					}
5515 				}
5516 			}
5517 		}
5518 	}
5519 }
5520 
5521 // internal
RemoveFuncdef(asCFuncdefType * funcdef)5522 void asCScriptEngine::RemoveFuncdef(asCFuncdefType *funcdef)
5523 {
5524 	funcDefs.RemoveValue(funcdef);
5525 }
5526 
5527 // interface
RegisterFuncdef(const char * decl)5528 int asCScriptEngine::RegisterFuncdef(const char *decl)
5529 {
5530 	if( decl == 0 ) return ConfigError(asINVALID_ARG, "RegisterFuncdef", decl, 0);
5531 
5532 	// Parse the function declaration
5533 	asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF);
5534 	if( func == 0 )
5535 		return ConfigError(asOUT_OF_MEMORY, "RegisterFuncdef", decl, 0);
5536 
5537 	asCBuilder bld(this, 0);
5538 	asCObjectType *parentClass = 0;
5539 	int r = bld.ParseFunctionDeclaration(0, decl, func, false, 0, 0, defaultNamespace, 0, &parentClass);
5540 	if( r < 0 )
5541 	{
5542 		// Set as dummy function before deleting
5543 		func->funcType = asFUNC_DUMMY;
5544 		asDELETE(func,asCScriptFunction);
5545 		return ConfigError(asINVALID_DECLARATION, "RegisterFuncdef", decl, 0);
5546 	}
5547 
5548 	// Check name conflicts
5549 	r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace);
5550 	if( r < 0 )
5551 	{
5552 		asDELETE(func,asCScriptFunction);
5553 		return ConfigError(asNAME_TAKEN, "RegisterFuncdef", decl, 0);
5554 	}
5555 
5556 	func->id = GetNextScriptFunctionId();
5557 	AddScriptFunction(func);
5558 
5559 	asCFuncdefType *fdt = asNEW(asCFuncdefType)(this, func);
5560 	funcDefs.PushLast(fdt); // doesn't increase refcount
5561 	registeredFuncDefs.PushLast(fdt); // doesn't increase refcount
5562 	allRegisteredTypes.Insert(asSNameSpaceNamePair(fdt->nameSpace, fdt->name), fdt); // constructor already set the ref count to 1
5563 
5564 	currentGroup->types.PushLast(fdt);
5565 	if (parentClass)
5566 	{
5567 		parentClass->childFuncDefs.PushLast(fdt);
5568 		fdt->parentClass = parentClass;
5569 
5570 		// Check if the method restricts that use of the template to value types or reference types
5571 		if (parentClass->flags & asOBJ_TEMPLATE)
5572 		{
5573 			r = SetTemplateRestrictions(parentClass, func, "RegisterFuncdef", decl);
5574 			if (r < 0)
5575 				return r;
5576 		}
5577 	}
5578 
5579 	// If parameter type from other groups are used, add references
5580 	currentGroup->AddReferencesForFunc(this, func);
5581 
5582 	// Return the type id as success
5583 	return GetTypeIdFromDataType(asCDataType::CreateType(fdt, false));
5584 }
5585 
5586 // interface
GetFuncdefCount() const5587 asUINT asCScriptEngine::GetFuncdefCount() const
5588 {
5589 	return asUINT(registeredFuncDefs.GetLength());
5590 }
5591 
5592 // interface
GetFuncdefByIndex(asUINT index) const5593 asITypeInfo *asCScriptEngine::GetFuncdefByIndex(asUINT index) const
5594 {
5595 	if( index >= registeredFuncDefs.GetLength() )
5596 		return 0;
5597 
5598 	return registeredFuncDefs[index];
5599 }
5600 
5601 // internal
FindMatchingFuncdef(asCScriptFunction * func,asCModule * module)5602 asCFuncdefType *asCScriptEngine::FindMatchingFuncdef(asCScriptFunction *func, asCModule *module)
5603 {
5604 	asCFuncdefType *funcDef = func->funcdefType;
5605 
5606 	if (funcDef == 0)
5607 	{
5608 		// Check if there is any matching funcdefs already in the engine that can be reused
5609 		for (asUINT n = 0; n < funcDefs.GetLength(); n++)
5610 		{
5611 			if (funcDefs[n]->funcdef->IsSignatureExceptNameEqual(func))
5612 			{
5613 				if (func->IsShared() && !funcDefs[n]->funcdef->IsShared())
5614 					continue;
5615 				funcDef = funcDefs[n];
5616 				break;
5617 			}
5618 		}
5619 	}
5620 
5621 	if (funcDef == 0)
5622 	{
5623 		// Create a matching funcdef
5624 		asCScriptFunction *fd = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF);
5625 		fd->name = func->name;
5626 		fd->nameSpace = func->nameSpace;
5627 		fd->SetShared(func->IsShared());
5628 
5629 		fd->returnType = func->returnType;
5630 		fd->parameterTypes = func->parameterTypes;
5631 		fd->inOutFlags = func->inOutFlags;
5632 
5633 		funcDef = asNEW(asCFuncdefType)(this, fd);
5634 		funcDefs.PushLast(funcDef); // doesn't increase the refCount
5635 
5636 		fd->id = GetNextScriptFunctionId();
5637 		AddScriptFunction(fd);
5638 
5639 		if (module)
5640 		{
5641 			// Add the new funcdef to the module so it will
5642 			// be available when saving the bytecode
5643 			funcDef->module = module;
5644 			module->funcDefs.PushLast(funcDef); // the refCount was already accounted for in the constructor
5645 		}
5646 
5647 		// Observe, if the funcdef is created without informing a module a reference will be stored in the
5648 		// engine's funcDefs array, but it will not be owned by any module. This means that it will live on
5649 		// until the engine is released.
5650 	}
5651 
5652 	if (funcDef && module && funcDef->module && funcDef->module != module)
5653 	{
5654 		// Unless this is a registered funcDef the returned funcDef must
5655 		// be stored as part of the module for saving/loading bytecode
5656 		if (!module->funcDefs.Exists(funcDef))
5657 		{
5658 			module->funcDefs.PushLast(funcDef);
5659 			funcDef->AddRefInternal();
5660 		}
5661 		else
5662 		{
5663 			asASSERT(funcDef->IsShared());
5664 		}
5665 	}
5666 
5667 	return funcDef;
5668 }
5669 
5670 // interface
5671 // TODO: typedef: Accept complex types for the typedefs
RegisterTypedef(const char * type,const char * decl)5672 int asCScriptEngine::RegisterTypedef(const char *type, const char *decl)
5673 {
5674 	if( type == 0 ) return ConfigError(asINVALID_NAME, "RegisterTypedef", type, decl);
5675 
5676 	// Verify if the name has been registered as a type already
5677 	// TODO: Must check against registered funcdefs too
5678 	if( GetRegisteredType(type, defaultNamespace) )
5679 		// Let the application recover from this error, for example if the same typedef is registered twice
5680 		return asALREADY_REGISTERED;
5681 
5682 	// Grab the data type
5683 	size_t tokenLen;
5684 	eTokenType token;
5685 	asCDataType dataType;
5686 
5687 	//	Create the data type
5688 	token = tok.GetToken(decl, strlen(decl), &tokenLen);
5689 	switch(token)
5690 	{
5691 	case ttBool:
5692 	case ttInt:
5693 	case ttInt8:
5694 	case ttInt16:
5695 	case ttInt64:
5696 	case ttUInt:
5697 	case ttUInt8:
5698 	case ttUInt16:
5699 	case ttUInt64:
5700 	case ttFloat:
5701 	case ttDouble:
5702 		if( strlen(decl) != tokenLen )
5703 		{
5704 			return ConfigError(asINVALID_TYPE, "RegisterTypedef", type, decl);
5705 		}
5706 		break;
5707 
5708 	default:
5709 		return ConfigError(asINVALID_TYPE, "RegisterTypedef", type, decl);
5710 	}
5711 
5712 	dataType = asCDataType::CreatePrimitive(token, false);
5713 
5714 	// Make sure the name is not a reserved keyword
5715 	token = tok.GetToken(type, strlen(type), &tokenLen);
5716 	if( token != ttIdentifier || strlen(type) != tokenLen )
5717 		return ConfigError(asINVALID_NAME, "RegisterTypedef", type, decl);
5718 
5719 	asCBuilder bld(this, 0);
5720 	int r = bld.CheckNameConflict(type, 0, 0, defaultNamespace);
5721 	if( r < 0 )
5722 		return ConfigError(asNAME_TAKEN, "RegisterTypedef", type, decl);
5723 
5724 	// Don't have to check against members of object
5725 	// types as they are allowed to use the names
5726 
5727 	// Put the data type in the list
5728 	asCTypedefType *td = asNEW(asCTypedefType)(this);
5729 	if( td == 0 )
5730 		return ConfigError(asOUT_OF_MEMORY, "RegisterTypedef", type, decl);
5731 
5732 	td->flags           = asOBJ_TYPEDEF;
5733 	td->size            = dataType.GetSizeInMemoryBytes();
5734 	td->name            = type;
5735 	td->nameSpace       = defaultNamespace;
5736 	td->aliasForType    = dataType;
5737 
5738 	allRegisteredTypes.Insert(asSNameSpaceNamePair(td->nameSpace, td->name), td);
5739 	registeredTypeDefs.PushLast(td);
5740 
5741 	currentGroup->types.PushLast(td);
5742 
5743 	return GetTypeIdByDecl(type);
5744 }
5745 
5746 // interface
GetTypedefCount() const5747 asUINT asCScriptEngine::GetTypedefCount() const
5748 {
5749 	return asUINT(registeredTypeDefs.GetLength());
5750 }
5751 
5752 // interface
GetTypedefByIndex(asUINT index) const5753 asITypeInfo *asCScriptEngine::GetTypedefByIndex(asUINT index) const
5754 {
5755 	if( index >= registeredTypeDefs.GetLength() )
5756 		return 0;
5757 
5758 	return registeredTypeDefs[index];
5759 }
5760 
5761 // interface
RegisterEnum(const char * name)5762 int asCScriptEngine::RegisterEnum(const char *name)
5763 {
5764 	//	Check the name
5765 	if( NULL == name )
5766 		return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0);
5767 
5768 	// Verify if the name has been registered as a type already
5769 	if( GetRegisteredType(name, defaultNamespace) )
5770 		return asALREADY_REGISTERED;
5771 
5772 	// Use builder to parse the datatype
5773 	asCDataType dt;
5774 	asCBuilder bld(this, 0);
5775 	bool oldMsgCallback = msgCallback; msgCallback = false;
5776 	int r = bld.ParseDataType(name, &dt, defaultNamespace);
5777 	msgCallback = oldMsgCallback;
5778 	if( r >= 0 )
5779 	{
5780 		// If it is not in the defaultNamespace then the type was successfully parsed because
5781 		// it is declared in a parent namespace which shouldn't be treated as an error
5782 		if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace )
5783 			return ConfigError(asERROR, "RegisterEnum", name, 0);
5784 	}
5785 
5786 	// Make sure the name is not a reserved keyword
5787 	size_t tokenLen;
5788 	int token = tok.GetToken(name, strlen(name), &tokenLen);
5789 	if( token != ttIdentifier || strlen(name) != tokenLen )
5790 		return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0);
5791 
5792 	r = bld.CheckNameConflict(name, 0, 0, defaultNamespace);
5793 	if( r < 0 )
5794 		return ConfigError(asNAME_TAKEN, "RegisterEnum", name, 0);
5795 
5796 	asCEnumType *st = asNEW(asCEnumType)(this);
5797 	if( st == 0 )
5798 		return ConfigError(asOUT_OF_MEMORY, "RegisterEnum", name, 0);
5799 
5800 	asCDataType dataType;
5801 	dataType.CreatePrimitive(ttInt, false);
5802 
5803 	st->flags = asOBJ_ENUM | asOBJ_SHARED;
5804 	st->size = 4;
5805 	st->name = name;
5806 	st->nameSpace = defaultNamespace;
5807 
5808 	allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st);
5809 	registeredEnums.PushLast(st);
5810 
5811 	currentGroup->types.PushLast(st);
5812 
5813 	return GetTypeIdByDecl(name);
5814 }
5815 
5816 // interface
RegisterEnumValue(const char * typeName,const char * valueName,int value)5817 int asCScriptEngine::RegisterEnumValue(const char *typeName, const char *valueName, int value)
5818 {
5819 	// Verify that the correct config group is used
5820 	if( currentGroup->FindType(typeName) == 0 )
5821 		return ConfigError(asWRONG_CONFIG_GROUP, "RegisterEnumValue", typeName, valueName);
5822 
5823 	asCDataType dt;
5824 	int r;
5825 	asCBuilder bld(this, 0);
5826 	r = bld.ParseDataType(typeName, &dt, defaultNamespace);
5827 	if( r < 0 )
5828 		return ConfigError(r, "RegisterEnumValue", typeName, valueName);
5829 
5830 	// Store the enum value
5831 	asCEnumType *ot = CastToEnumType(dt.GetTypeInfo());
5832 	if( ot == 0 )
5833 		return ConfigError(asINVALID_TYPE, "RegisterEnumValue", typeName, valueName);
5834 
5835 	if( NULL == valueName )
5836 		return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName);
5837 
5838 	asUINT tokenLen = 0;
5839 	asETokenClass tokenClass = ParseToken(valueName, 0, &tokenLen);
5840 	if( tokenClass != asTC_IDENTIFIER || tokenLen != strlen(valueName) )
5841 		return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName);
5842 
5843 	for( unsigned int n = 0; n < ot->enumValues.GetLength(); n++ )
5844 	{
5845 		if( ot->enumValues[n]->name == valueName )
5846 			return ConfigError(asALREADY_REGISTERED, "RegisterEnumValue", typeName, valueName);
5847 	}
5848 
5849 	asSEnumValue *e = asNEW(asSEnumValue);
5850 	if( e == 0 )
5851 		return ConfigError(asOUT_OF_MEMORY, "RegisterEnumValue", typeName, valueName);
5852 
5853 	e->name = valueName;
5854 	e->value = value;
5855 
5856 	ot->enumValues.PushLast(e);
5857 
5858 	return asSUCCESS;
5859 }
5860 
5861 // interface
GetEnumCount() const5862 asUINT asCScriptEngine::GetEnumCount() const
5863 {
5864 	return registeredEnums.GetLength();
5865 }
5866 
5867 // interface
GetEnumByIndex(asUINT index) const5868 asITypeInfo *asCScriptEngine::GetEnumByIndex(asUINT index) const
5869 {
5870 	if( index >= registeredEnums.GetLength() )
5871 		return 0;
5872 
5873 	return registeredEnums[index];
5874 }
5875 
5876 // interface
GetObjectTypeCount() const5877 asUINT asCScriptEngine::GetObjectTypeCount() const
5878 {
5879 	return asUINT(registeredObjTypes.GetLength());
5880 }
5881 
5882 // interface
GetObjectTypeByIndex(asUINT index) const5883 asITypeInfo *asCScriptEngine::GetObjectTypeByIndex(asUINT index) const
5884 {
5885 	if( index >= registeredObjTypes.GetLength() )
5886 		return 0;
5887 
5888 	return registeredObjTypes[index];
5889 }
5890 
5891 // interface
GetTypeInfoByName(const char * name) const5892 asITypeInfo *asCScriptEngine::GetTypeInfoByName(const char *name) const
5893 {
5894 	asSNameSpace *ns = defaultNamespace;
5895 	while (ns)
5896 	{
5897 		// Check the object types
5898 		for (asUINT n = 0; n < registeredObjTypes.GetLength(); n++)
5899 		{
5900 			if (registeredObjTypes[n]->name == name &&
5901 				registeredObjTypes[n]->nameSpace == ns)
5902 				return registeredObjTypes[n];
5903 		}
5904 
5905 		// Perhaps it is a template type? In this case
5906 		// the returned type will be the generic type
5907 		for (asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++)
5908 		{
5909 			if (registeredTemplateTypes[n]->name == name &&
5910 				registeredTemplateTypes[n]->nameSpace == ns)
5911 				return registeredTemplateTypes[n];
5912 		}
5913 
5914 		// Check the enum types
5915 		for (asUINT n = 0; n < registeredEnums.GetLength(); n++)
5916 		{
5917 			if (registeredEnums[n]->name == name &&
5918 				registeredEnums[n]->nameSpace == ns)
5919 				return registeredEnums[n];
5920 		}
5921 
5922 		// Check the typedefs
5923 		for (asUINT n = 0; n < registeredTypeDefs.GetLength();n++)
5924 		{
5925 			if (registeredTypeDefs[n]->name == name &&
5926 				registeredTypeDefs[n]->nameSpace == ns)
5927 				return registeredTypeDefs[n];
5928 		}
5929 
5930 		// Recursively search parent namespace
5931 		ns = GetParentNameSpace(ns);
5932 	}
5933 
5934 	return 0;
5935 }
5936 
5937 // interface
GetTypeInfoById(int typeId) const5938 asITypeInfo *asCScriptEngine::GetTypeInfoById(int typeId) const
5939 {
5940 	asCDataType dt = GetDataTypeFromTypeId(typeId);
5941 
5942 	// Is the type id valid?
5943 	if (!dt.IsValid()) return 0;
5944 
5945 	return dt.GetTypeInfo();
5946 }
5947 
5948 // interface
GetFunctionById(int funcId) const5949 asIScriptFunction *asCScriptEngine::GetFunctionById(int funcId) const
5950 {
5951 	return GetScriptFunction(funcId);
5952 }
5953 
5954 // internal
IsTemplateType(const char * name) const5955 bool asCScriptEngine::IsTemplateType(const char *name) const
5956 {
5957 	// Only look in the list of template types (not instance types)
5958 	for( unsigned int n = 0; n < registeredTemplateTypes.GetLength(); n++ )
5959 	{
5960 		asCObjectType *type = registeredTemplateTypes[n];
5961 		if( type && type->name == name )
5962 			return true;
5963 	}
5964 
5965 	return false;
5966 }
5967 
5968 // internal
GetScriptSectionNameIndex(const char * name)5969 int asCScriptEngine::GetScriptSectionNameIndex(const char *name)
5970 {
5971 	ACQUIREEXCLUSIVE(engineRWLock);
5972 
5973 	// TODO: These names are only released when the engine is freed. The assumption is that
5974 	//       the same script section names will be reused instead of there always being new
5975 	//       names. Is this assumption valid? Do we need to add reference counting?
5976 
5977 	// Store the script section names for future reference
5978 	for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ )
5979 	{
5980 		if( scriptSectionNames[n]->Compare(name) == 0 )
5981 		{
5982 			RELEASEEXCLUSIVE(engineRWLock);
5983 			return n;
5984 		}
5985 	}
5986 
5987 	asCString *str = asNEW(asCString)(name);
5988 	if( str )
5989 		scriptSectionNames.PushLast(str);
5990 	int r = int(scriptSectionNames.GetLength()-1);
5991 
5992 	RELEASEEXCLUSIVE(engineRWLock);
5993 
5994 	return r;
5995 }
5996 
5997 // interface
SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback,asPWORD type)5998 void asCScriptEngine::SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type)
5999 {
6000 	ACQUIREEXCLUSIVE(engineRWLock);
6001 
6002 	for( asUINT n = 0; n < cleanEngineFuncs.GetLength(); n++ )
6003 	{
6004 		if( cleanEngineFuncs[n].type == type )
6005 		{
6006 			cleanEngineFuncs[n].cleanFunc = callback;
6007 
6008 			RELEASEEXCLUSIVE(engineRWLock);
6009 
6010 			return;
6011 		}
6012 	}
6013 	SEngineClean otc = {type, callback};
6014 	cleanEngineFuncs.PushLast(otc);
6015 
6016 	RELEASEEXCLUSIVE(engineRWLock);
6017 }
6018 
6019 // interface
SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback,asPWORD type)6020 void asCScriptEngine::SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type)
6021 {
6022 	ACQUIREEXCLUSIVE(engineRWLock);
6023 
6024 	for( asUINT n = 0; n < cleanModuleFuncs.GetLength(); n++ )
6025 	{
6026 		if( cleanModuleFuncs[n].type == type )
6027 		{
6028 			cleanModuleFuncs[n].cleanFunc = callback;
6029 
6030 			RELEASEEXCLUSIVE(engineRWLock);
6031 
6032 			return;
6033 		}
6034 	}
6035 	SModuleClean otc = {type, callback};
6036 	cleanModuleFuncs.PushLast(otc);
6037 
6038 	RELEASEEXCLUSIVE(engineRWLock);
6039 }
6040 
6041 // interface
SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback,asPWORD type)6042 void asCScriptEngine::SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type)
6043 {
6044 	ACQUIREEXCLUSIVE(engineRWLock);
6045 
6046 	for( asUINT n = 0; n < cleanContextFuncs.GetLength(); n++ )
6047 	{
6048 		if( cleanContextFuncs[n].type == type )
6049 		{
6050 			cleanContextFuncs[n].cleanFunc = callback;
6051 
6052 			RELEASEEXCLUSIVE(engineRWLock);
6053 
6054 			return;
6055 		}
6056 	}
6057 	SContextClean otc = {type, callback};
6058 	cleanContextFuncs.PushLast(otc);
6059 
6060 	RELEASEEXCLUSIVE(engineRWLock);
6061 }
6062 
6063 // interface
SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback,asPWORD type)6064 void asCScriptEngine::SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type)
6065 {
6066 	ACQUIREEXCLUSIVE(engineRWLock);
6067 
6068 	for( asUINT n = 0; n < cleanFunctionFuncs.GetLength(); n++ )
6069 	{
6070 		if( cleanFunctionFuncs[n].type == type )
6071 		{
6072 			cleanFunctionFuncs[n].cleanFunc = callback;
6073 
6074 			RELEASEEXCLUSIVE(engineRWLock);
6075 
6076 			return;
6077 		}
6078 	}
6079 	SFunctionClean otc = {type, callback};
6080 	cleanFunctionFuncs.PushLast(otc);
6081 
6082 	RELEASEEXCLUSIVE(engineRWLock);
6083 }
6084 
6085 // interface
SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback,asPWORD type)6086 void asCScriptEngine::SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type)
6087 {
6088 	ACQUIREEXCLUSIVE(engineRWLock);
6089 
6090 	for( asUINT n = 0; n < cleanTypeInfoFuncs.GetLength(); n++ )
6091 	{
6092 		if( cleanTypeInfoFuncs[n].type == type )
6093 		{
6094 			cleanTypeInfoFuncs[n].cleanFunc = callback;
6095 
6096 			RELEASEEXCLUSIVE(engineRWLock);
6097 
6098 			return;
6099 		}
6100 	}
6101 	STypeInfoClean otc = {type, callback};
6102 	cleanTypeInfoFuncs.PushLast(otc);
6103 
6104 	RELEASEEXCLUSIVE(engineRWLock);
6105 }
6106 
6107 // interface
SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback,asPWORD type)6108 void asCScriptEngine::SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type)
6109 {
6110 	ACQUIREEXCLUSIVE(engineRWLock);
6111 
6112 	for( asUINT n = 0; n < cleanScriptObjectFuncs.GetLength(); n++ )
6113 	{
6114 		if( cleanScriptObjectFuncs[n].type == type )
6115 		{
6116 			cleanScriptObjectFuncs[n].cleanFunc = callback;
6117 
6118 			RELEASEEXCLUSIVE(engineRWLock);
6119 
6120 			return;
6121 		}
6122 	}
6123 	SScriptObjClean soc = {type, callback};
6124 	cleanScriptObjectFuncs.PushLast(soc);
6125 
6126 	RELEASEEXCLUSIVE(engineRWLock);
6127 }
6128 
6129 // internal
GetListPatternType(int listPatternFuncId)6130 asCObjectType *asCScriptEngine::GetListPatternType(int listPatternFuncId)
6131 {
6132 	// Get the object type either from the constructor's object for value types
6133 	// or from the factory's return type for reference types
6134 	asCObjectType *ot = scriptFunctions[listPatternFuncId]->objectType;
6135 	if( ot == 0 )
6136 		ot = CastToObjectType(scriptFunctions[listPatternFuncId]->returnType.GetTypeInfo());
6137 	asASSERT( ot );
6138 
6139 	// Check if this object type already has a list pattern type
6140 	for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ )
6141 	{
6142 		if( listPatternTypes[n]->templateSubTypes[0].GetTypeInfo() == ot )
6143 			return listPatternTypes[n];
6144 	}
6145 
6146 	// Create a new list pattern type for the given object type
6147 	asCObjectType *lpt = asNEW(asCObjectType)(this);
6148 	lpt->templateSubTypes.PushLast(asCDataType::CreateType(ot, false));
6149 	lpt->flags = asOBJ_LIST_PATTERN;
6150 	listPatternTypes.PushLast(lpt);
6151 
6152 	return lpt;
6153 }
6154 
6155 // internal
DestroyList(asBYTE * buffer,const asCObjectType * listPatternType)6156 void asCScriptEngine::DestroyList(asBYTE *buffer, const asCObjectType *listPatternType)
6157 {
6158 	asASSERT( listPatternType && (listPatternType->flags & asOBJ_LIST_PATTERN) );
6159 
6160 	// Get the list pattern from the listFactory function
6161 	// TODO: runtime optimize: Store the used list factory in the listPatternType itself
6162 	// TODO: runtime optimize: Keep a flag to indicate if there is really a need to free anything
6163 	asCObjectType *ot = CastToObjectType(listPatternType->templateSubTypes[0].GetTypeInfo());
6164 	asCScriptFunction *listFactory = scriptFunctions[ot->beh.listFactory];
6165 	asASSERT( listFactory );
6166 
6167 	asSListPatternNode *node = listFactory->listPattern;
6168 	DestroySubList(buffer, node);
6169 
6170 	asASSERT( node->type == asLPT_END );
6171 }
6172 
6173 // internal
DestroySubList(asBYTE * & buffer,asSListPatternNode * & node)6174 void asCScriptEngine::DestroySubList(asBYTE *&buffer, asSListPatternNode *&node)
6175 {
6176 	asASSERT( node->type == asLPT_START );
6177 
6178 	int count = 0;
6179 
6180 	node = node->next;
6181 	while( node )
6182 	{
6183 		if( node->type == asLPT_REPEAT || node->type == asLPT_REPEAT_SAME )
6184 		{
6185 			// Align the offset to 4 bytes boundary
6186 			if( (asPWORD(buffer) & 0x3) )
6187 				buffer += 4 - (asPWORD(buffer) & 0x3);
6188 
6189 			// Determine how many times the pattern repeat
6190 			count = *(asUINT*)buffer;
6191 			buffer += 4;
6192 
6193 			if( count == 0 )
6194 			{
6195 				// Skip the sub pattern that was expected to be repeated, otherwise
6196 				// we'll try to delete things that don't exist in the buffer
6197 				node = node->next;
6198 				if( node->type == asLPT_START )
6199 				{
6200 					int subCount = 1;
6201 					do
6202 					{
6203 						node = node->next;
6204 						if( node->type == asLPT_START )
6205 							subCount++;
6206 						else if( node->type == asLPT_END )
6207 							subCount--;
6208 					} while( subCount > 0 );
6209 					return;
6210 				}
6211 			}
6212 		}
6213 		else if( node->type == asLPT_TYPE )
6214 		{
6215 			// If we're not in a repeat iteration, then only 1 value should be destroyed
6216 			if( count <= 0 )
6217 				count = 1;
6218 
6219 			asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(node)->dataType;
6220 			bool isVarType = dt.GetTokenType() == ttQuestion;
6221 
6222 			while( count-- )
6223 			{
6224 				if( isVarType )
6225 				{
6226 					// Align the offset to 4 bytes boundary
6227 					if( (asPWORD(buffer) & 0x3) )
6228 						buffer += 4 - (asPWORD(buffer) & 0x3);
6229 
6230 					int typeId = *(int*)buffer;
6231 					buffer += 4;
6232 					dt = GetDataTypeFromTypeId(typeId);
6233 				}
6234 
6235 				asCTypeInfo *ti = dt.GetTypeInfo();
6236 				if( ti && (ti->flags & asOBJ_ENUM) == 0 )
6237 				{
6238 					// Free all instances of this type
6239 					if( ti->flags & asOBJ_VALUE )
6240 					{
6241 						asUINT size = ti->GetSize();
6242 
6243 						// Align the offset to 4 bytes boundary
6244 						if( size >= 4 && (asPWORD(buffer) & 0x3) )
6245 							buffer += 4 - (asPWORD(buffer) & 0x3);
6246 
6247 						asCObjectType *ot = CastToObjectType(ti);
6248 						if( ot && ot->beh.destruct )
6249 						{
6250 							// Only call the destructor if the object has been created
6251 							// We'll assume the object has been created if any byte in
6252 							// the memory is different from 0.
6253 							// TODO: This is not really correct, as bytes may have been
6254 							//       modified by the constructor, but then an exception
6255 							//       thrown aborting the initialization. The engine
6256 							//       really should be keeping track of which objects has
6257 							//       been successfully initialized.
6258 
6259 							for( asUINT n = 0; n < size; n++ )
6260 							{
6261 								if( buffer[n] != 0 )
6262 								{
6263 									void *ptr = (void*)buffer;
6264 									CallObjectMethod(ptr, ot->beh.destruct);
6265 									break;
6266 								}
6267 							}
6268 						}
6269 
6270 						// Advance the pointer in the buffer
6271 						buffer += size;
6272 					}
6273 					else
6274 					{
6275 						// Align the offset to 4 bytes boundary
6276 						if( asPWORD(buffer) & 0x3 )
6277 							buffer += 4 - (asPWORD(buffer) & 0x3);
6278 
6279 						// Call the release behaviour
6280 						void *ptr = *(void**)buffer;
6281 						if( ptr )
6282 							ReleaseScriptObject(ptr, ti);
6283 						buffer += AS_PTR_SIZE*4;
6284 					}
6285 				}
6286 				else
6287 				{
6288 					asUINT size = dt.GetSizeInMemoryBytes();
6289 
6290 					// Align the offset to 4 bytes boundary
6291 					if( size >= 4 && (asPWORD(buffer) & 0x3) )
6292 						buffer += 4 - (asPWORD(buffer) & 0x3);
6293 
6294 					// Advance the buffer
6295 					buffer += size;
6296 				}
6297 			}
6298 		}
6299 		else if( node->type == asLPT_START )
6300 		{
6301 			// If we're not in a repeat iteration, then only 1 value should be destroyed
6302 			if( count <= 0 )
6303 				count = 1;
6304 
6305 			while( count-- )
6306 			{
6307 				asSListPatternNode *subList = node;
6308 				DestroySubList(buffer, subList);
6309 
6310 				asASSERT( subList->type == asLPT_END );
6311 
6312 				if( count == 0 )
6313 					node = subList;
6314 			}
6315 		}
6316 		else if( node->type == asLPT_END )
6317 		{
6318 			return;
6319 		}
6320 		else
6321 		{
6322 			asASSERT( false );
6323 		}
6324 
6325 		node = node->next;
6326 	}
6327 }
6328 
6329 // internal
GetParentNameSpace(asSNameSpace * ns) const6330 asSNameSpace *asCScriptEngine::GetParentNameSpace(asSNameSpace *ns) const
6331 {
6332 	if( ns == 0 ) return 0;
6333 	if( ns == nameSpaces[0] ) return 0;
6334 
6335 	asCString scope = ns->name;
6336 	int pos = scope.FindLast("::");
6337 	if( pos >= 0 )
6338 	{
6339 		scope = scope.SubString(0, pos);
6340 		return FindNameSpace(scope.AddressOf());
6341 	}
6342 
6343 	return nameSpaces[0];
6344 }
6345 
6346 END_AS_NAMESPACE
6347 
6348