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);
            }
        }
Example #2
0
        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");
                }
            }
        }
Example #3
0
        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;
                }
            }
        }
Example #4
0
        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;
            }
        }
Example #6
0
        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);
            }
        }
Example #8
0
        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);
            }
        }