1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Runtime; 7 using System.Collections.Generic; 8 using System.Runtime.InteropServices; 9 10 using Internal.JitInterface; 11 using Internal.Runtime.Augments; 12 using Internal.Runtime.TypeLoader; 13 using Internal.TypeSystem; 14 15 using ILCompiler; 16 using ILCompiler.DependencyAnalysisFramework; 17 using ILCompiler.DependencyAnalysis; 18 19 using Debug = System.Diagnostics.Debug; 20 21 namespace Internal.Runtime.JitSupport 22 { 23 public class RyuJitExecutionStrategy : MethodExecutionStrategy 24 { 25 private CorInfoImpl _corInfoImpl; 26 private TypeSystemContext _context; 27 private NodeFactory _nodeFactory; 28 UpdateBytesUsed(ObjectNode.ObjectData nodeData, ref int bytesUsed)29 private void UpdateBytesUsed(ObjectNode.ObjectData nodeData, ref int bytesUsed) 30 { 31 bytesUsed = bytesUsed.AlignUp(nodeData.Alignment); 32 bytesUsed += nodeData.Data.Length; 33 return; 34 } 35 36 [DllImport("jitinterface")] AllocJittedCode(UInt32 cbCode, UInt32 align, out IntPtr pCodeManager)37 static extern IntPtr AllocJittedCode(UInt32 cbCode, UInt32 align, out IntPtr pCodeManager); 38 39 [DllImport("jitinterface")] SetEHInfoPtr(IntPtr pCodeManager, IntPtr pbCode, IntPtr ehInfo)40 static extern void SetEHInfoPtr(IntPtr pCodeManager, IntPtr pbCode, IntPtr ehInfo); 41 42 [DllImport("jitinterface")] PublishRuntimeFunction( IntPtr pCodeManager, IntPtr pbCode, IntPtr pMainRuntimeFunction, UInt32 startOffset, UInt32 endOffset, byte[] pUnwindInfo, UInt32 cbUnwindInfo, byte[] pGCData, UInt32 cbGCData)43 static extern unsafe IntPtr PublishRuntimeFunction( 44 IntPtr pCodeManager, 45 IntPtr pbCode, 46 IntPtr pMainRuntimeFunction, 47 UInt32 startOffset, 48 UInt32 endOffset, 49 byte[] pUnwindInfo, 50 UInt32 cbUnwindInfo, 51 byte[] pGCData, 52 UInt32 cbGCData); 53 54 [DllImport("jitinterface")] UpdateRuntimeFunctionTable(IntPtr pCodeManager)55 static extern void UpdateRuntimeFunctionTable(IntPtr pCodeManager); 56 57 [DllImport("jitinterface")] InitJitCodeManager(IntPtr mrtModule)58 static extern void InitJitCodeManager(IntPtr mrtModule); 59 OnEntryPoint(MethodEntrypointPtr methodEntrypoint, IntPtr callerArgs)60 public override IntPtr OnEntryPoint(MethodEntrypointPtr methodEntrypoint, IntPtr callerArgs) 61 { 62 lock (this) 63 { 64 if (_corInfoImpl == null) 65 { 66 InitJitCodeManager(RuntimeAugments.RhGetOSModuleForMrt ()); 67 68 // TODO: Recycle jit interface object and TypeSystemContext 69 _context = TypeSystemContextFactory.Create(); 70 71 Compilation compilation = new Compilation(_context); 72 _nodeFactory = compilation.NodeFactory; 73 74 JitConfigProvider configProvider = new JitConfigProvider(new CorJitFlag[] { CorJitFlag.CORJIT_FLAG_DEBUG_CODE }, Array.Empty<KeyValuePair<string, string>>()); 75 76 _corInfoImpl = new CorInfoImpl(compilation, configProvider); 77 } 78 79 MethodDesc methodToCompile = methodEntrypoint.MethodIdentifier.ToMethodDesc(_context); 80 81 JitMethodCodeNode codeNode = new JitMethodCodeNode(methodToCompile); 82 _corInfoImpl.CompileMethod(codeNode); 83 84 ObjectNode.ObjectData codeData = codeNode.GetData(null, false); 85 86 List<ObjectNode> nodesToEmit = new List<ObjectNode>(); 87 Dictionary<DependencyNodeCore<NodeFactory>, object> relocTargets = new Dictionary<DependencyNodeCore<NodeFactory>, object>(); 88 int totalAllocSizeNeeded = 0; 89 int nonObjectRelocTargets = 0; 90 91 nodesToEmit.Add(codeNode); 92 UpdateBytesUsed(codeNode.GetData(_nodeFactory), ref totalAllocSizeNeeded); 93 94 int offsetOfEHData = totalAllocSizeNeeded; 95 96 if (codeNode.EHInfo != null) 97 { 98 Debug.Assert(codeNode.EHInfo.Alignment == 1); // Assert needed as otherwise offsetOfEHData will be wrong 99 100 UpdateBytesUsed(codeNode.EHInfo, ref totalAllocSizeNeeded); 101 ComputeDependencySizeAndRelocData(codeNode.EHInfo, relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); 102 } 103 104 for (int i = 0; i < nodesToEmit.Count; i++) 105 { 106 ObjectNode objNode = nodesToEmit[i]; 107 ComputeDependencySizeAndRelocData(objNode.GetData(_nodeFactory, true), relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); 108 } 109 110 if (nonObjectRelocTargets != 0) 111 { 112 totalAllocSizeNeeded = totalAllocSizeNeeded.AlignUp(IntPtr.Size); 113 } 114 115 int relocTargetOffsetStart = totalAllocSizeNeeded; 116 117 DependencyNodeCore<NodeFactory>[] relocTargetsArray = new DependencyNodeCore<NodeFactory>[nonObjectRelocTargets]; 118 { 119 int iRelocTarget = 0; 120 foreach (var relocTarget in relocTargets) 121 { 122 if (!(relocTarget.Key is ObjectNode)) 123 { 124 relocTargetsArray[iRelocTarget] = relocTarget.Key; 125 totalAllocSizeNeeded += IntPtr.Size; 126 iRelocTarget++; 127 } 128 } 129 Debug.Assert(iRelocTarget == nonObjectRelocTargets); 130 } 131 132 GenericDictionaryCell[] genDictCells = new GenericDictionaryCell[relocTargetsArray.Length]; 133 for (int iRelocTarget = 0; iRelocTarget < relocTargetsArray.Length; iRelocTarget++) 134 { 135 DependencyNodeCore<NodeFactory> relocTarget = relocTargetsArray[iRelocTarget]; 136 GenericDictionaryCell newCell = null; 137 138 if (relocTarget is ExternObjectSymbolNode) 139 { 140 var externObjectSymbolNode = (ExternObjectSymbolNode)relocTarget; 141 var newMethodCell = externObjectSymbolNode.GetDictionaryCell(); 142 newCell = newMethodCell; 143 } 144 145 if (newCell == null) 146 { 147 Environment.FailFast("Unknown reloc target type"); 148 } 149 genDictCells[iRelocTarget] = newCell; 150 } 151 152 IntPtr[] relocTargetsAsIntPtr = null; 153 154 TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock( 155 () => 156 { 157 TypeBuilderApi.ResolveMultipleCells(genDictCells, out relocTargetsAsIntPtr); 158 }); 159 160 // Layout of allocated memory... 161 // ObjectNodes (aligned as appropriate) 162 IntPtr pCodeManager; 163 IntPtr jittedCode = AllocJittedCode(checked((uint)totalAllocSizeNeeded), 8/* TODO, alignment calculation */, out pCodeManager); 164 int currentOffset = 0; 165 166 foreach (var node in nodesToEmit) 167 { 168 ObjectNode.ObjectData objectData = node.GetData(_nodeFactory); 169 EmitAndRelocData(objectData, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); 170 171 // EHInfo doesn't get its own node, but it does get emitted into the stream. 172 if ((node == codeNode) && (codeNode.EHInfo != null)) 173 { 174 Debug.Assert(offsetOfEHData == currentOffset); 175 EmitAndRelocData(codeNode.EHInfo, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); 176 } 177 } 178 179 foreach (IntPtr ptr in relocTargetsAsIntPtr) 180 { 181 currentOffset = currentOffset.AlignUp(IntPtr.Size); 182 Marshal.WriteIntPtr(jittedCode, currentOffset, ptr); 183 currentOffset += IntPtr.Size; 184 } 185 186 SetEHInfoPtr(pCodeManager, jittedCode, jittedCode + offsetOfEHData); 187 188 IntPtr mainRuntimeFunction = IntPtr.Zero; 189 190 for (int i = 0; i < codeNode.FrameInfos.Length; i++) 191 { 192 FrameInfo frame = codeNode.FrameInfos[i]; 193 byte[] frameData = frame.BlobData; 194 byte[] gcInfoData = Array.Empty<byte>(); 195 byte[] gcInfoDataDeref = frameData; 196 197 if (i == 0) 198 { 199 // For main function, add the gc info to the data 200 gcInfoDataDeref = gcInfoData = codeNode.GCInfo; 201 } 202 203 IntPtr publishedFunction = PublishRuntimeFunction(pCodeManager, 204 jittedCode, 205 mainRuntimeFunction, 206 checked((uint)frame.StartOffset), 207 checked((uint)frame.EndOffset), 208 frameData, 209 checked((uint)frameData.Length), 210 gcInfoDataDeref, 211 checked((uint)gcInfoData.Length)); 212 213 if (i == 0) 214 { 215 mainRuntimeFunction = publishedFunction; 216 } 217 } 218 219 if (mainRuntimeFunction != IntPtr.Zero) 220 { 221 UpdateRuntimeFunctionTable(pCodeManager); 222 } 223 224 methodEntrypoint.MethodCode = jittedCode; 225 226 return jittedCode; 227 } 228 } 229 ComputeDependencySizeAndRelocData(ObjectNode.ObjectData objectData, Dictionary<DependencyNodeCore<NodeFactory>, object> relocTargets, List<ObjectNode> nodesToEmit, ref int totalAllocSizeNeeded, ref int nonObjectRelocTargets)230 void ComputeDependencySizeAndRelocData(ObjectNode.ObjectData objectData, Dictionary<DependencyNodeCore<NodeFactory>, object> relocTargets, List<ObjectNode> nodesToEmit, ref int totalAllocSizeNeeded, ref int nonObjectRelocTargets) 231 { 232 foreach (var reloc in objectData.Relocs) 233 { 234 DependencyNodeCore<NodeFactory> relocTargetAsNode = (DependencyNodeCore<NodeFactory>)reloc.Target; 235 236 if (!relocTargets.ContainsKey(relocTargetAsNode)) 237 { 238 relocTargets.Add(relocTargetAsNode, null); 239 ObjectNode relocTargetObjectNode = relocTargetAsNode as ObjectNode; 240 if (relocTargetObjectNode != null) 241 { 242 UpdateBytesUsed(relocTargetObjectNode.GetData(_nodeFactory), ref totalAllocSizeNeeded); 243 nodesToEmit.Add(relocTargetObjectNode); 244 } 245 else 246 { 247 nonObjectRelocTargets++; 248 } 249 } 250 } 251 } 252 EmitAndRelocData(ObjectNode.ObjectData objectData, IntPtr jittedCode, int relocTargetOffsetStart, ref int currentOffset, DependencyNodeCore<NodeFactory>[] relocTargetsArray, IntPtr[] relocTargetsAsIntPtr)253 void EmitAndRelocData(ObjectNode.ObjectData objectData, IntPtr jittedCode, int relocTargetOffsetStart, ref int currentOffset, DependencyNodeCore<NodeFactory>[] relocTargetsArray, IntPtr[] relocTargetsAsIntPtr) 254 { 255 currentOffset = currentOffset.AlignUp(objectData.Alignment); 256 Marshal.Copy(objectData.Data, 0, jittedCode + currentOffset, objectData.Data.Length); 257 foreach (Relocation reloc in objectData.Relocs) 258 { 259 switch (reloc.RelocType) 260 { 261 case RelocType.IMAGE_REL_BASED_REL32: 262 // 4 byte offset from current pointer to target 263 // ADD ROUTINE TO FIND Relocation 264 for (int i = 0; i < relocTargetsArray.Length; i++) 265 { 266 if (relocTargetsArray[i] == reloc.Target) 267 { 268 int relocTargetAddressOffset = relocTargetOffsetStart + i * IntPtr.Size; 269 int relocAddressOffset = currentOffset + reloc.Offset; 270 271 int relocTargetAddressDelta = relocTargetAddressOffset - relocAddressOffset - 4; 272 Marshal.WriteInt32(jittedCode, relocAddressOffset, relocTargetAddressDelta); 273 break; 274 } 275 } 276 break; 277 278 default: 279 Environment.FailFast("Unknown RelocType"); 280 break; 281 } 282 } 283 284 currentOffset += objectData.Data.Length; 285 } 286 } 287 } 288