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