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