// Loads a single table, returns pointer to table in memory. public static void *LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **ppTable) { int numRows = (int)pThis->tables.numRows[tableID]; int rowLen = tableRowSize[tableID]; int i, row; /*char**/ byte *pDef = tableDefs[tableID]; int defLen = (int)S.strlen(pDef); void * pRet; byte * pSource = (byte *)*ppTable; byte * pDest; uint v = 0; SIZE_T p = 0; // Allocate memory for destination table pRet = Mem.malloc((SIZE_T)(numRows * rowLen)); pDest = (byte *)pRet; // Load table int srcLen = 0; for (row = 0; row < numRows; row++) { byte *pSrcStart = pSource; for (i = 0; i < defLen; i += 2) { byte d = pDef[i]; if (d < MAX_TABLES) { if (pThis->tables.numRows[d] < 0x10000) { // Use 16-bit offset v = GetU16(pSource); pSource += 2; } else { // Use 32-bit offset v = GetU32(pSource); pSource += 4; } v |= (uint)d << 24; } else { switch ((char)d) { case 'c': // 8-bit value v = *(byte *)pSource; pSource++; break; case 's': // 16-bit short v = GetU16(pSource); pSource += 2; break; case 'i': // 32-bit int v = GetU32(pSource); pSource += 4; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': { int ofs = pDef[i] - '0'; /*char*/ byte *pCoding = codedTags[ofs]; int tagBits = codedTagBits[ofs]; byte tag = (byte)(*pSource & ((1 << tagBits) - 1)); int idxIntoTableID = pCoding[tag]; // The actual table index that we're looking for if (idxIntoTableID < 0 || idxIntoTableID > MAX_TABLES) { Sys.Crash("Error: Bad table index: 0x%02x\n", idxIntoTableID); } if (pThis->tables.codedIndex32Bit[ofs] != 0) { // Use 32-bit number v = GetU32(pSource) >> tagBits; pSource += 4; } else { // Use 16-bit number v = GetU16(pSource) >> tagBits; pSource += 2; } v |= (uint)idxIntoTableID << 24; } break; case 'S': // index into string heap if (pThis->index32BitString != 0) { v = GetU32(pSource); pSource += 4; } else { v = GetU16(pSource); pSource += 2; } p = (PTR)(pThis->strings.pStart + v); // NOTE: Quick way to validate metadata loading, check if all strings are valid! if (S.isvalidstr((byte *)p) == 0) { Sys.Crash("Invalid string %s", (PTR)p); } break; case 'G': // index into GUID heap if (pThis->index32BitGUID != 0) { v = GetU32(pSource); pSource += 4; } else { v = GetU16(pSource); pSource += 2; } p = (PTR)(pThis->GUIDs.pGUID1 + ((v - 1) * 16)); break; case 'B': // index into BLOB heap if (pThis->index32BitBlob != 0) { v = GetU32(pSource); pSource += 4; } else { v = GetU16(pSource); pSource += 2; } p = (PTR)(pThis->blobs.pStart + v); break; case '^': // RVA to convert to pointer v = GetU32(pSource); pSource += 4; p = (PTR)RVA.FindData(pRVA, v); break; case 'm': // Pointer to this metadata p = (PTR)pThis; break; case 'l': // Is this the last table entry? v = (row == numRows - 1) ? (uint)1 : (uint)0; break; case 'I': // Original table index v = MetaData.MAKE_TABLE_INDEX((uint)tableID, (uint)(row + 1)); break; case 'x': // Nothing, use 0 v = 0; p = 0; break; default: Sys.Crash("Cannot handle MetaData source definition character '%c' (0x%02X)\n", d, d); break; } } switch ((char)pDef[i + 1]) { case '*': *(SIZE_T *)pDest = p; pDest += sizeof(SIZE_T); break; case 'i': *(uint *)pDest = v; pDest += 4; break; case 's': *(ushort *)pDest = (ushort)v; pDest += 2; break; case 'c': *(byte *)pDest = (byte)v; pDest++; break; case 'x': // Do nothing break; default: Sys.Crash("Cannot handle MetaData destination definition character '%c'\n", pDef[i + 1]); break; } } if (srcLen == 0) { srcLen = (int)(pSource - pSrcStart); } } Sys.log_f(1, "Loaded MetaData table 0x%02X; %d rows %d len\n", tableID, numRows, srcLen); // Update the parameter to the position after this table *ppTable = pSource; // Return new table information return(pRet); }
public static byte *scatprintf(byte *bfr, byte *end, string fmt, params object[] args) { if (bfr == null || fmt == null) { throw new System.NullReferenceException(); } Mem.heapcheck(); int curarg = 0; int i = 0; int fmtLen = fmt.Length; byte *b = bfr; byte *e = end; while (i < fmtLen) { char ch = fmt[i]; if (ch == '%' && i + 1 < fmtLen) { i++; ch = fmt[i]; if (ch == 's') { object sarg = args[curarg]; curarg++; if (sarg == null) { if (b + 4 > e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)'n'; *b++ = (byte)'u'; *b++ = (byte)'l'; *b++ = (byte)'l'; } else if (sarg is string) { string str = (string)sarg; for (int j = 0; j < str.Length; j++) { if (b >= e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)str[j]; } } else if (sarg is PTR) { byte *s = (byte *)((PTR)sarg); if (s == null) { if (b + 4 >= e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)'n'; *b++ = (byte)'u'; *b++ = (byte)'l'; *b++ = (byte)'l'; } else { while (*s != 0) { if (b >= e) { throw new System.IndexOutOfRangeException(); } *b++ = *s++; } } } else { throw new System.ArgumentException(); } } else if (ch == 'x' || ch == 'X' || ch == 'd') { int v; object arg = args[curarg]; if (arg is int) { v = (int)arg; } else if (arg is uint) { v = (int)(uint)arg; } else if (arg is long) { v = (int)(long)arg; } else if (arg is ulong) { v = (int)(ulong)arg; } else { throw new System.ArgumentException(); } curarg++; string vs = (ch == 'x' || ch == 'X' ? v.ToString("X") : v.ToString()); for (int j = 0; j < vs.Length; j++) { if (b >= e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)vs[j]; } } else if (ch == 'l' && i + 2 < fmtLen && fmt[i + 1] == 'l' && (fmt[i + 2] == 'x' || fmt[i + 2] == 'X' || fmt[i + 2] == 'd')) { i += 2; ch = fmt[i]; long lv = System.Convert.ToInt64(args[curarg]); curarg++; string lvs = (ch == 'x' || ch == 'X' ? lv.ToString("X") : lv.ToString()); for (int j = 0; j < lvs.Length; j++) { if (b >= e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)lvs[j]; } } else if (ch == '0' && i + 2 < fmtLen && (fmt[i + 1] >= '0' && fmt[i + 1] <= '9') && (fmt[i + 2] == 'x' || fmt[i + 2] == 'X' || fmt[i + 2] == 'd')) { char l0 = fmt[i + 1]; i += 2; ch = fmt[i]; int v0; object arg = args[curarg]; if (arg is int) { v0 = (int)arg; } else if (arg is uint) { v0 = (int)(uint)arg; } else if (arg is long) { v0 = (int)(long)arg; } else if (arg is ulong) { v0 = (int)(ulong)arg; } else { throw new System.ArgumentException(); } curarg++; string vs0 = (ch == 'x' || ch == 'X' ? v0.ToString("X" + l0) : v0.ToString("D" + l0)); for (int j = 0; j < vs0.Length; j++) { if (b >= e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)vs0[j]; } } else { if (b >= e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)ch; } } else { if (b >= e) { throw new System.IndexOutOfRangeException(); } *b++ = (byte)ch; } i++; } // Null terminator *b = 0; Mem.heapcheck(); return(b); }
static int InternalLoadAndRun(bool tryRun, string[] args) { if (!_isInitialized) { Init(); } /*char**/ byte * pFileName = new S(args[0]); int argc = args.Length; /*char**/ byte **argv = S.buildArray(args); tCLIFile * pCLIFile; int retValue; #if DIAG_TOTAL_TIME ulong startTime; #endif #if DIAG_OPCODE_TIMES Mem.memset(opcodeTimes, 0, sizeof(opcodeTimes)); #endif #if DIAG_OPCODE_USE Mem.memset(opcodeNumUses, 0, sizeof(opcodeNumUses)); #endif pCLIFile = CLIFile.LoadAssembly(pFileName); #if DIAG_TOTAL_TIME startTime = microTime(); #endif if (tryRun) { if (pCLIFile->entryPoint != 0) { retValue = CLIFile.Execute(pCLIFile, argc, argv); } else { Sys.printf("File %s has no entry point, skipping execution\n", (PTR)pFileName); retValue = 0; } } else { retValue = 0; } #if DIAG_TOTAL_TIME printf("Total execution time = %d ms\n", (int)((microTime() - startTime) / 1000)); #endif #if DIAG_GC printf("Total GC time = %d ms\n", (int)(Heap.gcTotalTime / 1000)); #endif #if DIAG_METHOD_CALLS { uint numMethods, i; int howMany = 25; tMetaData *pCorLib; // Report on most-used methods pCorLib = CLIFile_GetMetaDataForAssembly("mscorlib"); numMethods = pCorLib->tables.numRows[MetaDataTable.MD_TABLE_METHODDEF]; printf("\nCorLib method usage:\n"); for (; howMany > 0; howMany--) { tMD_MethodDef *pMethod; uint maxCount = 0, maxIndex = 0; for (i = 1; i <= numMethods; i++) { pMethod = (tMD_MethodDef *)MetaData.GetTableRow(pCorLib, MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_METHODDEF, i)); if (pMethod->callCount > maxCount) { maxCount = pMethod->callCount; maxIndex = i; } } pMethod = (tMD_MethodDef *)MetaData.GetTableRow(pCorLib, MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_METHODDEF, maxIndex)); printf("%d: %s (%d)\n", (int)pMethod->callCount, Sys_GetMethodDesc(pMethod), (int)(pMethod->totalTime / 1000)); pMethod->callCount = 0; } printf("\n"); } { uint numMethods, i; int howMany = 25; tMetaData *pCorLib; // Report on most-used methods pCorLib = CLIFile_GetMetaDataForAssembly("mscorlib"); numMethods = pCorLib->tables.numRows[MetaDataTable.MD_TABLE_METHODDEF]; printf("\nCorLib method execution time:\n"); for (; howMany > 0; howMany--) { tMD_MethodDef *pMethod; ulong maxTime = 0; uint maxIndex = 0; for (i = 1; i <= numMethods; i++) { pMethod = (tMD_MethodDef *)MetaData.GetTableRow(pCorLib, MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_METHODDEF, i)); if (pMethod->totalTime > maxTime) { maxTime = pMethod->totalTime; maxIndex = i; } } pMethod = (tMD_MethodDef *)MetaData.GetTableRow(pCorLib, MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_METHODDEF, maxIndex)); printf("%d: %s (%d)\n", (int)pMethod->callCount, Sys_GetMethodDesc(pMethod), (int)(pMethod->totalTime / 1000)); pMethod->totalTime = 0; } printf("\n"); } #endif #if DIAG_OPCODE_TIMES { int howMany = 25; uint i; printf("\nOpCodes execution time:\n"); for (; howMany > 0; howMany--) { ulong maxTime = 0; uint maxIndex = 0; for (i = 0; i < JitOps.JIT_OPCODE_MAXNUM; i++) { if (opcodeTimes[i] > maxTime) { maxTime = opcodeTimes[i]; maxIndex = i; } } printf("0x%03x: %dms (used %d times) (ave = %d)\n", maxIndex, (int)(maxTime / 1000), (int)opcodeNumUses[maxIndex], (int)(maxTime / opcodeNumUses[maxIndex])); opcodeTimes[maxIndex] = 0; } } #endif #if DIAG_OPCODE_USE { int howMany = 25; uint i, j; printf("\nOpcode use:\n"); for (j = 1; howMany > 0; howMany--, j++) { uint maxUse = 0; uint maxIndex = 0; for (i = 0; i < JitOps.JIT_OPCODE_MAXNUM; i++) { if (opcodeNumUses[i] > maxUse) { maxUse = opcodeNumUses[i]; maxIndex = i; } } printf("%02d 0x%03x: %d\n", j, maxIndex, maxUse); opcodeNumUses[maxIndex] = 0; } } #endif //Sys.Crash("FINISHED!!!"); return(retValue); }
public static uint Update(uint maxInstr, int *pReturnCode) { tThread *pThread; tThread *pPrevThread; uint status; pThread = pAllThreads; // Set the initial thread to the RUNNING state. pThread->state = THREADSTATE_RUNNING; // Set the initial CurrentThread pCurrentThread = pThread; for (;;) { uint minSleepTime = 0xffffffff; int threadExitValue; status = JIT_Execute.Execute(pThread, maxInstr); switch (status) { case Thread.THREAD_STATUS_EXIT: threadExitValue = pThread->threadExitValue; Sys.log_f(1, "Thread ID#%d exited. Return value: %d\n", (int)pThread->threadID, (int)threadExitValue); // Remove the current thread from the running threads list. // Note that this list may have changed since before the call to JitOps.JIT_Execute(). { if (pAllThreads == pThread) { pAllThreads = pAllThreads->pNextThread; } else { tThread *pThread1 = pAllThreads; while (pThread1->pNextThread != pThread) { pThread1 = pThread1->pNextThread; } pThread1->pNextThread = pThread1->pNextThread->pNextThread; } } // Delete the current thread Thread.Delete(pThread); // If there are no more threads left running, then exit application (by returning) // Threads that are unstarted or background do not stop the exit // [Steve edit] Threads that are suspended also do not stop the exit. This is because you'd just // wait forever for them if they did. Note that 'exit' doesn't mean tearing down the process // like in a regular .NET runtime case. The application state is still there and we can make // further calls into it to create new threads. { tThread *pThread2 = pAllThreads; uint canExit = 1; while (pThread2 != null) { if ( ((pThread2->state & THREADSTATE_BACKGROUND) == 0) && ((pThread2->state & (~THREADSTATE_BACKGROUND)) != THREADSTATE_UNSTARTED) && ((pThread2->state & (~THREADSTATE_BACKGROUND)) != THREADSTATE_SUSPENDED)) { canExit = 0; break; } pThread2 = pThread2->pNextThread; } if (canExit != 0) { if (pReturnCode != null) { *pReturnCode = threadExitValue; } return(THREADSTATE_STOPPED); } } pThread = pAllThreads; // This is not really correct, but it'll work for the time being break; case THREAD_STATUS_RUNNING: case THREAD_STATUS_LOCK_EXIT: // Nothing to do break; case THREAD_STATUS_ASYNC: pThread->pAsync->startTime = Sys.msTime(); break; } // Move on to the next thread. // Find the next thread that isn't sleeping or blocked on IO pPrevThread = pThread; for (;;) { pThread = pThread->pNextThread; if (pThread == null) { // That was the thread -- return! return(THREADSTATE_RUNNING); } // Set the CurrentThread correctly pCurrentThread = pThread; if ((pThread->state & (~THREADSTATE_BACKGROUND)) != 0) { // Thread is not running continue; } if (pThread->pAsync != null) { // Discover if whatever is being waited for is finished tAsyncCall *pAsync = pThread->pAsync; if (pAsync->sleepTime >= 0) { // This is a sleep ulong nowTime = Sys.msTime(); int msSleepRemaining = pAsync->sleepTime - (int)(nowTime - pAsync->startTime); if (msSleepRemaining <= 0) { // Sleep is finished break; } // Sleep is not finished, so continue to next thread if ((uint)msSleepRemaining < minSleepTime) { minSleepTime = (uint)msSleepRemaining; } } else { // This is blocking IO, or a lock tMethodState *pMethodState = pThread->pCurrentMethodState; byte * pThis; uint thisOfs; uint unblocked; if (MetaData.METHOD_ISSTATIC(pMethodState->pMethod)) { pThis = null; thisOfs = 0; } else { pThis = *(byte **)pMethodState->pParamsLocals; thisOfs = 4; } unblocked = ((fnInternalCallCheck)H.ToObj(pAsync->checkFn))(null, pThis, pMethodState->pParamsLocals + thisOfs, pMethodState->pEvalStack, pAsync); if (unblocked != 0) { // The IO has unblocked, and the return value is ready. // So delete the async object. // TODO: The async->state object needs to be deleted somehow (maybe) Mem.free(pAsync); // And remove it from the thread pThread->pAsync = null; break; } minSleepTime = 5; } } else { // Thread is ready to run break; } if (pThread == pPrevThread) { // When it gets here, it means that all threads are currently blocked. //printf("All blocked; sleep(%d)\n", minSleepTime); Sys.SleepMS(minSleepTime); } } } }
public static tMD_TypeDef *GetGenericTypeFromCoreType(tMD_TypeDef *pCoreType, uint numTypeArgs, tMD_TypeDef **ppTypeArgs) { tGenericInstance *pInst; tMD_TypeDef * pTypeDef; uint i; byte * name = stackalloc byte[NAME_BUF_SIZE]; byte * namePos, nameEnd; tMetaData *pMetaData; Mem.heapcheck(); pMetaData = pCoreType->pMetaData; MetaData.Fill_TypeDef(pCoreType, null, null, Type.TYPE_FILL_PARENTS); // See if we have already built an instantiation of this type with the given type args. pInst = pCoreType->pGenericInstances; while (pInst != null) { if (pInst->numTypeArgs == numTypeArgs && Mem.memcmp(pInst->ppTypeArgs, ppTypeArgs, (SIZE_T)(numTypeArgs * sizeof(tMD_TypeDef *))) == 0) { return(pInst->pInstanceTypeDef); } pInst = pInst->pNext; } // This has not already been instantiated, so instantiate it now. pInst = (tGenericInstance *)Mem.mallocForever((SIZE_T)sizeof(tGenericInstance)); // Insert this into the chain of instantiations. pInst->pNext = pCoreType->pGenericInstances; pCoreType->pGenericInstances = pInst; // Copy the type args into the instantiation. pInst->numTypeArgs = numTypeArgs; pInst->ppTypeArgs = (tMD_TypeDef **)Mem.malloc((SIZE_T)(numTypeArgs * sizeof(tMD_TypeDef *))); Mem.memcpy(pInst->ppTypeArgs, ppTypeArgs, (SIZE_T)(numTypeArgs * sizeof(tMD_TypeDef *))); Mem.heapcheck(); // Create the new instantiated type pInst->pInstanceTypeDef = pTypeDef = ((tMD_TypeDef *)Mem.mallocForever((SIZE_T)sizeof(tMD_TypeDef))); Mem.memset(pTypeDef, 0, (SIZE_T)sizeof(tMD_TypeDef)); // Make the name of the instantiation. namePos = name; nameEnd = namePos + NAME_BUF_SIZE - 1; namePos = S.scatprintf(namePos, nameEnd, "%s", (PTR)pCoreType->name); namePos = S.scatprintf(namePos, nameEnd, "["); for (i = 0; i < numTypeArgs; i++) { if (i > 0) { namePos = S.scatprintf(namePos, nameEnd, ","); } if (ppTypeArgs[i] != null) { namePos = S.scatprintf(namePos, nameEnd, "%s.%s", (PTR)ppTypeArgs[i]->nameSpace, (PTR)ppTypeArgs[i]->name); } else { tMD_GenericParam *pGenericParam = FindGenericParam(pCoreType, i); if (pGenericParam != null) { namePos = S.scatprintf(namePos, nameEnd, "%s", (PTR)pGenericParam->name); } else { namePos = S.scatprintf(namePos, nameEnd, "???"); } } } namePos = S.scatprintf(namePos, nameEnd, "]"); // Fill in the basic bits of the new type def. pTypeDef->pTypeDef = pTypeDef; pTypeDef->pMetaData = pMetaData; pTypeDef->flags = pCoreType->flags; pTypeDef->pGenericDefinition = pCoreType; for (i = 0; i < numTypeArgs; i++) { if (ppTypeArgs[i] == null) { pTypeDef->isGenericDefinition = 1; break; } } pTypeDef->nameSpace = pCoreType->nameSpace; int nameLen = S.strlen(name) + 1; pTypeDef->name = (/*STRING*/ byte *)Mem.mallocForever((SIZE_T)nameLen); S.strncpy(pTypeDef->name, name, nameLen); pTypeDef->ppClassTypeArgs = pInst->ppTypeArgs; pTypeDef->extends = pCoreType->extends; pTypeDef->tableIndex = pCoreType->tableIndex; pTypeDef->fieldList = pCoreType->fieldList; pTypeDef->methodList = pCoreType->methodList; pTypeDef->numFields = pCoreType->numFields; pTypeDef->numMethods = pCoreType->numMethods; pTypeDef->numVirtualMethods = pCoreType->numVirtualMethods; pTypeDef->pNestedIn = pCoreType->pNestedIn; pTypeDef->isPrimed = 1; MetaData.Fill_TypeDef(pTypeDef, pInst->ppTypeArgs, null, Type.TYPE_FILL_PARENTS); Mem.heapcheck(); return(pTypeDef); }
public static tMD_MethodDef *GetMethodDefFromCoreMethod(tMD_MethodDef *pCoreMethod, tMD_TypeDef *pParentType, uint numTypeArgs, tMD_TypeDef **ppTypeArgs, HashSet <PTR> resolveTypes = null) { tGenericMethodInstance *pInst; tMD_MethodDef * pMethod; Mem.heapcheck(); // See if we already have an instance with the given type args pInst = pCoreMethod->pGenericMethodInstances; while (pInst != null) { if (pInst->numTypeArgs == numTypeArgs && Mem.memcmp(pInst->ppTypeArgs, ppTypeArgs, (SIZE_T)(numTypeArgs * sizeof(tMD_TypeDef *))) == 0) { return(pInst->pInstanceMethodDef); } pInst = pInst->pNext; } // We don't have an instance so create one now. pInst = (tGenericMethodInstance *)Mem.mallocForever((SIZE_T)(sizeof(tGenericMethodInstance))); pInst->pNext = pCoreMethod->pGenericMethodInstances; pCoreMethod->pGenericMethodInstances = pInst; pInst->numTypeArgs = numTypeArgs; pInst->ppTypeArgs = (tMD_TypeDef **)Mem.malloc((SIZE_T)(numTypeArgs * sizeof(tMD_TypeDef *))); Mem.memcpy(pInst->ppTypeArgs, ppTypeArgs, (SIZE_T)(numTypeArgs * sizeof(tMD_TypeDef *))); pInst->pInstanceMethodDef = pMethod = ((tMD_MethodDef *)Mem.mallocForever((SIZE_T)sizeof(tMD_MethodDef))); Mem.memset(pMethod, 0, (SIZE_T)sizeof(tMD_MethodDef)); pMethod->pMethodDef = pMethod; pMethod->pMetaData = pCoreMethod->pMetaData; pMethod->pCIL = pCoreMethod->pCIL; pMethod->implFlags = pCoreMethod->implFlags; pMethod->flags = pCoreMethod->flags; pMethod->name = pCoreMethod->name; pMethod->signature = pCoreMethod->signature; pMethod->vTableOfs = pCoreMethod->vTableOfs; pMethod->ppMethodTypeArgs = pInst->ppTypeArgs; if (pCoreMethod->monoMethodInfo != null) { System.Reflection.MethodInfo methodInfo = H.ToObj(pCoreMethod->monoMethodInfo) as System.Reflection.MethodInfo; System.Type[] typeArgs = new System.Type[(int)numTypeArgs]; for (uint i = 0; i < numTypeArgs; i++) { typeArgs[i] = MonoType.GetMonoTypeForType(ppTypeArgs[i]); if (typeArgs[i] == null) { Sys.Crash("Unable to find mono type for type arg %s.%s in for generic method %s", (PTR)ppTypeArgs[i]->nameSpace, (PTR)ppTypeArgs[i]->name, (PTR)pCoreMethod->name); } } System.Reflection.MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(typeArgs); MonoType.Fill_MethodDef(pParentType, genericMethodInfo, pMethod, pParentType->ppClassTypeArgs, pInst->ppTypeArgs); } else { MetaData.Fill_MethodDef(pParentType, pMethod, pParentType->ppClassTypeArgs, pInst->ppTypeArgs); } Mem.heapcheck(); return(pMethod); }
public static void Fill_TypeDef(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs, uint resolve = Type.TYPE_FILL_ALL) { /*IDX_TABLE*/ uint firstIdx, lastIdx, token; uint instanceMemSize, staticMemSize, virtualOfs, isDeferred, i, j; tMetaData * pMetaData = pTypeDef->pMetaData; tMD_TypeDef *pParent; if (pTypeDef->fillState >= resolve) { return; } if (pTypeDef->monoType != null) { MonoType.Fill_TypeDef(pTypeDef, ppClassTypeArgs, ppMethodTypeArgs, resolve); return; } // Sys.printf("FILLING TYPE: %s\n", (PTR)pTypeDef->name); // string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((System.IntPtr)pTypeDef->name); if (typesToFill == null) { Fill_StartDefer(); isDeferred = 1; } else { isDeferred = 0; } if (resolve < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pTypeDef, ppClassTypeArgs, ppMethodTypeArgs); } MetaData.Fill_GetDeferredTypeArgs(pTypeDef, ref ppClassTypeArgs, ref ppMethodTypeArgs); // Fill parent info if (pTypeDef->fillState < Type.TYPE_FILL_PARENTS) { pTypeDef->fillState = Type.TYPE_FILL_PARENTS; pTypeDef->pTypeDef = pTypeDef; if (pTypeDef->alignment == 0) { pTypeDef->alignment = 1; } if (pTypeDef->pParent == null) { pTypeDef->pParent = MetaData.GetTypeDefFromDefRefOrSpec(pMetaData, pTypeDef->extends, ppClassTypeArgs, ppMethodTypeArgs); } pParent = pTypeDef->pParent; if (pParent != null) { if (pParent->fillState < Type.TYPE_FILL_PARENTS) { MetaData.Fill_TypeDef(pParent, null, null, Type.TYPE_FILL_PARENTS); } else if (pParent->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pParent, null, null); } pTypeDef->hasMonoBase = pParent->hasMonoBase; if (pParent->hasMonoBase == 0) { // If we have a mono base type, we have at least 1 non-blittable field pTypeDef->blittable = pParent->blittable; pTypeDef->fixedBlittable = pParent->fixedBlittable; } else { pTypeDef->blittable = pTypeDef->fixedBlittable = 0; } } else { pTypeDef->blittable = pTypeDef->fixedBlittable = 1; } // If this type is an interface, then return 0 if (pTypeDef->stackSize != 0) { pTypeDef->isValueType = (byte)(pTypeDef->stackType != EvalStack.EVALSTACK_O ? 1 : 0); } else if (MetaData.TYPE_ISINTERFACE(pTypeDef)) { pTypeDef->isValueType = 0; } else if (pTypeDef->nameSpace[0] == 'S' && S.strcmp(pTypeDef->nameSpace, new S(ref scSystem, "System")) == 0) { if ((pTypeDef->name[0] == 'V' && S.strcmp(pTypeDef->name, new S(ref scValueType, "ValueType")) == 0) || (pTypeDef->name[0] == 'E' && S.strcmp(pTypeDef->name, new S(ref scEnum, "Enum")) == 0)) { pTypeDef->isValueType = 1; } else if (pTypeDef->name[0] == 'O' && S.strcmp(pTypeDef->name, new S(ref scObject, "Object")) == 0) { pTypeDef->isValueType = 0; } else if (pParent != null) { pTypeDef->isValueType = pParent->isValueType; } } else if (pParent != null) { pTypeDef->isValueType = pParent->isValueType; } // If not primed, then work out how many methods & fields there are. if (pTypeDef->isPrimed == 0) { // Methods lastIdx = (pTypeDef->isLast != 0) ? MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_METHODDEF, pTypeDef->pMetaData->tables.numRows[MetaDataTable.MD_TABLE_METHODDEF]) : (pTypeDef[1].methodList - 1); pTypeDef->numMethods = lastIdx - pTypeDef->methodList + 1; // Fields lastIdx = (pTypeDef->isLast != 0) ? MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_FIELDDEF, pTypeDef->pMetaData->tables.numRows[MetaDataTable.MD_TABLE_FIELDDEF]) : (pTypeDef[1].fieldList - 1); pTypeDef->numFields = lastIdx - pTypeDef->fieldList + 1; } // If this is a nested type, then find the namespace of it if (pTypeDef->pNestedIn != null) { tMD_TypeDef *pRootTypeDef = pTypeDef->pNestedIn; while (pRootTypeDef->pNestedIn != null) { pRootTypeDef = pRootTypeDef->pNestedIn; } pTypeDef->nameSpace = pRootTypeDef->nameSpace; } // If this is an enum type, then pretend its stack type is its underlying type if (pTypeDef->pParent == Type.types[Type.TYPE_SYSTEM_ENUM]) { pTypeDef->stackType = EvalStack.EVALSTACK_INT32; pTypeDef->stackSize = sizeof(PTR); pTypeDef->instanceMemSize = 4; pTypeDef->arrayElementSize = 4; pTypeDef->blittable = pTypeDef->fixedBlittable = 1; } if (pTypeDef->fillState >= resolve) { return; } } else { pParent = pTypeDef->pParent; } if (pTypeDef->fillState < Type.TYPE_FILL_LAYOUT) { pTypeDef->fillState = Type.TYPE_FILL_LAYOUT; if (pParent != null) { if (pParent->fillState < Type.TYPE_FILL_LAYOUT) { MetaData.Fill_TypeDef(pParent, null, null, Type.TYPE_FILL_LAYOUT); } else if (pParent->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pParent, null, null); } } if (pTypeDef->isGenericDefinition == 0) { // Resolve fields, members, interfaces. // Only needs to be done if it's not a generic definition type // It it's not a value-type and the stack-size is not preset, then set it up now. // It needs to be done here as non-static fields in non-value type can point to the containing type if (pTypeDef->stackSize == 0 && pTypeDef->isValueType == 0) { pTypeDef->stackType = EvalStack.EVALSTACK_O; pTypeDef->stackSize = sizeof(PTR); pTypeDef->alignment = sizeof(PTR); } // Resolve all fields - instance ONLY at this point, // because static fields in value-Type.types can be of the containing type, and the size is not yet known. firstIdx = pTypeDef->fieldList; lastIdx = firstIdx + pTypeDef->numFields - 1; staticMemSize = 0; if (pTypeDef->numFields > 0) { pTypeDef->ppFields = (tMD_FieldDef **)Mem.mallocForever((SIZE_T)(pTypeDef->numFields * sizeof(tMD_FieldDef *))); } instanceMemSize = (pParent == null ? 0 : pTypeDef->pParent->instanceMemSize); if (pTypeDef->hasMonoBase != 0 && pParent->hasMonoBase == 0) { // Some DNA types like String are actually wrappers around mono objects. In those cases, we need to allocate the // space in the instance memory for the GCHandle to the mono object. We distinguish this case from the case // where we're just extending a Mono Type object by checking if the parent also has the hasMonoBase flag set. instanceMemSize += (uint)sizeof(void *); } for (token = firstIdx, i = 0; token <= lastIdx; token++, i++) { tMD_FieldDef *pFieldDef; pFieldDef = MetaData.GetFieldDefFromDefOrRef(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); if (!MetaData.FIELD_ISSTATIC(pFieldDef)) { // Only handle non-static fields at the moment if (pTypeDef->pGenericDefinition != null) { // If this is a generic instantiation type, then all field defs need to be copied, // as there will be lots of different instantiations. tMD_FieldDef *pFieldCopy = ((tMD_FieldDef *)Mem.mallocForever((SIZE_T)sizeof(tMD_FieldDef))); Mem.memcpy(pFieldCopy, pFieldDef, (SIZE_T)sizeof(tMD_FieldDef)); pFieldDef = pFieldCopy; } if (MetaData.FIELD_ISLITERAL(pFieldDef) || MetaData.FIELD_HASFIELDRVA(pFieldDef)) { // If it's a literal, then analyse the field, but don't include it in any memory allocation // If is has an RVA, then analyse the field, but don't include it in any memory allocation MetaData.Fill_FieldDef(pTypeDef, pFieldDef, 0, null, ppClassTypeArgs); } else { MetaData.Fill_FieldDef(pTypeDef, pFieldDef, instanceMemSize, &(pTypeDef->alignment), ppClassTypeArgs); instanceMemSize = pFieldDef->memOffset + pFieldDef->memSize; } // Update blittable and fixedBlittable status for type - if any non-blittable fields are included set to 0 if (pTypeDef->blittable != 0 || pTypeDef->fixedBlittable != 0) { if (pFieldDef->pType->isValueType == 0 || pFieldDef->pType->blittable == 0) { pTypeDef->blittable = pTypeDef->fixedBlittable = 0; } else if (pFieldDef->pType->typeInitId == Type.TYPE_SYSTEM_INTPTR || pFieldDef->pType->typeInitId == Type.TYPE_SYSTEM_UINTPTR) { pTypeDef->fixedBlittable = 0; } } pTypeDef->ppFields[i] = pFieldDef; } } if (pTypeDef->instanceMemSize == 0) { pTypeDef->instanceMemSize = (instanceMemSize + (pTypeDef->alignment - 1)) & ~(pTypeDef->alignment - 1); } // Sort out stack type and size. // Note that this may already be set, as some basic type have this preset; // or if it's not a value-type it'll already be set if (pTypeDef->stackSize == 0) { // if it gets here then it must be a value type pTypeDef->stackType = EvalStack.EVALSTACK_VALUETYPE; pTypeDef->stackSize = pTypeDef->instanceMemSize; } // Sort out array element size. Note that some basic type will have this preset. if (pTypeDef->arrayElementSize == 0) { pTypeDef->arrayElementSize = pTypeDef->stackSize; } // Make sure stack size is even multiple of stack alignment pTypeDef->stackSize = (pTypeDef->stackSize + (STACK_ALIGNMENT - 1)) & ~(STACK_ALIGNMENT - 1); // Handle static fields for (token = firstIdx, i = 0; token <= lastIdx; token++, i++) { tMD_FieldDef *pFieldDef; pFieldDef = MetaData.GetFieldDefFromDefOrRef(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); if (MetaData.FIELD_ISSTATIC(pFieldDef)) { // Only handle static fields here if (pTypeDef->pGenericDefinition != null) { // If this is a generic instantiation type, then all field defs need to be copied, // as there will be lots of different instantiations. tMD_FieldDef *pFieldCopy = ((tMD_FieldDef *)Mem.mallocForever((SIZE_T)sizeof(tMD_FieldDef))); Mem.memcpy(pFieldCopy, pFieldDef, (SIZE_T)sizeof(tMD_FieldDef)); pFieldDef = pFieldCopy; } if (MetaData.FIELD_ISLITERAL(pFieldDef) || MetaData.FIELD_HASFIELDRVA(pFieldDef)) { // If it's a literal, then analyse the field, but don't include it in any memory allocation // If is has an RVA, then analyse the field, but don't include it in any memory allocation MetaData.Fill_FieldDef(pTypeDef, pFieldDef, 0, null, ppClassTypeArgs); } else { MetaData.Fill_FieldDef(pTypeDef, pFieldDef, staticMemSize, null, ppClassTypeArgs); staticMemSize += pFieldDef->memSize; } pTypeDef->ppFields[i] = pFieldDef; } } if (staticMemSize > 0) { pTypeDef->pStaticFields = (byte *)Mem.mallocForever((SIZE_T)staticMemSize); Mem.memset(pTypeDef->pStaticFields, 0, staticMemSize); // Set the field addresses (->pMemory) of all static fields for (i = 0; i < pTypeDef->numFields; i++) { tMD_FieldDef *pFieldDef; pFieldDef = pTypeDef->ppFields[i]; if (MetaData.FIELD_ISSTATIC(pFieldDef) && pFieldDef->pMemory == null) { // Only set it if it isn't already set. It will be already set if this field has an RVA pFieldDef->pMemory = pTypeDef->pStaticFields + pFieldDef->memOffset; } } pTypeDef->staticFieldSize = staticMemSize; } } if (pTypeDef->fillState >= resolve) { return; } } // This only needs to be done for non-generic Type.types, or for generic type that are not a definition // I.e. Fully instantiated generic Type.types if (pTypeDef->fillState < Type.TYPE_FILL_VTABLE) { pTypeDef->fillState = Type.TYPE_FILL_VTABLE; if (pParent != null) { if (pParent->fillState < Type.TYPE_FILL_VTABLE) { MetaData.Fill_TypeDef(pParent, null, null, Type.TYPE_FILL_VTABLE); } else if (pParent->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pParent, null, null); } } if (pTypeDef->isGenericDefinition == 0) { virtualOfs = (pParent != null) ? pParent->numVirtualMethods : 0; // Must create the virtual method table BEFORE any other type resolution is done // Note that this must not do ANY filling of type or methods. // This is to ensure that the parent object(s) in any type inheritance hierachy are allocated // their virtual method offset before derived Type.types. firstIdx = pTypeDef->methodList; lastIdx = firstIdx + pTypeDef->numMethods - 1; for (token = firstIdx; token <= lastIdx; token++) { tMD_MethodDef *pMethodDef; pMethodDef = MetaData.GetMethodDefFromDefRefOrSpec(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); //Sys.printf("Method: %s\n", (PTR)pMethodDef->name); // This is needed, so array resolution can work correctly and FindVirtualOverriddenMethod() can work. pMethodDef->pParentType = pTypeDef; if (MetaData.METHOD_ISVIRTUAL(pMethodDef)) { if (MetaData.METHOD_ISNEWSLOT(pMethodDef) || pTypeDef->pParent == null) { // Allocate a new vTable slot if method is explicitly marked as NewSlot, or // this is of type Object. pMethodDef->vTableOfs = virtualOfs++; } else { tMD_MethodDef *pVirtualOveriddenMethod; pVirtualOveriddenMethod = FindVirtualOverriddenMethod(pTypeDef->pParent, pMethodDef); if (pVirtualOveriddenMethod == null) { Sys.Crash("Unable to find virtual override method for %s %s", (PTR)pTypeDef->name, (PTR)pMethodDef->name); } pMethodDef->vTableOfs = pVirtualOveriddenMethod->vTableOfs; } } else { // Dummy value - make it obvious it's not valid! pMethodDef->vTableOfs = 0xffffffff; } } // Create the virtual method table pTypeDef->numVirtualMethods = virtualOfs; // Resolve all members firstIdx = pTypeDef->methodList; lastIdx = firstIdx + pTypeDef->numMethods - 1; pTypeDef->ppMethods = (tMD_MethodDef **)Mem.mallocForever((SIZE_T)(pTypeDef->numMethods * sizeof(tMD_MethodDef *))); pTypeDef->pVTable = (tMD_MethodDef **)Mem.mallocForever((SIZE_T)(pTypeDef->numVirtualMethods * sizeof(tMD_MethodDef *))); // Copy initial vTable from parent if (pTypeDef->pParent != null) { if (pTypeDef->pParent->fillState != Type.TYPE_FILL_MEMBERS) { Fill_TypeDef(pTypeDef->pParent, null, null, Type.TYPE_FILL_MEMBERS); } Mem.memcpy(pTypeDef->pVTable, pTypeDef->pParent->pVTable, (SIZE_T)(pTypeDef->pParent->numVirtualMethods * sizeof(tMD_MethodDef *))); } for (token = firstIdx, i = 0; token <= lastIdx; token++, i++) { tMD_MethodDef *pMethodDef; pMethodDef = MetaData.GetMethodDefFromDefRefOrSpec(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); if (pTypeDef->pGenericDefinition != null) { // If this is a generic instantiation type, then all method defs need to be copied, // as there will be lots of different instantiations. tMD_MethodDef *pMethodCopy = ((tMD_MethodDef *)Mem.mallocForever((SIZE_T)sizeof(tMD_MethodDef))); Mem.memcpy(pMethodCopy, pMethodDef, (SIZE_T)sizeof(tMD_MethodDef)); pMethodDef = pMethodCopy; } if (MetaData.METHOD_ISSTATIC(pMethodDef) && S.strcmp(pMethodDef->name, ".cctor") == 0) { // This is a static constructor pTypeDef->pStaticConstructor = pMethodDef; } if (!MetaData.METHOD_ISSTATIC(pMethodDef) && pTypeDef->pParent != null && S.strcmp(pMethodDef->name, "Finalize") == 0) { // This is a Finalizer method, but not for Object. // Delibrately miss out Object's Finalizer because it's empty and will cause every object // of any type to have a Finalizer which will be terrible for performance. pTypeDef->pFinalizer = pMethodDef; } if (MetaData.METHOD_ISVIRTUAL(pMethodDef)) { // This is a virtual method, so enter it in the vTable pTypeDef->pVTable[pMethodDef->vTableOfs] = pMethodDef; } pTypeDef->ppMethods[i] = pMethodDef; } // Find inherited Finalizer, if this type doesn't have an explicit Finalizer, and if there is one if (pTypeDef->pFinalizer == null) { tMD_TypeDef *pInheritedType = pTypeDef->pParent; while (pInheritedType != null) { if (pInheritedType->pFinalizer != null) { pTypeDef->pFinalizer = pInheritedType->pFinalizer; break; } pInheritedType = pInheritedType->pParent; } } } if (pTypeDef->fillState >= resolve) { return; } } if (pTypeDef->fillState < Type.TYPE_FILL_MEMBERS) { pTypeDef->fillState = Type.TYPE_FILL_MEMBERS; if (pParent != null) { if (pParent->fillState < Type.TYPE_FILL_MEMBERS) { MetaData.Fill_TypeDef(pParent, null, null, Type.TYPE_FILL_MEMBERS); } else if (pParent->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pParent, null, null); } } if (pTypeDef->isGenericDefinition == 0) { // Fill all method definitions for this type for (i = 0; i < pTypeDef->numMethods; i++) { MetaData.Fill_MethodDef(pTypeDef, pTypeDef->ppMethods[i], ppClassTypeArgs, ppMethodTypeArgs); } } if (pTypeDef->fillState >= resolve) { return; } } if (pTypeDef->fillState < Type.TYPE_FILL_INTERFACES) { pTypeDef->fillState = Type.TYPE_FILL_INTERFACES; if (pParent != null) { if (pParent->fillState < Type.TYPE_FILL_INTERFACES) { MetaData.Fill_TypeDef(pParent, null, null, Type.TYPE_FILL_INTERFACES); } else if (pParent->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pParent, null, null); } } if (pTypeDef->isGenericDefinition == 0 && !MetaData.TYPE_ISINTERFACE(pTypeDef)) { if (pParent != null && pParent->fillState < Type.TYPE_FILL_INTERFACES) { MetaData.Fill_TypeDef(pParent, null, null, Type.TYPE_FILL_INTERFACES); } // Map all interface method calls. This only needs to be done for Classes, not Interfaces // And is not done for generic definitions. firstIdx = 0; if (pTypeDef->pParent != null) { j = pTypeDef->numInterfaces = pTypeDef->pParent->numInterfaces; } else { j = 0; } lastIdx = firstIdx; for (i = 1; i <= pMetaData->tables.numRows[MetaDataTable.MD_TABLE_INTERFACEIMPL]; i++) { tMD_InterfaceImpl *pInterfaceImpl; pInterfaceImpl = (tMD_InterfaceImpl *)MetaData.GetTableRow(pMetaData, MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_INTERFACEIMPL, i)); if (pInterfaceImpl->class_ == pTypeDef->tableIndex) { // count how many interfaces are implemented pTypeDef->numInterfaces++; if (firstIdx == 0) { firstIdx = MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_INTERFACEIMPL, i); } lastIdx = MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_INTERFACEIMPL, i); } } if (pTypeDef->numInterfaces > 0) { uint mapNum; pTypeDef->pInterfaceMaps = (tInterfaceMap *)Mem.mallocForever((SIZE_T)(pTypeDef->numInterfaces * sizeof(tInterfaceMap))); // Copy interface maps from parent type if (j > 0) { Mem.memcpy(pTypeDef->pInterfaceMaps, pTypeDef->pParent->pInterfaceMaps, (SIZE_T)(j * sizeof(tInterfaceMap))); } mapNum = j; if (firstIdx > 0) { for (token = firstIdx; token <= lastIdx; token++, mapNum++) { tMD_InterfaceImpl *pInterfaceImpl; pInterfaceImpl = (tMD_InterfaceImpl *)MetaData.GetTableRow(pMetaData, token); if (pInterfaceImpl->class_ == pTypeDef->tableIndex) { tMD_TypeDef * pInterface; tInterfaceMap *pMap; // Get the interface that this type implements pInterface = MetaData.GetTypeDefFromDefRefOrSpec(pMetaData, pInterfaceImpl->interface_, ppClassTypeArgs, ppMethodTypeArgs); MetaData.Fill_TypeDef(pInterface, null, null, Type.TYPE_FILL_INTERFACES); pMap = &pTypeDef->pInterfaceMaps[mapNum]; pMap->pInterface = pInterface; pMap->pVTableLookup = (uint *)Mem.mallocForever((SIZE_T)(pInterface->numVirtualMethods * sizeof(uint))); pMap->ppMethodVLookup = (tMD_MethodDef **)Mem.mallocForever((SIZE_T)(pInterface->numVirtualMethods * sizeof(tMD_MethodDef *))); // Discover interface mapping for each interface method for (i = 0; i < pInterface->numVirtualMethods; i++) { tMD_MethodDef *pInterfaceMethod; tMD_MethodDef *pOverriddenMethod; pInterfaceMethod = pInterface->pVTable[i]; pOverriddenMethod = FindVirtualOverriddenMethod(pTypeDef, pInterfaceMethod); pMap->pVTableLookup[i] = pOverriddenMethod->vTableOfs; pMap->ppMethodVLookup[i] = pOverriddenMethod; } } else { Sys.Crash("Problem with interface class"); } } } } } if (pTypeDef->fillState >= resolve) { return; } } if (pTypeDef->fillState < Type.TYPE_FILL_ALL) { pTypeDef->fillState = Type.TYPE_FILL_ALL; if (pTypeDef->isGenericDefinition == 0 && pTypeDef->stackSize == 0) { j = 0; } if (pParent != null && pParent->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_TypeDef(pParent, null, null, Type.TYPE_FILL_ALL); } if (isDeferred != 0) { Fill_ResolveDeferred(); } } Sys.log_f(2, "Type: %s.%s\n", (PTR)pTypeDef->nameSpace, (PTR)pTypeDef->name); }
public static void Init() { methodNameBuf = (byte *)Mem.malloc((SIZE_T)METHOD_NAME_BUF_SIZE); }
public static void SetParameters(tMethodState *pMethodState, tMD_MethodDef *pCallMethod, byte *pParams) { Mem.memcpy(pMethodState->pParamsLocals, pParams, pCallMethod->parameterStackSize); }
public static void Fill_MethodDef(tMD_TypeDef *pParentType, tMD_MethodDef *pMethodDef, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) { /*SIG*/ byte *sig; uint i, entry, totalSize, start; if (pMethodDef->isFilled == 1) { return; } // Note: parent type can be null for module level methods (not typical in C# assemblies) pMethodDef->pParentType = pParentType; pMethodDef->pMethodDef = pMethodDef; pMethodDef->isFilled = 1; if (pMethodDef->isGenericDefinition != 0) { // Generic definition method, so can't do any more. //Sys.log_f("Method<>: %s.%s.%s()\n", pParentType->nameSpace, pParentType->name, pMethodDef->name); return; } sig = MetaData.GetBlob(pMethodDef->signature, null); entry = MetaData.DecodeSigEntry(&sig); if ((entry & SIG_METHODDEF_GENERIC) != 0) { // Has generic parameters. Read how many, but don't care about the answer MetaData.DecodeSigEntry(&sig); } pMethodDef->numberOfParameters = (ushort)(MetaData.DecodeSigEntry(&sig) + (MetaData.METHOD_ISSTATIC(pMethodDef)?0:1)); pMethodDef->pReturnType = Type.GetTypeFromSig(pMethodDef->pMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs, null); if (pMethodDef->pReturnType != null && pMethodDef->pReturnType->fillState < Type.TYPE_FILL_ALL) { Fill_Defer(pMethodDef->pReturnType, ppClassTypeArgs, ppMethodTypeArgs); } pMethodDef->pParams = (tParameter *)Mem.malloc((SIZE_T)(pMethodDef->numberOfParameters * sizeof(tParameter))); totalSize = 0; start = 0; if (!MetaData.METHOD_ISSTATIC(pMethodDef)) { // Fill in parameter info for the 'this' pointer pMethodDef->pParams->offset = 0; if (pParentType->isValueType != 0) { // If this is a value-type then the 'this' pointer is actually an IntPtr to the value-type's location pMethodDef->pParams->size = sizeof(PTR); pMethodDef->pParams->pStackTypeDef = Type.types[Type.TYPE_SYSTEM_INTPTR]; } else { pMethodDef->pParams->size = sizeof(PTR); pMethodDef->pParams->pStackTypeDef = pParentType; } totalSize = sizeof(PTR); start = 1; } for (i = start; i < pMethodDef->numberOfParameters; i++) { tMD_TypeDef *pStackTypeDef; tMD_TypeDef *pByRefTypeDef; uint size; pByRefTypeDef = null; pStackTypeDef = Type.GetTypeFromSig(pMethodDef->pMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs, &pByRefTypeDef); if (pStackTypeDef != null) { if (pStackTypeDef->fillState < Type.TYPE_FILL_LAYOUT) { MetaData.Fill_TypeDef(pStackTypeDef, null, null, Type.TYPE_FILL_LAYOUT); } else if (pStackTypeDef->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pStackTypeDef, null, null); } size = pStackTypeDef->stackSize; } else { size = 0; } if (pByRefTypeDef != null) { if (pByRefTypeDef->fillState < Type.TYPE_FILL_LAYOUT) { MetaData.Fill_TypeDef(pByRefTypeDef, null, null, Type.TYPE_FILL_LAYOUT); } else if (pByRefTypeDef->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_Defer(pByRefTypeDef, null, null); } } pMethodDef->pParams[i].pStackTypeDef = pStackTypeDef; pMethodDef->pParams[i].pByRefTypeDef = pByRefTypeDef; pMethodDef->pParams[i].offset = totalSize; pMethodDef->pParams[i].size = size; totalSize += size; } pMethodDef->parameterStackSize = totalSize; }
static tMD_MethodDef *FindMethodInType(tMD_TypeDef *pTypeDef, /*STRING*/ byte *name, tMetaData *pSigMetaData, /*BLOB_*/ byte *sigBlob, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) { uint i; tMD_TypeDef *pLookInType = pTypeDef; if (pLookInType->fillState < Type.TYPE_FILL_MEMBERS) { MetaData.Fill_TypeDef(pTypeDef, ppClassTypeArgs, ppMethodTypeArgs, Type.TYPE_FILL_MEMBERS); } do { for (i = 0; i < pLookInType->numMethods; i++) { if (MetaData.CompareNameAndSig(name, sigBlob, pSigMetaData, ppClassTypeArgs, ppMethodTypeArgs, pLookInType->ppMethods[i], pLookInType->ppClassTypeArgs, null) != 0) { return(pLookInType->ppMethods[i]); } } pLookInType = pLookInType->pParent; } while (pLookInType != null); { // Error reporting!! uint entry, numParams, j; /*SIG*/ byte * sig; /*char**/ byte *pMsg, pMsgPos, pMsgEnd; tMD_TypeDef * pParamTypeDef; pMsgPos = pMsg = (byte *)Mem.malloc(MSG_BUF_SIZE); pMsgEnd = pMsg + MSG_BUF_SIZE; *pMsg = 0; sig = MetaData.GetBlob(sigBlob, &j); entry = MetaData.DecodeSigEntry(&sig); if ((entry & SIG_METHODDEF_HASTHIS) == 0) { pMsgPos = S.scatprintf(pMsgPos, pMsgEnd, "static "); } if ((entry & SIG_METHODDEF_GENERIC) != 0) { // read number of generic type args - don't care what it is MetaData.DecodeSigEntry(&sig); } numParams = MetaData.DecodeSigEntry(&sig); pParamTypeDef = Type.GetTypeFromSig(pSigMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs, null); // return type if (pParamTypeDef != null) { pMsgPos = S.scatprintf(pMsgPos, pMsgEnd, "%s ", (PTR)pParamTypeDef->name); } pMsgPos = S.scatprintf(pMsgPos, pMsgEnd, "%s.%s.%s(", (PTR)pTypeDef->nameSpace, (PTR)pTypeDef->name, (PTR)name); for (j = 0; j < numParams; j++) { pParamTypeDef = Type.GetTypeFromSig(pSigMetaData, &sig, ppClassTypeArgs, ppMethodTypeArgs, null); if (j > 0) { pMsgPos = S.scatprintf(pMsgPos, pMsgEnd, ","); } if (pParamTypeDef != null) { pMsgPos = S.scatprintf(pMsgPos, pMsgEnd, "%s", (PTR)pParamTypeDef->name); } else { pMsgPos = S.scatprintf(pMsgPos, pMsgEnd, "???"); } } Sys.Crash("FindMethodInType(): Cannot find method %s)", (PTR)pMsg); } return(null); }
// Value-Type.types will be boxed public static tAsyncCall *Internal_SetValue(tJITCallNative *pCallNative, byte *pThis_, byte *pParams, byte *pReturnValue) { tSystemArray * pArray = (tSystemArray *)pThis_; tMD_TypeDef * pArrayType, pObjType; uint index, elementSize; /*HEAP_PTR*/ byte *obj; tMD_TypeDef * pElementType; byte * pElement; pArrayType = Heap.GetType(pThis_); obj = (*((byte **)(pParams + 0))); pObjType = Heap.GetType(obj); pElementType = pArrayType->pArrayElementType; // Check to see if the Type is ok to put in the array if (!(Type.IsAssignableFrom(pElementType, pObjType) != 0 || (pElementType->pGenericDefinition == Type.types[Type.TYPE_SYSTEM_NULLABLE] && pElementType->ppClassTypeArgs[0] == pObjType))) { // Can't be done Sys.INTERNALCALL_RESULT_U32(pReturnValue, 0); return(null); } index = (*((uint *)(pParams + Sys.S_PTR))); #if WIN32 && _DEBUG // Do a bounds-check if (index >= pArray->length) { printf("[Array] Internal_SetValue() Bounds-check failed\n"); __debugbreak(); } #endif elementSize = pElementType->arrayElementSize; pElement = tSystemArray.GetElements(pArray) + elementSize * index; if (pElementType->isValueType != 0) { if (pElementType->pGenericDefinition == Type.types[Type.TYPE_SYSTEM_NULLABLE]) { // Nullable type, so treat specially if (obj == null) { Mem.memset(pElement, 0, elementSize); } else { *(uint *)pElement = 1; Mem.memcpy(pElement + 4, obj, elementSize - 4); } } else { // Get the value out of the box Mem.memcpy(pElement, obj, elementSize); } } else { // This must be a reference type, so it must be 32-bits wide *(/*HEAP_PTR*/ byte **)pElement = obj; } Sys.INTERNALCALL_RESULT_U32(pReturnValue, 1); return(null); }
public static void GarbageCollect() { #if NO tHeapRoots heapRoots; tHeapEntry * pNode; tHeapEntry **pUp = stackalloc tHeapEntry *[MAX_TREE_DEPTH * 2]; int top; tHeapEntry * pToDelete = null; SIZE_T orgHeapSize = trackHeapSize; uint orgNumNodes = numNodes; #if DIAG_GC ulong startTime; #endif Mem.heapcheck(); numCollections++; #if DIAG_GC startTime = microTime(); #endif heapRoots.capacity = 64; heapRoots.num = 0; heapRoots.pHeapEntries = (tHeapRootEntry *)Mem.malloc(heapRoots.capacity * (SIZE_T)sizeof(tHeapRootEntry)); Thread.GetHeapRoots(&heapRoots); CLIFile.GetHeapRoots(&heapRoots); // Mark phase while (heapRoots.num > 0) { tHeapRootEntry *pRootsEntry; uint i; uint moreRootsAdded = 0; uint rootsEntryNumPointers; void ** pRootsEntryMem; // Get a piece of memory off the list of heap memory roots. pRootsEntry = &heapRoots.pHeapEntries[heapRoots.num - 1]; rootsEntryNumPointers = pRootsEntry->numPointers; pRootsEntryMem = pRootsEntry->pMem; // Mark this entry as done pRootsEntry->numPointers = 0; pRootsEntry->pMem = null; // Iterate through all pointers in it for (i = 0; i < rootsEntryNumPointers; i++) { void *pMemRef = pRootsEntryMem[i]; // Quick escape for known non-memory if (pMemRef == null) { continue; } // Find this piece of heap memory in the tracking tree. // Note that the 2nd memory address comparison MUST be >, not >= as might be expected, // to allow for a zero-sized memory to be detected (and not garbage collected) properly. // E.g. The object class has zero memory. pNode = pHeapTreeRoot; while (pNode != nil) { if (pMemRef < (void *)pNode) { pNode = (tHeapEntry *)pNode->pLink[0]; } else if ((byte *)pMemRef > ((byte *)pNode) + GetSize(pNode) + sizeof(tHeapEntry)) { pNode = (tHeapEntry *)pNode->pLink[1]; } else { // Found memory. See if it's already been marked. // If it's already marked, then don't do anything. // It it's not marked, then add all of its memory to the roots, and mark it. if (pNode->marked == 0) { tMD_TypeDef *pType = pNode->pTypeDef; // Not yet marked, so mark it, and add it to heap roots. pNode->marked = 1; // Don't look at the contents of strings, arrays of primitive Type.types, or WeakReferences if (pType->stackType == EvalStack.EVALSTACK_O || pType->stackType == EvalStack.EVALSTACK_VALUETYPE || pType->stackType == EvalStack.EVALSTACK_PTR) { if (pType != Type.types[Type.TYPE_SYSTEM_STRING] && (!MetaData.TYPE_ISARRAY(pType) || pType->pArrayElementType->stackType == EvalStack.EVALSTACK_O || pType->pArrayElementType->stackType == EvalStack.EVALSTACK_VALUETYPE || pType->pArrayElementType->stackType == EvalStack.EVALSTACK_PTR)) { if (pType != Type.types[Type.TYPE_SYSTEM_WEAKREFERENCE]) { Heap.SetRoots(&heapRoots, ((byte *)&pNode->pSync + sizeof(PTR)), GetSize(pNode)); moreRootsAdded = 1; } } } } break; } } } if (moreRootsAdded == 0) { heapRoots.num--; } } Mem.free(heapRoots.pHeapEntries); // Sweep phase // Traverse nodes pUp[0] = pHeapTreeRoot; top = 1; while (top != 0) { // Get this node pNode = pUp[--top]; // Act on this node if (pNode->marked != 0) { if (pNode->marked != 0xff) { // Still in use (but not marked undeletable), so unmark pNode->marked = 0; } } else { // Not in use any more, so put in deletion queue if it does not need Finalizing // If it does need Finalizing, then don't garbage collect, and put in Finalization queue. if (pNode->needToFinalize != 0) { if (pNode->needToFinalize == 1) { Finalizer.AddFinalizer((/*HEAP_PTR*/ byte *)pNode + sizeof(tHeapEntry)); // Mark it has having been placed in the finalization queue. // When it has been finalized, then this will be set to 0 pNode->needToFinalize = 2; // If this object is being targetted by weak-ref(s), handle it if (pNode->pSync != null) { RemoveWeakRefTarget(pNode, 0); Mem.free(pNode->pSync); } } } else { // If this object is being targetted by weak-ref(s), handle it if (pNode->pSync != null) { RemoveWeakRefTarget(pNode, 1); Mem.free(pNode->pSync); } // Use pSync to point to next entry in this linked-list. pNode->pSync = (tSync *)pToDelete; pToDelete = pNode; } } // Get next node(s) if (pNode->pLink[1] != (PTR)nil) { pUp[top++] = (tHeapEntry *)pNode->pLink[1]; } if (pNode->pLink[0] != (PTR)nil) { pUp[top++] = (tHeapEntry *)pNode->pLink[0]; } } // Delete all unused memory nodes. while (pToDelete != null) { tHeapEntry *pThis = pToDelete; pToDelete = (tHeapEntry *)(pToDelete->pSync); pHeapTreeRoot = TreeRemove(pHeapTreeRoot, pThis); if (pThis->monoGCHandle == 1) { void *hptr = *(void **)((byte *)pThis + sizeof(tHeapEntry)); if (hptr != null) { GCHandle h = System.Runtime.InteropServices.GCHandle.FromIntPtr((System.IntPtr)hptr); h.Free(); } } numNodes--; trackHeapSize -= GetSize(pThis) + (uint)sizeof(tHeapEntry); Mem.free(pThis); } Mem.heapcheck(); #if DIAG_GC gcTotalTime += microTime() - startTime; #endif Sys.log_f(1, "--- GARBAGE --- [Size: %d -> %d] [Nodes: %d -> %d]\n", orgHeapSize, trackHeapSize, orgNumNodes, numNodes); #if DIAG_GC Sys.log_f(1, "GC time = %d ms\n", gcTotalTime / 1000); #endif #endif }
public static tAsyncCall *InternalReplace(tJITCallNative *pCallNative, byte *pThis_, byte *pParams, byte *pReturnValue) { tSystemString *pThis = (tSystemString *)pThis_; tSystemString *pOld = (*((tSystemString **)(pParams + 0))); tSystemString *pNew = (*((tSystemString **)(pParams + Sys.S_PTR))); tSystemString *pResult; uint thisLen, oldLen, newLen; char * pThisChar0, pOldChar0, pNewChar0, pResultChar0; uint i, j, replacements, dstIndex; uint resultLen; // This function (correctly) assumes that the old string is not empty thisLen = pThis->length; oldLen = pOld->length; newLen = pNew->length; pThisChar0 = tSystemString.GetChars(pThis); pOldChar0 = tSystemString.GetChars(pOld); pNewChar0 = tSystemString.GetChars(pNew); replacements = 0; for (i = 0; i < thisLen - oldLen + 1; i++) { uint match = 1; for (j = 0; j < oldLen; j++) { if (pThisChar0[i + j] != pOldChar0[j]) { match = 0; break; } } if (match != 0) { i += oldLen - 1; replacements++; } } resultLen = thisLen - (oldLen - newLen) * replacements; pResult = CreateStringHeapObj(resultLen); pResultChar0 = tSystemString.GetChars(pResult); dstIndex = 0; for (i = 0; i < thisLen; i++) { uint match = 1; if (i < thisLen - oldLen + 1) { for (j = 0; j < oldLen; j++) { match = 1; if (pThisChar0[i + j] != pOldChar0[j]) { match = 0; break; } } } else { match = 0; } if (match != 0) { Mem.memcpy(&pResultChar0[dstIndex], pNewChar0, newLen << 1); dstIndex += newLen; i += oldLen - 1; } else { pResultChar0[dstIndex++] = pThisChar0[i]; } } Sys.INTERNALCALL_RESULT_PTR(pReturnValue, pResult); return(null); }
public static tAsyncCall *InternalTrim(tJITCallNative *pCallNative, byte *pThis_, byte *pParams, byte *pReturnValue) { tSystemString * pThis = (tSystemString *)pThis_; /*HEAP_PTR*/ byte *pWhiteChars; uint trimType, i, j, checkCharsLen; uint ofsStart, ofsEnd; ushort * pCheckChars; uint isWhiteSpace; tSystemString *pRet; ushort c; char * pChars, pRetChars; pWhiteChars = (*((/*HEAP_PTR*/ byte **)(pParams + 0))); trimType = (*((uint *)(pParams + Sys.S_PTR))); pCheckChars = (ushort *)System_Array.GetElements(pWhiteChars); checkCharsLen = System_Array.GetLength(pWhiteChars); ofsStart = 0; ofsEnd = pThis->length; pChars = tSystemString.GetChars(pThis); if ((trimType & 1) != 0) { // Trim start for (i = ofsStart; i < ofsEnd; i++) { // Check if each char is in the array isWhiteSpace = 0; c = pChars[i]; for (j = 0; j < checkCharsLen; j++) { if (c == pCheckChars[j]) { isWhiteSpace = 1; break; } } if (isWhiteSpace == 0) { ofsStart = i; break; } } } if ((trimType & 2) != 0) { // Trim end for (i = ofsEnd - 1; i >= ofsStart; i--) { // Check if each char is in the array isWhiteSpace = 0; c = pChars[i]; for (j = 0; j < checkCharsLen; j++) { if (c == pCheckChars[j]) { isWhiteSpace = 1; break; } } if (isWhiteSpace == 0) { ofsEnd = i + 1; break; } } } pRet = CreateStringHeapObj(ofsEnd - ofsStart); pRetChars = tSystemString.GetChars(pRet); Mem.memcpy(pRetChars, &pChars[ofsStart], (SIZE_T)((ofsEnd - ofsStart) << 1)); Sys.INTERNALCALL_RESULT_PTR(pReturnValue, pRet); return(null); }