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*>(¶m1));
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*)¶m1);
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*)¶m);
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*)¶m);
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*)¶ms);
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