public static tMetaData *GetResolutionScopeMetaData(tMetaData *pMetaData, /*IDX_TABLE*/ uint resolutionScopeToken, tMD_TypeDef **ppInNestedType) { switch (MetaData.TABLE_ID(resolutionScopeToken)) { case MetaDataTable.MD_TABLE_ASSEMBLYREF: { tMD_AssemblyRef *pAssemblyRef; pAssemblyRef = (tMD_AssemblyRef *)MetaData.GetTableRow(pMetaData, resolutionScopeToken); *ppInNestedType = null; return(CLIFile.GetMetaDataForAssembly(pAssemblyRef->name)); } case MetaDataTable.MD_TABLE_TYPEREF: { tMD_TypeDef *pTypeDef; pTypeDef = MetaData.GetTypeDefFromDefRefOrSpec(pMetaData, resolutionScopeToken, null, null); *ppInNestedType = pTypeDef; return(pTypeDef->pMetaData); } default: Sys.Crash("MetaData.GetResolutionScopeMetaData(): Cannot resolve token: 0x%08x", resolutionScopeToken); return(null); } }
public static tMD_TypeDef *GetTypeDefFromFullName(/*STRING*/ byte *assemblyName, /*STRING*/ byte *nameSpace, /*STRING*/ byte *name) { tMetaData *pTypeMetaData; pTypeMetaData = CLIFile.GetMetaDataForAssembly(assemblyName); // Note that this cannot get a nested class, as this final parameter is always null return(MetaData.GetTypeDefFromName(pTypeMetaData, nameSpace, name, null, /* assertExists */ 1)); }
/// <summary> /// Returns a DNA TypeDef for a given type. /// </summary> /// <param name="type">The fully qualified name of the type (namespace and type name)</param> /// <returns>The TypeDef or 0 if no type by that name was found</returns> public static ulong FindType(string type) { byte *className = stackalloc byte[128]; byte *nameSpace = stackalloc byte[128]; if (!_isInitialized) { Init(); } string[] split = type.Split('.'); if (split.Length < 1) { throw new System.ArgumentException("Type must have at least a type name"); } if (split.Length > 1) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0; i < split.Length - 1; i++) { if (i > 0) { sb.Append('.'); } sb.Append(split[i]); } S.strncpy(nameSpace, sb.ToString(), 128); } else { nameSpace[0] = 0; } S.strncpy(className, split[split.Length - 1], 128); // Find any overload of the named method; assume it's the right one. // Specifying it exactly (type generic args, method generic args, arguments themselves, picking the // inherited methods if needed), is complex and not required at the moment. tMD_TypeDef *pTypeDef = CLIFile.FindTypeInAllLoadedAssemblies(nameSpace, className); if (pTypeDef->fillState < Type.TYPE_FILL_ALL) { MetaData.Fill_TypeDef(pTypeDef, null, null); } return((ulong)pTypeDef); }
/// <summary> /// Initializes the DNA script engine. /// </summary> /// <param name="memsize">The heap memory size to use (note: can not be expanded)</param> /// <param name="assemblySearchPaths">Array of assembly search paths to use when loading assemblies</param> public static void Init(int memsize = DEFAULT_MEM_SIZE, string[] assemblySearchPaths = null) { if (_isInitialized) { throw new System.InvalidOperationException("Dna has already been initialized. Use Dna.Reset() to reset the interpreter"); } if (assemblySearchPaths == null) { assemblySearchPaths = defaultAssemblySearchPaths; } #if UNITY_EDITOR string[] finalAssemblySearchPaths = new string[assemblySearchPaths.Length]; string unityDir = UnityEditor.EditorApplication.applicationContentsPath; string projectDir = System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath); for (int i = 0; i < assemblySearchPaths.Length; i++) { finalAssemblySearchPaths[i] = assemblySearchPaths[i] .Replace("${UNITY_DIR}", unityDir) .Replace("${PROJECT_DIR}", projectDir); } #else string[] finalAssemblySearchPaths = assemblySearchPaths; #endif Mem.Init(memsize); H.Init(); Sys.Init(); JIT.Init(); JIT_Execute.Init(); DnaObject.Init(); MetaData.Init(); MonoType.Init(); Generics.Init(); Serialization.Init(); Heap.Init(); Finalizer.Init(); InternalCall.Init(); CLIFile.Init(finalAssemblySearchPaths); Type.Init(); _isInitialized = true; }
/// <summary> /// Resets entire DNA environment to it's initial state, clearing all DnaObject references to null. /// </summary> public static void Reset() { Type.Clear(); CLIFile.Clear(); InternalCall.Clear(); Finalizer.Clear(); Heap.Clear(); Generics.Clear(); MonoType.Clear(); MetaData.Clear(); DnaObject.Clear(); JIT_Execute.Clear(); JIT.Clear(); Sys.Clear(); H.Clear(); Mem.Clear(); _isInitialized = false; }
static int InternalLoadAndRun(bool tryRun, string[] args) { if (!_isInitialized) { Init(); } /*char**/ byte *pFileName = new S(args[0]); 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, args); } 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 tMetaData *GetMetaDataForAssembly(byte *pAssemblyName) { tFilesLoaded *pFiles; int monoAssembly = 0; tCLIFile * pCLIFile = null; tMD_Assembly *pThisAssembly = null; tMetaData ** ppChildMetaData = null; int i, j, childCount; // Check corlib assemblies i = 0; while (dnaCorlibAssemblies[i] != null) { if (S.strcmp(pAssemblyName, dnaCorlibAssemblies[i]) == 0) { pAssemblyName = scCorLib; break; } i++; } // Look in already-loaded files first pFiles = pFilesLoaded; while (pFiles != null) { pCLIFile = pFiles->pCLIFile; if (S.strcmp(pAssemblyName, pCLIFile->assemblyName) == 0) { // Found the correct assembly, so return its meta-data return(pCLIFile->pMetaData); } pFiles = pFiles->pNext; } // Mono/Unity assemblies only load metadata, no code if (monoAssemblies != null) { i = 0; while (monoAssemblies[i] != null) { if (S.strcmp(pAssemblyName, monoAssemblies[i]) == 0) { if (i == 0) { // Handle "UnityEngine" assemblies j = 0; childCount = 0; while (unityModuleAssemblies[j] != null) { childCount++; j++; } ppChildMetaData = (tMetaData **)Mem.malloc((SIZE_T)((childCount + 1) * sizeof(tMetaData *))); Mem.memset(ppChildMetaData, 0, (SIZE_T)((childCount + 1) * sizeof(tMetaData *))); j = 0; while (unityModuleAssemblies[j] != null) { ppChildMetaData[j] = GetMetaDataForAssembly(unityModuleAssemblies[j]); j++; } } monoAssembly = 1; break; } i++; } } // Assembly not loaded, so load it if possible if (monoAssembly != 0) { pCLIFile = CLIFile.WrapMonoAssembly(pAssemblyName); if (pCLIFile == null) { Sys.Crash("Cannot load required mono assembly file: %s.dll", (PTR)pAssemblyName); } } else { byte *fileName = stackalloc byte[256]; S.snprintf(fileName, 256, "%s.dll", (PTR)pAssemblyName); pCLIFile = CLIFile.LoadAssembly(fileName); if (pCLIFile == null) { Sys.Crash("Cannot load required assembly file: %s.dll", (PTR)pAssemblyName); } } pCLIFile->pMetaData->ppChildMetaData = ppChildMetaData; return(pCLIFile->pMetaData); }
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->monoHandle == 1) { void *hptr = *(void **)((byte *)pThis + sizeof(tHeapEntry)); if (hptr != null) { H.Free(hptr); } } 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 }