/* _____ __ ___ __ ____ _ __ / ___/__ ___ _ ___ / |/ /__ ___ / /_____ __ __/ __/_______(_)__ / /_ / (_ / _ `/ ' \/ -_) /|_/ / _ \/ _ \/ '_/ -_) // /\ \/ __/ __/ / _ \/ __/ \___/\_,_/_/_/_/\__/_/ /_/\___/_//_/_/\_\\__/\_, /___/\__/_/ /_/ .__/\__/ /___/ /_/ See Copyright Notice in gmMachine.h */ #include "gmConfig.h" #include "gmFunctionObject.h" #include "gmMachine.h" gmFunctionObject::gmFunctionObject() { m_cFunction = NULL; m_cUserData = NULL; m_debugInfo = NULL; m_byteCode = NULL; m_byteCodeLength = 0; m_maxStackSize = 1; // return value m_numLocals = 0; m_numParams = 0; m_numParamsLocals = 0; m_numReferences = 0; m_references = NULL; } void gmFunctionObject::Destruct(gmMachine * a_machine) { if(m_references) { a_machine->Sys_Free(m_references); m_references = NULL; } if(m_byteCode) { a_machine->Sys_Free(m_byteCode); m_byteCode = NULL; } if(m_debugInfo) { if(m_debugInfo->m_debugName) { a_machine->Sys_Free(m_debugInfo->m_debugName); } if(m_debugInfo->m_lineInfo) { a_machine->Sys_Free(m_debugInfo->m_lineInfo); } if(m_debugInfo->m_symbols) { int i; for(i = 0; i < m_numParamsLocals; ++i) { a_machine->Sys_Free(m_debugInfo->m_symbols[i]); } a_machine->Sys_Free(m_debugInfo->m_symbols); } a_machine->Sys_Free(m_debugInfo); m_debugInfo = NULL; } #if GM_USE_INCGC a_machine->DestructDeleteObject(this); #endif //GM_USE_INCGC } #if GM_USE_INCGC bool gmFunctionObject::Trace(gmMachine * a_machine, gmGarbageCollector* a_gc, const int a_workLeftToGo, int& a_workDone) { int i; for(i = 0; i < m_numReferences; ++i) { gmObject * object = a_machine->GetObject(m_references[i]); a_gc->GetNextObject(object); ++a_workDone; } ++a_workDone; return true; } #else //GM_USE_INCGC void gmFunctionObject::Mark(gmMachine * a_machine, gmuint32 a_mark) { if(m_mark != GM_MARK_PERSIST) m_mark = a_mark; int i; for(i = 0; i < m_numReferences; ++i) { gmObject * object = a_machine->GetObject(m_references[i]); if(object->NeedsMark(a_mark)) object->Mark(a_machine, a_mark); } } #endif //GM_USE_INCGC bool gmFunctionObject::Init(gmMachine * a_machine, bool a_debug, gmFunctionInfo &a_info, gmuint32 a_sourceId) { // byte code if(a_info.m_byteCodeLength) { m_byteCode = (gmuint8 *) a_machine->Sys_Alloc(a_info.m_byteCodeLength); memcpy(m_byteCode, a_info.m_byteCode, a_info.m_byteCodeLength); m_byteCodeLength = a_info.m_byteCodeLength; } else { m_byteCode = NULL; m_byteCodeLength = 0; } // stack info m_maxStackSize = a_info.m_maxStackSize; m_numLocals = a_info.m_numLocals; m_numParams = a_info.m_numParams; m_numParamsLocals = a_info.m_numParams + a_info.m_numLocals; // references m_numReferences = 0; m_references = NULL; if(m_byteCode) { // find the objects this function references by iterating over the byte code and collecting them. // we could perform this step in the compilation phase if we don't want to iterate over the byte code. gmptr * references = (gmptr *) GM_NEW( char[a_info.m_byteCodeLength] ); union { const gmuint8 * instruction; const gmuint32 * instruction32; }; instruction = (const gmuint8 *) m_byteCode; const gmuint8 * end = instruction + m_byteCodeLength; for(;instruction < end;) { switch(*(instruction32++)) { case BC_GETDOT : case BC_SETDOT : case BC_BRA : case BC_BRZ : case BC_BRNZ : case BC_BRZK : case BC_BRNZK : case BC_FOREACH : case BC_GETGLOBAL : case BC_SETGLOBAL : case BC_GETTHIS : case BC_SETTHIS : instruction += sizeof(gmptr); break; case BC_PUSHINT : instruction += sizeof(gmint); break; case BC_PUSHFP : instruction += sizeof(gmfloat); break; case BC_CALL : case BC_GETLOCAL : case BC_SETLOCAL : instruction += sizeof(gmuint32); break; case BC_PUSHSTR : case BC_PUSHFN : { // if the reference does not already exist, add it. gmptr reference = *((gmptr *) instruction); instruction += sizeof(gmptr); int i; for(i = 0; i < m_numReferences; ++i) { if(references[i] == reference) break; } if(i == m_numReferences) references[m_numReferences++] = reference; break; } default : break; } } if(m_numReferences > 0) { m_references = (gmptr *) a_machine->Sys_Alloc(sizeof(gmptr) * m_numReferences); memcpy(m_references, references, sizeof(gmptr) * m_numReferences); } delete [] (char*) references; } // debug info m_debugInfo = NULL; if(a_debug) { m_debugInfo = (gmFunctionObjectDebugInfo *) a_machine->Sys_Alloc(sizeof(gmFunctionObjectDebugInfo)); memset(m_debugInfo, 0, sizeof(gmFunctionObjectDebugInfo)); // source code id m_debugInfo->m_sourceId = a_sourceId; // debug name if(a_info.m_debugName) { int len = (int)strlen(a_info.m_debugName) + 1; m_debugInfo->m_debugName = (char *) a_machine->Sys_Alloc(len); memcpy(m_debugInfo->m_debugName, a_info.m_debugName, len); } // symbols if(a_info.m_symbols) { m_debugInfo->m_symbols = (char **) a_machine->Sys_Alloc(sizeof(char *) * m_numParamsLocals); int i; for(i = 0; i < m_numParamsLocals; ++i) { int len = (int)strlen(a_info.m_symbols[i]) + 1; m_debugInfo->m_symbols[i] = (char *) a_machine->Sys_Alloc(len); memcpy(m_debugInfo->m_symbols[i], a_info.m_symbols[i], len); } } // line number debugging. if(a_info.m_lineInfo) { // alloc and copy m_debugInfo->m_lineInfo = (gmLineInfo *) a_machine->Sys_Alloc(sizeof(gmLineInfo) * a_info.m_lineInfoCount); memcpy(m_debugInfo->m_lineInfo, a_info.m_lineInfo, sizeof(gmLineInfo) * a_info.m_lineInfoCount); m_debugInfo->m_lineInfoCount = a_info.m_lineInfoCount; } } return true; } int gmFunctionObject::GetLine(int a_address) const { if(m_debugInfo && m_debugInfo->m_lineInfo) { int i; for(i = 0; i < m_debugInfo->m_lineInfoCount; ++i) { if(a_address < m_debugInfo->m_lineInfo[i].m_address) { // return entry before if(i > 0) --i; return m_debugInfo->m_lineInfo[i].m_lineNumber; } } return m_debugInfo->m_lineInfo[i - 1].m_lineNumber; } return 0; } const void * gmFunctionObject::GetInstructionAtLine(int a_line) const { if(m_debugInfo && m_debugInfo->m_lineInfo && m_byteCode) { // serach for the first address using this line. int i; for(i = 0; i < m_debugInfo->m_lineInfoCount; ++i) { if(m_debugInfo->m_lineInfo[i].m_lineNumber == a_line) { return (void *) ((char *) m_byteCode + m_debugInfo->m_lineInfo[i].m_address); } } } return NULL; } gmuint32 gmFunctionObject::GetSourceId() const { if(m_debugInfo) { return m_debugInfo->m_sourceId; } return 0; }