void ComputeDependencySizeAndRelocData(ObjectNode.ObjectData objectData, Dictionary <DependencyNodeCore <NodeFactory>, object> relocTargets, List <ObjectNode> nodesToEmit, ref int totalAllocSizeNeeded, ref int nonObjectRelocTargets) { foreach (var reloc in objectData.Relocs) { DependencyNodeCore <NodeFactory> relocTargetAsNode = (DependencyNodeCore <NodeFactory>)reloc.Target; if (!relocTargets.ContainsKey(relocTargetAsNode)) { relocTargets.Add(relocTargetAsNode, null); ObjectNode relocTargetObjectNode = relocTargetAsNode as ObjectNode; if (relocTargetObjectNode != null) { UpdateBytesUsed(relocTargetObjectNode.GetData(_nodeFactory), ref totalAllocSizeNeeded); nodesToEmit.Add(relocTargetObjectNode); } else { nonObjectRelocTargets++; } } } }
private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) { // virtual slots var nodeData = node.GetData(factory, false); CppGenerationBuffer nodeCode = new CppGenerationBuffer(); /* Create list of byte data. Used to divide contents between reloc and byte data * First val - isReloc * Second val - size of byte data if first value of tuple is false */ List<NodeDataSection> nodeDataSections = new List<NodeDataSection>(); byte[] actualData = new byte[nodeData.Data.Length]; Relocation[] relocs = nodeData.Relocs; int nextRelocOffset = -1; int nextRelocIndex = -1; int lastByteIndex = 0; if (relocs.Length > 0) { nextRelocOffset = relocs[0].Offset; nextRelocIndex = 0; } int i = 0; int offset = 0; CppGenerationBuffer nodeDataDecl = new CppGenerationBuffer(); if (node is ISymbolNode) { offset = (node as ISymbolNode).Offset; i = offset; lastByteIndex = offset; } while (i < nodeData.Data.Length) { if (i == nextRelocOffset) { Relocation reloc = relocs[nextRelocIndex]; int size = _compilation.TypeSystemContext.Target.PointerSize; // Make sure we've gotten the correct size for the reloc System.Diagnostics.Debug.Assert(reloc.RelocType == (size == 8 ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW)); // Update nextRelocIndex/Offset if (++nextRelocIndex < relocs.Length) { nextRelocOffset = relocs[nextRelocIndex].Offset; } nodeDataSections.Add(new NodeDataSection(NodeDataSectionType.Relocation, size)); i += size; lastByteIndex = i; } else { i++; if (i + 1 == nextRelocOffset || i + 1 == nodeData.Data.Length) { nodeDataSections.Add(new NodeDataSection(NodeDataSectionType.ByteData, (i + 1) - lastByteIndex)); } } } string pointerType = node is EETypeNode ? "MethodTable * " : "void* "; nodeCode.Append(pointerType); if (node is EETypeNode) { nodeCode.Append(GetCppMethodDeclarationName((node as EETypeNode).Type, "__getMethodTable")); } else { string mangledName = ((ISymbolNode)node).GetMangledName(); // Rename generic composition and optional fields nodes to avoid name clash with types bool shouldReplaceNamespaceQualifier = node is GenericCompositionNode || node is EETypeOptionalFieldsNode; nodeCode.Append(shouldReplaceNamespaceQualifier ? mangledName.Replace("::", "_") : mangledName); } nodeCode.Append("()"); nodeCode.AppendLine(); nodeCode.Append("{"); nodeCode.Indent(); nodeCode.AppendLine(); nodeCode.Append("static struct {"); nodeCode.AppendLine(); nodeCode.Append(GetCodeForNodeStruct(nodeDataSections, node)); nodeCode.AppendLine(); nodeCode.Append("} mt = {"); nodeCode.Append(GetCodeForNodeData(nodeDataSections, relocs, nodeData.Data, node, offset, factory)); nodeCode.Append("};"); nodeCode.AppendLine(); nodeCode.Append("return ( "); nodeCode.Append(pointerType); nodeCode.Append(")&mt;"); nodeCode.Exdent(); nodeCode.AppendLine(); nodeCode.Append("}"); nodeCode.AppendLine(); return nodeCode.ToString(); }
private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) { // virtual slots var nodeData = node.GetData(factory, false); CppGenerationBuffer nodeCode = new CppGenerationBuffer(); /* Create list of byte data. Used to divide contents between reloc and byte data * First val - isReloc * Second val - size of byte data if first value of tuple is false */ List <NodeDataSection> nodeDataSections = new List <NodeDataSection>(); byte[] actualData = new byte[nodeData.Data.Length]; Relocation[] relocs = nodeData.Relocs; int nextRelocOffset = -1; int nextRelocIndex = -1; int lastByteIndex = 0; if (relocs.Length > 0) { nextRelocOffset = relocs[0].Offset; nextRelocIndex = 0; } int i = 0; int offset = 0; CppGenerationBuffer nodeDataDecl = new CppGenerationBuffer(); if (node is ISymbolDefinitionNode) { offset = (node as ISymbolDefinitionNode).Offset; i = offset; lastByteIndex = offset; } while (i < nodeData.Data.Length) { if (i == nextRelocOffset) { Relocation reloc = relocs[nextRelocIndex]; int size = _compilation.TypeSystemContext.Target.PointerSize; // Make sure we've gotten the correct size for the reloc System.Diagnostics.Debug.Assert(reloc.RelocType == (size == 8 ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW)); // Update nextRelocIndex/Offset if (++nextRelocIndex < relocs.Length) { nextRelocOffset = relocs[nextRelocIndex].Offset; } nodeDataSections.Add(new NodeDataSection(NodeDataSectionType.Relocation, size)); i += size; lastByteIndex = i; } else { i++; if (i + 1 == nextRelocOffset || i + 1 == nodeData.Data.Length) { nodeDataSections.Add(new NodeDataSection(NodeDataSectionType.ByteData, (i + 1) - lastByteIndex)); } } } string pointerType = node is EETypeNode ? "MethodTable * " : "void* "; nodeCode.Append(pointerType); if (node is EETypeNode) { nodeCode.Append(GetCppMethodDeclarationName((node as EETypeNode).Type, "__getMethodTable")); } else { string mangledName = ((ISymbolNode)node).GetMangledName(factory.NameMangler); // Rename generic composition and optional fields nodes to avoid name clash with types bool shouldReplaceNamespaceQualifier = node is GenericCompositionNode || node is EETypeOptionalFieldsNode; nodeCode.Append(shouldReplaceNamespaceQualifier ? mangledName.Replace("::", "_") : mangledName); } nodeCode.Append("()"); nodeCode.AppendLine(); nodeCode.Append("{"); nodeCode.Indent(); nodeCode.AppendLine(); nodeCode.Append("static struct {"); nodeCode.AppendLine(); nodeCode.Append(GetCodeForNodeStruct(nodeDataSections, node)); nodeCode.AppendLine(); nodeCode.Append("} mt = {"); nodeCode.Append(GetCodeForNodeData(nodeDataSections, relocs, nodeData.Data, node, offset, factory)); nodeCode.Append("};"); nodeCode.AppendLine(); nodeCode.Append("return ( "); nodeCode.Append(pointerType); nodeCode.Append(")&mt;"); nodeCode.Exdent(); nodeCode.AppendLine(); nodeCode.Append("}"); nodeCode.AppendLine(); return(nodeCode.ToString()); }
public override IntPtr OnEntryPoint(MethodEntrypointPtr methodEntrypoint, IntPtr callerArgs) { lock (this) { if (_corInfoImpl == null) { InitJitCodeManager(RuntimeAugments.RhGetOSModuleForMrt()); // TODO: Recycle jit interface object and TypeSystemContext _context = TypeSystemContextFactory.Create(); Compilation compilation = new Compilation(_context); _nodeFactory = compilation.NodeFactory; JitConfigProvider configProvider = new JitConfigProvider(new CorJitFlag[] { CorJitFlag.CORJIT_FLAG_DEBUG_CODE }, Array.Empty <KeyValuePair <string, string> >()); _corInfoImpl = new CorInfoImpl(compilation, configProvider); } MethodDesc methodToCompile = methodEntrypoint.MethodIdentifier.ToMethodDesc(_context); JitMethodCodeNode codeNode = new JitMethodCodeNode(methodToCompile); _corInfoImpl.CompileMethod(codeNode); ObjectNode.ObjectData codeData = codeNode.GetData(null, false); List <ObjectNode> nodesToEmit = new List <ObjectNode>(); Dictionary <DependencyNodeCore <NodeFactory>, object> relocTargets = new Dictionary <DependencyNodeCore <NodeFactory>, object>(); int totalAllocSizeNeeded = 0; int nonObjectRelocTargets = 0; nodesToEmit.Add(codeNode); UpdateBytesUsed(codeNode.GetData(_nodeFactory), ref totalAllocSizeNeeded); int offsetOfEHData = totalAllocSizeNeeded; if (codeNode.EHInfo != null) { Debug.Assert(codeNode.EHInfo.Alignment == 1); // Assert needed as otherwise offsetOfEHData will be wrong UpdateBytesUsed(codeNode.EHInfo, ref totalAllocSizeNeeded); ComputeDependencySizeAndRelocData(codeNode.EHInfo, relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); } for (int i = 0; i < nodesToEmit.Count; i++) { ObjectNode objNode = nodesToEmit[i]; ComputeDependencySizeAndRelocData(objNode.GetData(_nodeFactory, true), relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); } if (nonObjectRelocTargets != 0) { totalAllocSizeNeeded = totalAllocSizeNeeded.AlignUp(IntPtr.Size); } int relocTargetOffsetStart = totalAllocSizeNeeded; DependencyNodeCore <NodeFactory>[] relocTargetsArray = new DependencyNodeCore <NodeFactory> [nonObjectRelocTargets]; { int iRelocTarget = 0; foreach (var relocTarget in relocTargets) { if (!(relocTarget.Key is ObjectNode)) { relocTargetsArray[iRelocTarget] = relocTarget.Key; totalAllocSizeNeeded += IntPtr.Size; iRelocTarget++; } } Debug.Assert(iRelocTarget == nonObjectRelocTargets); } GenericDictionaryCell[] genDictCells = new GenericDictionaryCell[relocTargetsArray.Length]; for (int iRelocTarget = 0; iRelocTarget < relocTargetsArray.Length; iRelocTarget++) { DependencyNodeCore <NodeFactory> relocTarget = relocTargetsArray[iRelocTarget]; GenericDictionaryCell newCell = null; if (relocTarget is ExternObjectSymbolNode) { var externObjectSymbolNode = (ExternObjectSymbolNode)relocTarget; var newMethodCell = externObjectSymbolNode.GetDictionaryCell(); newCell = newMethodCell; } if (newCell == null) { Environment.FailFast("Unknown reloc target type"); } genDictCells[iRelocTarget] = newCell; } IntPtr[] relocTargetsAsIntPtr = null; TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock( () => { TypeBuilderApi.ResolveMultipleCells(genDictCells, out relocTargetsAsIntPtr); }); // Layout of allocated memory... // ObjectNodes (aligned as appropriate) IntPtr pCodeManager; IntPtr jittedCode = AllocJittedCode(checked ((uint)totalAllocSizeNeeded), 8 /* TODO, alignment calculation */, out pCodeManager); int currentOffset = 0; foreach (var node in nodesToEmit) { ObjectNode.ObjectData objectData = node.GetData(_nodeFactory); EmitAndRelocData(objectData, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); // EHInfo doesn't get its own node, but it does get emitted into the stream. if ((node == codeNode) && (codeNode.EHInfo != null)) { Debug.Assert(offsetOfEHData == currentOffset); EmitAndRelocData(codeNode.EHInfo, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); } } foreach (IntPtr ptr in relocTargetsAsIntPtr) { currentOffset = currentOffset.AlignUp(IntPtr.Size); Marshal.WriteIntPtr(jittedCode, currentOffset, ptr); currentOffset += IntPtr.Size; } SetEHInfoPtr(pCodeManager, jittedCode, jittedCode + offsetOfEHData); IntPtr mainRuntimeFunction = IntPtr.Zero; for (int i = 0; i < codeNode.FrameInfos.Length; i++) { FrameInfo frame = codeNode.FrameInfos[i]; byte[] frameData = frame.BlobData; byte[] gcInfoData = Array.Empty <byte>(); byte[] gcInfoDataDeref = frameData; if (i == 0) { // For main function, add the gc info to the data gcInfoDataDeref = gcInfoData = codeNode.GCInfo; } IntPtr publishedFunction = PublishRuntimeFunction(pCodeManager, jittedCode, mainRuntimeFunction, checked ((uint)frame.StartOffset), checked ((uint)frame.EndOffset), frameData, checked ((uint)frameData.Length), gcInfoDataDeref, checked ((uint)gcInfoData.Length)); if (i == 0) { mainRuntimeFunction = publishedFunction; } } if (mainRuntimeFunction != IntPtr.Zero) { UpdateRuntimeFunctionTable(pCodeManager); } methodEntrypoint.MethodCode = jittedCode; return(jittedCode); } }