protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { using (PerfEventSource.StartStopEvents.JitEvents()) { ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = _parallelism }; Parallel.ForEach(obj, options, dependency => { MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; MethodDesc method = methodCodeNodeNeedingCode.Method; if (Logger.IsVerbose) { string methodName = method.ToString(); Logger.Writer.WriteLine("Compiling " + methodName); } try { using (PerfEventSource.StartStopEvents.JitMethodEvents()) { CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); corInfoImpl.CompileMethod(methodCodeNodeNeedingCode); } } catch (TypeSystemException ex) { // If compilation fails, don't emit code for this method. It will be Jitted at runtime Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); } catch (RequiresRuntimeJitException ex) { Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } catch (CodeGenerationFailedException ex) when(_resilient) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } }); } if (_methodILCache.Count > 1000) { _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup); } }
protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (DependencyNodeCore <NodeFactory> dependency in obj) { var methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; if (methodCodeNodeNeedingCode == null) { // To compute dependencies of the shadow method that tracks dictionary // dependencies we need to ensure there is code for the canonical method body. var dependencyMethod = (ShadowConcreteMethodNode)dependency; methodCodeNodeNeedingCode = (MethodWithGCInfo)dependencyMethod.CanonicalMethodNode; } // We might have already compiled this method. if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed) { continue; } MethodDesc method = methodCodeNodeNeedingCode.Method; if (!NodeFactory.CompilationModuleGroup.ContainsMethodBody(method, unboxingStub: false)) { // Don't drill into methods defined outside of this version bubble continue; } if (Logger.IsVerbose) { string methodName = method.ToString(); Logger.Writer.WriteLine("Compiling " + methodName); } try { _corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (TypeSystemException ex) { // If compilation fails, don't emit code for this method. It will be Jitted at runtime Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); } catch (RequiresRuntimeJitException ex) { Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } }
private void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (MethodCodeNode methodCodeNodeNeedingCode in obj) { MethodDesc method = methodCodeNodeNeedingCode.Method; string methodName = method.ToString(); Log.WriteLine("Compiling " + methodName); var methodIL = GetMethodIL(method); if (methodIL == null) { return; } try { _corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (Exception e) { Log.WriteLine("*** " + method + ": " + e.Message); // Call the __not_yet_implemented method DependencyAnalysis.X64.X64Emitter emit = new DependencyAnalysis.X64.X64Emitter(_nodeFactory); emit.Builder.RequireAlignment(_nodeFactory.Target.MinimumFunctionAlignment); emit.Builder.DefinedSymbols.Add(methodCodeNodeNeedingCode); emit.EmitLEAQ(emit.TargetRegister.Arg0, _nodeFactory.StringIndirection(method.ToString())); DependencyAnalysis.X64.AddrMode loadFromArg0 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg0, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitLEAQ(emit.TargetRegister.Arg1, _nodeFactory.StringIndirection(e.Message)); DependencyAnalysis.X64.AddrMode loadFromArg1 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg1, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitJMP(_nodeFactory.ExternSymbol("__not_yet_implemented")); methodCodeNodeNeedingCode.SetCode(emit.Builder.ToObjectData()); continue; } } }
protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { using (PerfEventSource.StartStopEvents.JitEvents()) { ConditionalWeakTable <Thread, CorInfoImpl> cwt = new ConditionalWeakTable <Thread, CorInfoImpl>(); foreach (DependencyNodeCore <NodeFactory> dependency in obj) { MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; MethodDesc method = methodCodeNodeNeedingCode.Method; if (Logger.IsVerbose) { string methodName = method.ToString(); Logger.Writer.WriteLine("Compiling " + methodName); } try { using (PerfEventSource.StartStopEvents.JitMethodEvents()) { CorInfoImpl corInfoImpl = cwt.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); corInfoImpl.CompileMethod(methodCodeNodeNeedingCode); } } catch (TypeSystemException ex) { // If compilation fails, don't emit code for this method. It will be Jitted at runtime Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); } catch (RequiresRuntimeJitException ex) { Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } catch (CodeGenerationFailedException ex) when(_resilient) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } } }
protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { using (PerfEventSource.StartStopEvents.JitEvents()) { Action <DependencyNodeCore <NodeFactory> > compileOneMethod = (DependencyNodeCore <NodeFactory> dependency) => { MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; if (methodCodeNodeNeedingCode == null) { if (dependency is DeferredTillPhaseNode deferredPhaseNode) { if (Logger.IsVerbose) { _logger.Writer.WriteLine($"Moved to phase {_nodeFactory.CompilationCurrentPhase}"); } deferredPhaseNode.NotifyCurrentPhase(_nodeFactory.CompilationCurrentPhase); return; } } Debug.Assert((_nodeFactory.CompilationCurrentPhase == 0) || ((_nodeFactory.CompilationCurrentPhase == 2) && !_finishedFirstCompilationRunInPhase2)); MethodDesc method = methodCodeNodeNeedingCode.Method; if (Logger.IsVerbose) { string methodName = method.ToString(); Logger.Writer.WriteLine("Compiling " + methodName); } if (_printReproInstructions != null) { Logger.Writer.WriteLine($"Single method repro args:{_printReproInstructions(method)}"); } try { using (PerfEventSource.StartStopEvents.JitMethodEvents()) { // Create only 1 CorInfoImpl per thread. // This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); corInfoImpl.CompileMethod(methodCodeNodeNeedingCode, Logger); } } catch (TypeSystemException ex) { // If compilation fails, don't emit code for this method. It will be Jitted at runtime if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); } } catch (RequiresRuntimeJitException ex) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } catch (CodeGenerationFailedException ex) when(_resilient) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } }; // Use only main thread to compile if parallelism is 1. This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Processing {obj.Count} dependencies"); } if (_parallelism == 1) { foreach (var dependency in obj) { compileOneMethod(dependency); } } else { ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = _parallelism }; Parallel.ForEach(obj, options, compileOneMethod); } } if (_methodILCache.Count > 1000) { _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup); } if (_nodeFactory.CompilationCurrentPhase == 2) { _finishedFirstCompilationRunInPhase2 = true; } }
protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { using (PerfEventSource.StartStopEvents.JitEvents()) { // Use only main thread to compile if parallelism is 1. This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Processing {obj.Count} dependencies"); } // Ensure all methods being compiled have assigned tokens. This matters for code from modules from outside of the version bubble // as those tokens are dynamically assigned, and for instantiation which depend on tokens outside of the module var ilProvider = (ReadyToRunILProvider)_methodILCache.ILProvider; obj.MergeSortAllowDuplicates(new SortableDependencyNode.ObjectNodeComparer(CompilerComparer.Instance)); foreach (var dependency in obj) { if (dependency is MethodWithGCInfo methodCodeNodeNeedingCode) { var method = methodCodeNodeNeedingCode.Method; if (method.GetTypicalMethodDefinition() is EcmaMethod ecmaMethod) { if (ilProvider.NeedsCrossModuleInlineableTokens(ecmaMethod) && !_methodsWhichNeedMutableILBodies.Contains(ecmaMethod) && CorInfoImpl.IsMethodCompilable(this, methodCodeNodeNeedingCode.Method)) { _methodsWhichNeedMutableILBodies.Add(ecmaMethod); } } if (!_nodeFactory.CompilationModuleGroup.VersionsWithMethodBody(method)) { // Validate that the typedef tokens for all of the instantiation parameters of the method // have tokens. foreach (var type in method.Instantiation) { EnsureTypeDefTokensAreReady(type); } foreach (var type in method.OwningType.Instantiation) { EnsureTypeDefTokensAreReady(type); } void EnsureTypeDefTokensAreReady(TypeDesc type) { // Type represented by simple element type if (type.IsPrimitive || type.IsVoid || type.IsObject || type.IsString || type.IsTypedReference) { return; } if (type is EcmaType ecmaType) { if (!_nodeFactory.Resolver.GetModuleTokenForType(ecmaType, allowDynamicallyCreatedReference: false, throwIfNotFound: false).IsNull) { return; } try { Debug.Assert(_nodeFactory.CompilationModuleGroup.CrossModuleInlineableModule(ecmaType.Module)); _nodeFactory.ManifestMetadataTable._mutableModule.ModuleThatIsCurrentlyTheSourceOfNewReferences = ecmaType.Module; if (!_nodeFactory.ManifestMetadataTable._mutableModule.TryGetEntityHandle(ecmaType).HasValue) { throw new InternalCompilerErrorException($"Unable to create token to {ecmaType}"); } } finally { _nodeFactory.ManifestMetadataTable._mutableModule.ModuleThatIsCurrentlyTheSourceOfNewReferences = null; } return; } if (type.HasInstantiation) { EnsureTypeDefTokensAreReady(type.GetTypeDefinition()); foreach (TypeDesc instParam in type.Instantiation) { EnsureTypeDefTokensAreReady(instParam); } } else if (type.IsParameterizedType) { EnsureTypeDefTokensAreReady(type.GetParameterType()); } } } } } ProcessMutableMethodBodiesList(); ResetILCache(); CompileMethodList(obj); while (_methodsToRecompile.Count > 0) { ProcessMutableMethodBodiesList(); ResetILCache(); MethodWithGCInfo[] methodsToRecompile = new MethodWithGCInfo[_methodsToRecompile.Count]; _methodsToRecompile.CopyTo(methodsToRecompile); _methodsToRecompile.Clear(); Array.Sort(methodsToRecompile, new SortableDependencyNode.ObjectNodeComparer(CompilerComparer.Instance)); if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Processing {methodsToRecompile.Length} recompiles"); } CompileMethodList(methodsToRecompile); } } ResetILCache(); if (_nodeFactory.CompilationCurrentPhase == 2) { _finishedFirstCompilationRunInPhase2 = true; } void ProcessMutableMethodBodiesList() { EcmaMethod[] mutableMethodBodyNeedList = new EcmaMethod[_methodsWhichNeedMutableILBodies.Count]; _methodsWhichNeedMutableILBodies.CopyTo(mutableMethodBodyNeedList); _methodsWhichNeedMutableILBodies.Clear(); TypeSystemComparer comparer = TypeSystemComparer.Instance; Comparison <EcmaMethod> comparison = (EcmaMethod a, EcmaMethod b) => comparer.Compare(a, b); Array.Sort(mutableMethodBodyNeedList, comparison); var ilProvider = (ReadyToRunILProvider)_methodILCache.ILProvider; foreach (var method in mutableMethodBodyNeedList) { ilProvider.CreateCrossModuleInlineableTokensForILBody(method); } } void ResetILCache() { if (_methodILCache.Count > 1000 || _methodILCache.ILProvider.Version != _methodILCache.ExpectedILProviderVersion) { _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup); } } void CompileMethodList(IEnumerable <DependencyNodeCore <NodeFactory> > methodList) { // Disable generation of new tokens across the multi-threaded compile NodeFactory.ManifestMetadataTable._mutableModule.DisableNewTokens = true; if (_parallelism == 1) { foreach (var dependency in methodList) { CompileOneMethod(dependency); } } else { ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = _parallelism }; Parallel.ForEach(methodList, options, CompileOneMethod); } // Re-enable generation of new tokens after the multi-threaded compile NodeFactory.ManifestMetadataTable._mutableModule.DisableNewTokens = false; } void CompileOneMethod(DependencyNodeCore <NodeFactory> dependency) { MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; if (methodCodeNodeNeedingCode == null) { if (dependency is DeferredTillPhaseNode deferredPhaseNode) { if (Logger.IsVerbose) { _logger.Writer.WriteLine($"Moved to phase {_nodeFactory.CompilationCurrentPhase}"); } deferredPhaseNode.NotifyCurrentPhase(_nodeFactory.CompilationCurrentPhase); return; } } Debug.Assert((_nodeFactory.CompilationCurrentPhase == 0) || ((_nodeFactory.CompilationCurrentPhase == 2) && !_finishedFirstCompilationRunInPhase2)); MethodDesc method = methodCodeNodeNeedingCode.Method; if (Logger.IsVerbose) { string methodName = method.ToString(); Logger.Writer.WriteLine("Compiling " + methodName); } if (_printReproInstructions != null) { Logger.Writer.WriteLine($"Single method repro args:{_printReproInstructions(method)}"); } try { using (PerfEventSource.StartStopEvents.JitMethodEvents()) { // Create only 1 CorInfoImpl per thread. // This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); corInfoImpl.CompileMethod(methodCodeNodeNeedingCode, Logger); } } catch (TypeSystemException ex) { // If compilation fails, don't emit code for this method. It will be Jitted at runtime if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); } } catch (RequiresRuntimeJitException ex) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } catch (CodeGenerationFailedException ex) when(_resilient) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } } }
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); } }
private void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (MethodCodeNode methodCodeNodeNeedingCode in obj) { MethodDesc method = methodCodeNodeNeedingCode.Method; string methodName = method.ToString(); Log.WriteLine("Compiling " + methodName); var methodIL = _ilProvider.GetMethodIL(method); if (methodIL == null) { return; } MethodCode methodCode; try { if (_skipJitList.Contains(new TypeAndMethod(method.OwningType.Name, method.Name))) { throw new NotImplementedException("SkipJIT"); } methodCode = _corInfo.CompileMethod(method); if (methodCode.Relocs != null) { if (methodCode.Relocs.Any(r => r.Target is FieldDesc)) { // We only support FieldDesc for InitializeArray intrinsic right now. throw new NotImplementedException("RuntimeFieldHandle is not implemented"); } } } catch (Exception e) { Log.WriteLine("*** " + e.Message + " (" + method + ")"); // Call the __not_yet_implemented method DependencyAnalysis.X64.X64Emitter emit = new DependencyAnalysis.X64.X64Emitter(_nodeFactory); emit.Builder.RequireAlignment(_nodeFactory.Target.MinimumFunctionAlignment); emit.Builder.DefinedSymbols.Add(methodCodeNodeNeedingCode); emit.EmitLEAQ(emit.TargetRegister.Arg0, _nodeFactory.StringIndirection(method.ToString())); DependencyAnalysis.X64.AddrMode loadFromArg0 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg0, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitLEAQ(emit.TargetRegister.Arg1, _nodeFactory.StringIndirection(e.Message)); DependencyAnalysis.X64.AddrMode loadFromArg1 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg1, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitJMP(_nodeFactory.ExternSymbol("__not_yet_implemented")); methodCodeNodeNeedingCode.SetCode(emit.Builder.ToObjectData()); continue; } ObjectDataBuilder objData = new ObjectDataBuilder(); objData.Alignment = _nodeFactory.Target.MinimumFunctionAlignment; objData.EmitBytes(methodCode.Code); objData.DefinedSymbols.Add(methodCodeNodeNeedingCode); BlobNode readOnlyDataBlob = null; if (methodCode.ROData != null) { readOnlyDataBlob = _nodeFactory.ReadOnlyDataBlob( "__readonlydata_" + _nameMangler.GetMangledMethodName(method), methodCode.ROData, methodCode.RODataAlignment); } if (methodCode.Relocs != null) { for (int i = 0; i < methodCode.Relocs.Length; i++) { // TODO: Arbitrary relocs if (methodCode.Relocs[i].Block != BlockType.Code) { throw new NotImplementedException(); } int offset = methodCode.Relocs[i].Offset; int delta = methodCode.Relocs[i].Delta; RelocType relocType = (RelocType)methodCode.Relocs[i].RelocType; ISymbolNode targetNode; object target = methodCode.Relocs[i].Target; if (target is MethodDesc) { targetNode = _nodeFactory.MethodEntrypoint((MethodDesc)target); } else if (target is ReadyToRunHelper) { targetNode = _nodeFactory.ReadyToRunHelper((ReadyToRunHelper)target); } else if (target is JitHelper) { targetNode = _nodeFactory.ExternSymbol(((JitHelper)target).MangledName); } else if (target is string) { targetNode = _nodeFactory.StringIndirection((string)target); } else if (target is TypeDesc) { targetNode = _nodeFactory.NecessaryTypeSymbol((TypeDesc)target); } else if (target is RvaFieldData) { var rvaFieldData = (RvaFieldData)target; targetNode = _nodeFactory.ReadOnlyDataBlob(rvaFieldData.MangledName, rvaFieldData.Data, _typeSystemContext.Target.PointerSize); } else if (target is BlockRelativeTarget) { var blockRelativeTarget = (BlockRelativeTarget)target; // TODO: Arbitrary block relative relocs if (blockRelativeTarget.Block != BlockType.ROData) { throw new NotImplementedException(); } targetNode = readOnlyDataBlob; } else { // TODO: throw new NotImplementedException(); } objData.AddRelocAtOffset(targetNode, relocType, offset, delta); } } // TODO: ColdCode if (methodCode.ColdCode != null) { throw new NotImplementedException(); } methodCodeNodeNeedingCode.SetCode(objData.ToObjectData()); methodCodeNodeNeedingCode.InitializeFrameInfos(methodCode.FrameInfos); methodCodeNodeNeedingCode.InitializeDebugLocInfos(methodCode.DebugLocInfos); } }