//----------------------------------------------------------------// int MOAILuaObject::_gc ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* self = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); self->mCollected = true; if ( MOAILuaRuntime::IsValid ()) { if ( self->mFinalizer ) { self->mFinalizer.PushRef ( state ); if ( state.IsType ( -1, LUA_TFUNCTION )) { state.DebugCall ( 0, 0 ); } else if ( state.IsType ( -1, LUA_TSTRING )) { printf ( "%s\n", state.GetValue < cc8* >( -1, "" )); } else { state.Pop ( 1 ); } self->mFinalizer.Clear (); } if ( MOAILuaRuntime::Get ().mReportGC ) { printf ( "GC %s <%p>\n", self->TypeName (), self ); } } if ( self->GetRefCount () == 0 ) { delete ( self ); } return 0; }
//----------------------------------------------------------------// int MOAILuaObject::_tostring ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* data = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); if ( data ) { STLString str; lua_getfield ( state, 1, "getClassName" ); if ( state.IsType ( -1, LUA_TFUNCTION )) { lua_pushvalue ( state, 1 ); state.DebugCall ( 1, 1 ); cc8* classname = state.GetValue < cc8* >( -1, "" ); str.write ( "%p <%s>", data, classname ); state.Push ( str ); return 1; } str.write ( "%p <%s>", data, data->TypeName ()); state.Push ( str ); return 1; } return 0; }
//----------------------------------------------------------------// int MOAILuaObject::_getClassName ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* object = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); if ( object ) { lua_pushstring ( L, object->TypeName ()); return 1; } return 0; }
//----------------------------------------------------------------// int MOAILuaObject::_getClass ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* object = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); if ( object ) { object->PushLuaClassTable ( state ); return 1; } return 0; }
//----------------------------------------------------------------// int MOAILuaObject::_tostring ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* data = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); if ( data ) { STLString str; str.write ( "0x%p <%s>", data, data->TypeName ()); // TODO: 64-bit state.Push ( str ); return 1; } return 0; }
//----------------------------------------------------------------// int MOAILuaObject::_gc ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* data = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); bool cleanup = ( data->GetRefCount () == 0 ); // ready to cleanup if no references // in any event, let's get rid of the userdata and lua refs we know about data->ClearLocal ( data->mContain ); data->mUserdata.Clear (); data->mMemberTable.Clear (); // check to see if gc is being invoked during finalization if ( MOAILuaRuntime::IsValid ()) { MOAILuaRuntime::Get ().ClearObjectStackTrace ( data ); } // delete if no references if ( cleanup ) { delete data; } return 0; }
//----------------------------------------------------------------// int MOAILuaObject::_index ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* data = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); if ( data ) { //AJV for debugging //__android_log_print(ANDROID_LOG_INFO, "MoaiLog", "0x%p <%s>", data, data->TypeName ()); } // push the instance table lua_getmetatable ( L, 1 ); // push the member table lua_pushstring ( L, LUA_MEMBER_TABLE_NAME ); lua_rawget ( L, -2 ); // try to get the value lua_pushvalue ( L, 2 ); lua_gettable ( L, -2 ); // if nil... if ( lua_isnil ( L, -1 )) { // pop the nil and the member table lua_pop ( L, 2 ); // get the instance table's metatable (the interface table) lua_getmetatable ( L, -1 ); // and try to get the value from the interface table directly lua_pushvalue ( L, 2 ); lua_rawget ( L, -2 ); } return 1; }
//----------------------------------------------------------------// int MOAILuaClass::_extendSingleton ( lua_State* L ) { MOAILuaState state ( L ); // upvalues: // 1: singleton userdata // 2: class table // set the userdata MOAILuaObject* luaData = ( MOAILuaObject* )state.GetPtrUserData ( lua_upvalueindex ( 1 )); state.PushPtrUserData ( luaData ); // clone the class table state.CloneTable ( lua_upvalueindex ( 2 )); lua_pushvalue ( state, -1 ); lua_setfield ( state, -2, "__index" ); lua_pushvalue ( state, -1 ); lua_setfield ( state, -2, "__newindex" ); // add getClassName to class table lua_pushvalue ( L, 1 ); lua_pushcclosure ( L, _getUpvalue, 1 ); lua_setfield ( L, -2, "getClassName" ); // copy the extended userdata lua_pushvalue ( L, -2 ); // copy the extended table lua_pushvalue ( L, -2 ); // push the 'extend' method with the singleton userdata and extended class table upvalues lua_pushcclosure ( L, _extendSingleton, 2 ); // set the extended 'extend' method... lua_setfield ( L, -2, "extend" ); // stack: // -1: extended class table // -2: extended userdata // call the extender if ( state.IsType ( 2, LUA_TFUNCTION )) { lua_pushvalue ( L, 2 ); lua_pushvalue ( L, -2 ); lua_pushvalue ( L, lua_upvalueindex ( 2 )); state.DebugCall ( 2, 0 ); } // stack: // -1: extended class table // -2: extended userdata // set the table as a metatable on the userdata lua_setmetatable ( L, -2 ); // and we're done cc8* classname = state.GetValue < cc8* >( 1, "" ); lua_setglobal ( state, classname ); return 0; }
//----------------------------------------------------------------// // This beast will walk through all tables and functions accessible in the // current lua state and print a reference line for each one found to help // track who is pointing to it. void MOAILuaRuntime::FindAndPrintLuaRefs ( int idx, cc8* prefix, FILE *f, const LeakPtrList& objects ) { lua_State* L = this->mMainState; // Convert to absolute index if ( idx < 0 ) { idx = lua_gettop(L) + idx + 1; } // Check if the item at the top of the stack has been traversed yet. lua_pushvalue ( L, -1 ); lua_gettable ( L, idx ); if( lua_type ( L, -1 ) != LUA_TNIL ) { // It has, let's bail. lua_pop ( L, 1 ); // Clean our 'true' return; } lua_pop(L, 1); // Remove the nil int tt = lua_type ( L, -1 ); if( tt == LUA_TTABLE ) { // printf("finding refs in: %s\n", prefix); // It hasn't been visited, so mark it in our traversal set lua_pushvalue ( L, -1 ); // Push table as key lua_pushboolean ( L, true ); lua_settable ( L, idx ); lua_pushnil ( L ); // first key while ( lua_next ( L, -2 ) != 0 ) { // use the 'key' (at index -2) and 'value' (at index -1) STLString key; if ( lua_type ( L, -2) == LUA_TSTRING ) { if ( MOAILuaRuntime::IsLuaIdentifier ( lua_tostring ( L, -2 ))) { key.write ( "%s.%s", prefix, lua_tostring ( L, -2 )); } else { // TODO: escape '\"' key.write ( "%s[\"%s\"]", prefix, lua_tostring ( L, -2 )); } } else { // stringify key lua_getglobal ( L, "tostring" ); lua_pushvalue ( L, -3 ); lua_call ( L, 1, 1 ); key.write ( "%s[%s]", prefix, lua_tostring ( L, -1 )); // Pop stringified key lua_pop ( L, 1 ); } this->FindAndPrintLuaRefs ( idx, key.c_str (), f, objects ); // removes 'value'; keeps 'key' for next iteration lua_pop ( L, 1 ); } // Check its metatable (if it has one) if ( lua_getmetatable ( L, -1 )) { STLString key; key.write ( "%s~mt", prefix ); this->FindAndPrintLuaRefs ( idx, key.c_str(), f, objects ); lua_pop ( L, 1 ); // Pop metatable } } else if ( tt == LUA_TFUNCTION ) { // printf("finding refs in: %s\n", prefix); // It hasn't been visited, so mark it in our tarversal set lua_pushvalue ( L, -1 ); // Push table as key lua_pushboolean ( L, true ); lua_settable ( L, idx ); const char *upname; for ( int i = 1; ( upname = lua_getupvalue ( L, -1, i )) != NULL; ++i ) { STLString key; key.write ( "%s(%s)", prefix, upname ); this->FindAndPrintLuaRefs ( idx, key.c_str(), f, objects ); // Pop the upvalue lua_pop ( L, 1 ); } } else if ( tt == LUA_TUSERDATA ) { // It hasn't been visited, so mark it in our traversal set lua_pushvalue ( L, -1 ); // Push table as key lua_pushboolean ( L, true ); lua_settable ( L, idx ); MOAILuaState state ( L ); void *ud = state.GetPtrUserData ( -1 ); for ( LeakPtrList::const_iterator i = objects.begin (); i != objects.end (); ++i ) { if( *i == ud ) { fprintf ( f, "\tLua Ref: %s = %s <%p>\n", prefix, ( *i )->TypeName (), ud ); // if ( strcmp((*i)->TypeName(), "MOAICoroutine") == 0 ) { // MOAICoroutine *t = (MOAICoroutine*)ud; // } } } // Check its metatable (if it has one) if ( lua_getmetatable ( L, -1 )) { STLString key; key.write ( "%s~mt", prefix ); this->FindAndPrintLuaRefs ( idx, key.c_str (), f, objects ); lua_pop ( L, 1 ); // Pop metatable } } }