• 追加された行はこの色です。
  • 削除された行はこの色です。
* フォーラムメモ [#fbc90ba3]
#contents

** 自分自身のプロパティアクセサを呼び出すとフリーズ [#x7fb62c5]
- ライブラリバージョン : r564

:コールトレース|
#code(){{
	GameProject.exe!asCArray<asCScriptFunction *>::operator[](unsigned int index=0)  Line 147 + 0x6 Bytes	C++
 	GameProject.exe!asCContext::CallInterfaceMethod(asCScriptFunction * func=0x0a8e1058)  Line 1254 + 0x15 Bytes	C++
 	GameProject.exe!asCContext::ExecuteNext()  Line 2790	C++
 	GameProject.exe!asCContext::Execute()  Line 1004 + 0x8 Bytes	C++
 	GameProject.exe!base::ags::ContextHandle::execute()  Line 104 + 0x23 Bytes	C++
 	GameProject.exe!app::scene::SceneASTest::onSceneStart()  Line 67	C++
 	GameProject.exe!app::Application::beginSceneProcess()  Line 191 + 0x23 Bytes	C++
 	GameProject.exe!app::Application::execute()  Line 99 + 0xc Bytes	C++
 	GameProject.exe!`anonymous namespace'::t_executeApplication()  Line 50 + 0xb Bytes	C++
 	GameProject.exe!app::EntryPoint::run()  Line 73	C++
 	GameProject.exe!wmain(int __formal=1, int __formal=1)  Line 16	C++
 	GameProject.exe!__tmainCRTStartup()  Line 594 + 0x19 Bytes	C
 	GameProject.exe!wmainCRTStartup()  Line 414	C
}}

:ASコード|
#code(c,){{
class Vector3
{
    float x;
    float y;
    float z;
};

class Hoge
{
    const Vector3 get_pos()const
    {
        return mPos;
    }
    const Vector3 foo()const
    {
        return pos;
    }

    Vector3 mPos;
};


void main()
{
    Hoge h;
    const Vector3 vec = h.foo();
}
}}


#hr






#code(c,){{
class Vector3
{
    float x;
    float y;
    float z;
};

class Hoge
{
    const Vector3 get_pos() { return mPos; }
    const Vector3 foo() { return pos;  }
    const Vector3 zoo() { return get_pos(); }
    Vector3 mPos;
};


void main()
{
    Hoge h;
    Vector3 vec;
    vec = h.zoo(); // ok
    vec = h.foo(); // runtime exception
}

}}

__Hoge_foo.txt
#code(){{
Temps: 1

    0   0 *    PUSH     1
    1   1 *    PshV4    v0
    2   2 *    CALLSYS  17           (void _builtin_object_::_beh_4_())
- 11,27 -
    4   1 *    SUSPEND
    5   1 *    PSF      v0
    6   2 *    CALLINTF 86           (const Vector3 Hoge::get_pos())
    8   1 *    STOREOBJ v1
    9   1 *    LOADOBJ  v1
   10   1 * 0:
   10   1 *    FREE     v0, 11276368
   12   0 *    RET      1
}}

__Hoge_zoo.txt
#code(,){{
Temps: 1

    0   0 *    PUSH     1
    1   1 *    PshV4    v0
    2   2 *    CALLSYS  17           (void _builtin_object_::_beh_4_())
- 12,27 -
    4   1 *    SUSPEND
    5   1 *    PshV4    v0
    6   2 *    CALLINTF 86           (const Vector3 Hoge::get_pos())
    8   1 *    STOREOBJ v1
    9   1 *    LOADOBJ  v1
   10   1 * 0:
   10   1 *    FREE     v0, 11276368
   12   0 *    RET      1
}}
** opAssignを定義するとコンパイル時にAssert [#c92f9374]
- ライブラリバージョン : 2.18.1

:エラーメッセージ|
 Assertion failed: tempVariables.GetLength() == 0, file ..\..\source\as_compiler.cpp, line 643

:コールトレース|
#code(){{
 	msvcr80d.dll!_wassert(const wchar_t * expr=0x007013cc, const wchar_t * filename=0x00701174, unsigned int lineno=643)  行 212	C
 	GameProject.exe!asCCompiler::CompileStatementBlock(asCScriptNode * block=0x0a8c1640, bool ownVariableScope=false, bool * hasReturn=0x0012b2e3, asCByteCode * bc=0x0012b2a0)  行 643 + 0x29 バイト	C++
 	GameProject.exe!asCCompiler::CompileFunction(asCBuilder * builder=0x0a8e2b08, asCScriptCode * script=0x0a8e2800, asCScriptNode * func=0x0a8e2878, asCScriptFunction * outFunc=0x0a8e3c10)  行 324	C++
 	GameProject.exe!asCBuilder::CompileFunctions()  行 524	C++
 	GameProject.exe!asCBuilder::Build()  行 184	C++
}}

:ASコード|
#code(c,){{
class Hoge
{
    int mValue;
    
    Hoge()
    {
        mValue = 0;
    }
    
    Hoge@ opAssign(const Hoge &in aObj)
    {
        mValue = aObj.mValue;
        return @this;
    }
};

void main()
{
    Hoge a = Hoge();
}
}}

** デストラクタが呼ばれない [#v821eb8e]
#code(c,){{
//-----------------------------------------------------------
// script code

class ObjType
{
};

class HaveObj
{
    HaveObj()
    {
        Print( "HaveObj::ctor\n" );
    }
    ~HaveObj()
    {
        Print( "HaveObj::dtor\n" );
    }
    ObjType o;
};

class HaveHandle
{
    HaveHandle()
    {
        Print( "HaveHandle::ctor\n" );
    }
    ~HaveHandle()
    {
        Print( "HaveHandle::dtor\n" );
    }
    ObjType@ o;
};

void testCase1()
{
    Print( "testCase1 start\n" );
    {
        HaveObj o;
    }// call o.~HaveObj();
    {
        HaveHandle o;
    }// not call o.~HaveHandle();
    
    Print( "testCase1 end\n" );
} 

void main()
{
    testCase1();
}


//-----------------------------------------------------------


//-----------------------------------------------------------
// output

testCase1 start
HaveObj::ctor
HaveObj::dtor
HaveHandle::ctor
testCase1 end


//-----------------------------------------------------------
}}


回答
As with any language with automatic memory management, it can be hard to predict when the destructor is called.

In your case you have created a situation where the ordinary reference counting is not enough to control the life time of the objects, so the garbage collector is notified to keep a watch on the object instance. However, the garbage collector is not invoked automatically by the script engine (so that the application will have full control of when that is done). This means that unless you manually call the GC, the object will only be destroyed when you release the script engine.


** 配列を使った循環参照状態を記述するとメモリリーク [#sf6cca03]
- ライブラリバージョン : r575

:C++コード|
#code(c,){{

//-----------------------------------------------------------
// C++ source code
namespace
{
    // alloc counter
    int t_allocCount = 0;
    // alloc function
    void* t_alloc( const size_t aSize )
    {
        ++t_allocCount;
        return std::malloc( aSize );
    }
    // free cuntion
    void t_free( void* aPtr )
    {
        std::free( aPtr );
        --t_allocCount;
    }
}

int main(int argc, char **argv)
{
    // set allocator
    asSetGlobalMemoryFunctions( t_alloc , t_free );

    // Create the script engine
    asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

    // Compile
    asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
    mod->AddScriptSection("script", 
        "class Hoge"
        "{"
        "    Hoge(){}"
        "    Hoge(HogeManager&){}"
        "};"
        "class HogeManager"
        "{"
        "    Hoge[] hoges;"
        "};"
        , 0);
    mod->Build();

    // Release engine
    engine->Release();

    // check
    assert( t_allocCount == 0 );
}

}}

:対処|
#code(c,){{
// as_scriptengine.cpp L490付近

	GarbageCollect(asGC_FULL_CYCLE);
	FreeUnusedGlobalProperties();
	ClearUnusedTypes();

        // もう一度,GCを走らせる
	GarbageCollect(asGC_FULL_CYCLE);
}}
** enumの文字列かぶりで無限ループ [#vf385fad]
- ライブラリバージョン : r575

:スクリプトコード|
#code(c,){{
enum Kind
{
    Kind_A
    , Kind_A // This code gives name conflict error and infinite loop.
};

}}

** asGC_ONE_STEPは想定した動きになっているのか [#aec6b6ad]
- ライブラリバージョン : r586

:code|
#code(c,){{
void main()
{
    // Create the script engine
    asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
 
    // Register Function
    RegisterScriptString(engine);
    engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString_Generic), asCALL_GENERIC);

    // Compile
    asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
    mod->AddScriptSection("script", 
        "class Obj{};"
        "class Hoge"
        "{"
        "    Hoge(){ Print(\"ctor\\n\"); }"
        "    ~Hoge(){ Print(\"dtor\\n\"); }"
        "    Obj@ obj;"
        "};"
        "void main()"
        "{"
        "    Hoge hoge;"
        "};"
        , 0);
    mod->Build();
 
    // Context Create
    asIScriptContext *ctx = engine->CreateContext();

    // Loop
    while ( true )
    {
        // Execute
        printf("----- execute\n");
        ctx->Prepare(mod->GetFunctionIdByDecl("void main()"));
        ctx->Execute();

        // GC
        const int GC_STEP_COUNT_PER_FRAME = 10000;
        for ( int i = 0; i < GC_STEP_COUNT_PER_FRAME; ++i )
        {
            engine->GarbageCollect(asGC_ONE_STEP);
        }
        
        // Check status
        {
            asUINT currentSize = asUINT();
            asUINT totalDestroyed = asUINT();
            asUINT totalDetected = asUINT();
            engine->GetGCStatistics(&currentSize , &totalDestroyed , &totalDetected );
            printf("(%lu,%lu,%lu)\n" , currentSize , totalDestroyed , totalDetected );
        }

        // Wait to input key
        while(!getch()){}
    }

    // Release 
    ctx->Release();
    engine->Release();
}
}}

:output|
#code(){{
----- execute
ctor
dtor
(8,1,0)
----- execute
ctor
(9,1,0)
----- execute
ctor
(10,1,0)
----- execute
ctor
(11,1,0)
----- execute
ctor
(12,1,0)
----- execute
ctor
(13,1,0)
----- execute
ctor
(14,1,0)

}}

** as_restore.cppの修正箇所 [#h2cd7e5f]
:revision|
r589

:Not work on Big Endian Environment(L1398,L1410,L1451,L1473,L1488)|
#code(c,){{
// src
asWORD w = (asWORD)(tmp[0]>>16);
// fixed
asWORD w = *(((asWORD*)tmp)+1);
}}
  
:Not work on Big Endian Environment(L1587,L1600,L1637,L1661,L1678,L1727)|
#code(c,){{
// src
*bc += asDWORD(w)<<16;
// fixed
*(((asWORD*)bc)+1) = w;
}}

:miss spell(L1497)|
#code(c,){{
// src
asDWORD dw = tmp[2];
WRITE_NUM(w);
// fixed
asDWORD dw = tmp[2];
WRITE_NUM(dw);
}}

:miss spell(L1642,L1666,L1683)|
#code(c,){{
// src
*(WORD*)bc = w;
// fixed
*(asWORD*)bc = w;
}}

:miss spell(L1646)|
#code(c,){{
// src
*(((WORD*)bc)+1) = w;
// fixed
*(((asWORD*)bc)+1) = w;
}}

** テンプレートのメソッドを呼ぶスクリプトコードをSaveByteCode&LoadByteCodeすると落ちる [#v4cad29a]
:リビジョン|
r589

:script code|
#code(c,){{
void main()
{
    array< int > intArray = {0,1,2};
    uint tmp = intArray.length(); // program stoped while module->LoadByteCode() Processing
};
}}

:freeze code pos|
#code(c,){{
// as_restore.cpp L1937
else if( c == asBC_CALL ||
		 c == asBC_CALLINTF ||
		 c == asBC_CALLSYS )
{
	// Translate the index to the func id
	int *fid = (int*)&bc[n+1];
	*fid = FindFunction(*fid)->id; // null pointer access
}
}}

:fix patch|
*** fix patch [#mba16a13]
:as_restore.cpp|
#code(c,){{
void asCRestore::WriteObjectType(asCObjectType* ot) 
{
	char ch;

	// Only write the object type name
	if( ot )
	{
		// Check for template instances/specializations
		if( ot->templateSubType.GetTokenType() != ttUnrecognizedToken &&
			ot != engine->defaultArrayObjectType )
		{
			ch = 'a';
			WRITE_NUM(ch);

			if( ot->templateSubType.IsObject() )
			{
				ch = 's';
				WRITE_NUM(ch);
				WriteObjectType(ot->templateSubType.GetObjectType());

				if( ot->templateSubType.IsObjectHandle() )
					ch = 'h';
				else
					ch = 'o';
                
				WRITE_NUM(ch);
#if 1
                ch = 'o';
                WRITE_NUM(ch);
			    WriteString(&ot->name);
#endif
			}
			else
			{
				ch = 't';
				WRITE_NUM(ch);
				eTokenType t = ot->templateSubType.GetTokenType();
				WRITE_NUM(t);
			}
		}
		else if( ot->flags & asOBJ_TEMPLATE_SUBTYPE )
		{
			ch = 's';
			WRITE_NUM(ch);
			WriteString(&ot->name);
		}
		else
		{
			ch = 'o';
			WRITE_NUM(ch);
			WriteString(&ot->name);
		}
	}
	else
	{
		ch = '\0';
		WRITE_NUM(ch);
	}
}


asCObjectType* asCRestore::ReadObjectType() 
{
	asCObjectType *ot;
	char ch;
	READ_NUM(ch);
	if( ch == 'a' )
	{
		READ_NUM(ch);
		if( ch == 's' )
		{
#if 0
			ot = ReadObjectType();
			asCDataType dt = asCDataType::CreateObject(ot, false);

			READ_NUM(ch);
			if( ch == 'h' )
				dt.MakeHandle(true);

			dt.MakeArray(engine);
			ot = dt.GetObjectType();
			
			asASSERT(ot);
#else
            asCObjectType* subOT = ReadObjectType();
            asCDataType subDT = asCDataType::CreateObject(subOT, false);
            asCDataType dt = asCDataType::CreateObject(subOT, false);
            READ_NUM(ch);
            if ( ch == 'h' )
            {
                subDT.MakeHandle(true);
                dt.MakeHandle(true);
            }
            else if ( ch == 'o' )
            {
            }
            else
            {
                assert(false);
            }

            ot = ReadObjectType();
            ot->templateSubType = subDT;
            subOT->AddRef();
            asCObjectType* tmplOT = ReadObjectType();
			dt.MakeTemplateInstanceType(engine,tmplOT);
            ot = dt.GetObjectType();
#endif
		}
		else
		{
			eTokenType tokenType;
			READ_NUM(tokenType);
			asCDataType dt = asCDataType::CreatePrimitive(tokenType, false);
			dt.MakeArray(engine);
			ot = dt.GetObjectType();
			
			asASSERT(ot);
		}
	}
	else if( ch == 's' )
	{
		// Read the name of the template subtype
		asCString typeName;
		ReadString(&typeName);

		// Find the template subtype
		for( asUINT n = 0; n < engine->templateSubTypes.GetLength(); n++ )
		{
			if( engine->templateSubTypes[n] && engine->templateSubTypes[n]->name == typeName )
			{
				ot = engine->templateSubTypes[n];
				break;
			}
		}

		// TODO: Should give a friendly error in case the template type isn't found
		asASSERT(ot);
	}
	else if( ch == 'o' )
	{
		// Read the object type name
		asCString typeName;
		ReadString(&typeName);

		if( typeName.GetLength() && typeName != "_builtin_object_" && typeName != "_builtin_function_" )
		{
			// Find the object type
			ot = module->GetObjectType(typeName.AddressOf());
			if( !ot )
				ot = engine->GetObjectType(typeName.AddressOf());
			
			asASSERT(ot);
		}
		else if( typeName == "_builtin_object_" )
		{
			ot = &engine->scriptTypeBehaviours;
		}
		else if( typeName == "_builtin_function_" )
		{
			ot = &engine->functionBehaviours;
		}
		else
			assert( false );
	}
	else
	{
		// No object type
		assert( ch == '\0' );
		ot = 0;
	}

	return ot;
}
}}

:as_datatype.h|
#code(c,){{
	int MakeHandle(bool b, bool acceptHandleForScope = false);
	int MakeArray(asCScriptEngine *engine);
	int MakeReference(bool b);
	int MakeReadOnly(bool b);
	int MakeHandleToConst(bool b);
#if 1
    int MakeTemplateInstanceType(asCScriptEngine *engine,asCObjectType*);
#endif
}}

:as_datatype.cpp|
#code(c,){{
#if 1
int asCDataType::MakeTemplateInstanceType(asCScriptEngine *engine,asCObjectType* templateOT)
{
	bool tmpIsReadOnly = isReadOnly;
	isReadOnly = false;
	asCObjectType *at = engine->GetTemplateInstanceType(templateOT, *this);
	isReadOnly = tmpIsReadOnly;

	isObjectHandle = false;
	isConstHandle = false;
	
	objectType = at;
	tokenType = ttIdentifier;

	return 0;
}
#endif
}}

** as_restore.cppの修正箇所 その2 [#c5750753]
r594
''Not work on Big Endian Environment(L1580,L1615,L1624,L1699,L1710)''
#code(c,){{
// src
*bc++ = b;
// fixed
*(asBYTE*)(bc) = b;
++bc;
}}

''Not work on Big Endian Environment(L1600.L1637,L1661,L1678,L1727)''
#code(c,){{
// src
*bc = b;
// fixed
*(asBYTE*)(bc) = b;
}}

** load byte code failed [#p4787cf6]
:Revision|
r595

Assertion failed at loading byte code.

#code(c,){{
// Succeed case
class Hoge {};
class HogeManager
{
    array< Hoge >@ hogeArray;
};
}}

#code(c,)){{
// Failed case
class HogeManager
{
    array< Hoge >@ hogeArray;
};
class Hoge {};
}}

:Message|
 Assertion failed: ot, file ..\..\source\as_restore.cpp, line 1244


** load byte code failed  part2 [#z3ed8e59]
:Revision|
r609

Assertion failed at loading byte code.

#code(c,)){{
// Failed case
class HogeManager
{
    HogeManager()
    {
        array< Hoge >@ hogeArray;
    }
};
class Hoge {};
}}

:Message|
 Assertion failed: ot, file ..\..\source\as_restore.cpp, line 1299



** memory leak part2 [#z3ed8e59]
:Revision|
r604

Add 'array' object method
#code(c,){{
// scriptarray.cpp
namespace
{
    void t_hoge(asIScriptGeneric*){}    
}
void RegisterScriptArray_Generic(asIScriptEngine *engine)
{
    ...
    r = engine->RegisterObjectMethod("array<T>", "void hoge(const T&in)" , asFUNCTION(t_hoge), asCALL_GENERIC); assert( r >= 0 );
    
}
}}

main.cpp
#code(c,){{
//-----------------------------------------------------------
// C++ source code
namespace
{
    // alloc counter
    int t_allocCount = 0;
    // alloc function
    void* t_alloc( const size_t aSize )
    {
        ++t_allocCount;
        return std::malloc( aSize );
    }
    // free cuntion
    void t_free( void* aPtr )
    {
        std::free( aPtr );
        --t_allocCount;
    }
}

int main(int argc, char **argv)
{
    // set allocator
    asSetGlobalMemoryFunctions( t_alloc , t_free );

    // Create the script engine
    asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

    // Register array class
    RegisterScriptArray_Generic(engine);

    // Compile
    asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
    mod->AddScriptSection("script", 
        "class Hoge"
        "{"
        "    HogeManager@ hogeManager;"
        "};"
        "class HogeManager"
        "{"
        "    array< Hoge >@ hoges;"
        "};"
        , 0);
    mod->Build();

    // Release engine
    engine->Release();

    // check
    assert( t_allocCount == 0 ); // assertion failed

    return 0;
}
}}

** load byte code failed part3 [#nf6a91f6]
:Revision|
r609

:Script Code|
#code(c,){{
array< ColorKind > COLOR_KIND_TABLE = { ColorKind_Red };
enum ColorKind
{
    ColorKind_Red
};
}}

:Call stack trace|
Maybe null pointer access.
msvc8.exe!asCRestore::TranslateFunction(asCScriptFunction * func=0x003ed990)  Line 2011 + 0x11 Byte	C++
msvc8.exe!asCRestore::Restore()  Line 358	C++
msvc8.exe!asCModule::LoadByteCode(asIBinaryStream * in=0x00ad7018)  Line 1237 + 0xb Byte	C++

** load byte code failed  part4 [#bd445078]
:Revision|
r613

:Script Code|
#code(c,){{
interface IObj {};
class Hoge : IObj {};
void main()
{
    Hoge h;
    IObj@ objHandle = h;
    Hoge@ hogeHandle = cast< Hoge@ >( objHandle );
};
}}

Crash at as_context.cpp L2866.

** build failed [#b9b4e0f1]
:Revision|
r614

:ScriptCode|
#code(c,){{
class Obj {};
class Hoge
{
    const Obj obj()const { return Obj(); }
};
class Foo
{
    Foo()
    {
        Hoge h;
        Obj tmpObj = h.obj(); /* OK */
        mObj = h.obj(); /* Build failed */
    }
    Obj mObj;
};
}}


    ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS