Пример #1
0
 public Relocation(RelocType relocType, int offset, ISymbolNode target, int delta)
 {
     RelocType = relocType;
     Offset = offset;
     Target = target;
     Delta = delta;
 }
Пример #2
0
 public HeaderItem(ReadyToRunSectionType id, ObjectNode node, ISymbolNode startSymbol, ISymbolNode endSymbol)
 {
     Id = id;
     Node = node;
     StartSymbol = startSymbol;
     EndSymbol = endSymbol;
 }
Пример #3
0
 public void EmitLEAQ(Register reg, ISymbolNode symbol, int delta = 0)
 {
     AddrMode rexAddrMode = new AddrMode(Register.RAX, null, 0, 0, AddrModeSize.Int64);
     EmitRexPrefix(reg, ref rexAddrMode);
     Builder.EmitByte(0x8D);
     Builder.EmitByte((byte)(0x05 | (((int)reg) & 0x07) << 3));
     Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32, delta);
 }
Пример #4
0
        public NonGCStaticsNode(MetadataType type)
        {
            _type = type;

            if (HasClassConstructorContext)
            {
                _classConstructorContext = new ObjectAndOffsetSymbolNode(this, 0,
                    "__CCtorContext_" + NodeFactory.NameMangler.GetMangledTypeName(_type));
            }
        }
Пример #5
0
 public void EmitLEAQ(Register reg, ISymbolNode symbol)
 {
     AddrMode rexAddrMode = new AddrMode(Register.RAX, null, 0, 0, AddrModeSize.Int64);
     EmitRexPrefix(reg, ref rexAddrMode);
     Builder.EmitByte(0x8D);
     int regNumLowBits = ((int)reg) & 0x07;
     int regNumLowBitsShifted = regNumLowBits << 3;
     byte modRM = (byte)(regNumLowBitsShifted | 0x05);
     Builder.EmitByte(modRM);
     Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
 }
        /// <summary>
        /// Adds a new entry to the table. Thread safety: not thread safe. Expected to be called at the final
        /// object data emission phase from a single thread.
        /// </summary>
        public uint GetIndex(ISymbolNode symbol)
        {
            uint index;
            if (!_insertedSymbolsDictionary.TryGetValue(symbol, out index))
            {
                index = (uint)_insertedSymbols.Count;
                _insertedSymbolsDictionary[symbol] = index;
                _insertedSymbols.Add(symbol);
            }

            return index;
        }
Пример #7
0
        public NonGCStaticsNode(MetadataType type, NodeFactory factory)
        {
            _type = type;

            if (factory.TypeInitializationManager.HasLazyStaticConstructor(type))
            {
                // Class constructor context is a small struct prepended to type's non-GC static data region
                // that keeps track of whether the .cctor executed and holds the pointer to the .cctor method.
                _classConstructorContext = new ObjectAndOffsetSymbolNode(this, 0,
                    "__CCtorContext_" + NodeFactory.NameMangler.GetMangledTypeName(_type));
            }
        }
Пример #8
0
 public void Visit(ISymbolNode node)
 {
     VisitLog.Add(node.ToString());
 }
Пример #9
0
 public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex)
 {
     Node        = node;
     NodeIndex   = nodeIndex;
     SymbolIndex = symbolIndex;
 }
Пример #10
0
 public IndirectionNode Indirection(ISymbolNode symbol)
 {
     return(_indirectionNodes.GetOrAdd(symbol));
 }
Пример #11
0
 public SingleArgumentJumpThunk(ExternSymbolNode target, ISymbolNode argument)
 {
     _target = target;
     _argument = argument;
 }
Пример #12
0
 public JumpStubNode(ISymbolNode target)
 {
     this._target = target;
 }
Пример #13
0
        public static void EmitObject(string objectFilePath, IEnumerable <DependencyNode> nodes, NodeFactory factory, WebAssemblyCodegenCompilation compilation, IObjectDumper dumper)
        {
            WebAssemblyObjectWriter objectWriter = new WebAssemblyObjectWriter(objectFilePath, factory, compilation);
            bool succeeded = false;

            try
            {
                objectWriter.EmitReadyToRunHeaderCallback(compilation.Module.Context);
                //ObjectNodeSection managedCodeSection = null;

                var listOfOffsets = new List <int>();
                foreach (DependencyNode depNode in nodes)
                {
                    ObjectNode node = depNode as ObjectNode;
                    if (node == null)
                    {
                        continue;
                    }

                    if (node.ShouldSkipEmittingObjectNode(factory))
                    {
                        continue;
                    }

                    if (node is ReadyToRunGenericHelperNode readyToRunGenericHelperNode)
                    {
                        objectWriter.GetCodeForReadyToRunGenericHelper(compilation, readyToRunGenericHelperNode, factory);
                        continue;
                    }

                    objectWriter.StartObjectNode(node);
                    ObjectData nodeContents = node.GetData(factory);

                    if (dumper != null)
                    {
                        dumper.DumpObjectNode(factory.NameMangler, node, nodeContents);
                    }

#if DEBUG
                    foreach (ISymbolNode definedSymbol in nodeContents.DefinedSymbols)
                    {
                        try
                        {
                            _previouslyWrittenNodeNames.Add(definedSymbol.GetMangledName(factory.NameMangler), definedSymbol);
                        }
                        catch (ArgumentException)
                        {
                            ISymbolNode alreadyWrittenSymbol = _previouslyWrittenNodeNames[definedSymbol.GetMangledName(factory.NameMangler)];
                            Debug.Fail("Duplicate node name emitted to file",
                                       $"Symbol {definedSymbol.GetMangledName(factory.NameMangler)} has already been written to the output object file {objectFilePath} with symbol {alreadyWrittenSymbol}");
                        }
                    }
#endif

                    ObjectNodeSection section = node.Section;
                    if (objectWriter.ShouldShareSymbol(node))
                    {
                        section = objectWriter.GetSharedSection(section, ((ISymbolNode)node).GetMangledName(factory.NameMangler));
                    }

                    // Ensure section and alignment for the node.
                    objectWriter.SetSection(section);
                    objectWriter.EmitAlignment(nodeContents.Alignment);

                    objectWriter.ResetByteRunInterruptionOffsets(nodeContents.Relocs);

                    // Build symbol definition map.
                    objectWriter.BuildSymbolDefinitionMap(node, nodeContents.DefinedSymbols);

                    Relocation[] relocs          = nodeContents.Relocs;
                    int          nextRelocOffset = -1;
                    int          nextRelocIndex  = -1;
                    if (relocs.Length > 0)
                    {
                        nextRelocOffset = relocs[0].Offset;
                        nextRelocIndex  = 0;
                    }

                    int i = 0;

                    listOfOffsets.Clear();
                    listOfOffsets.AddRange(objectWriter._byteInterruptionOffsets);

                    int offsetIndex = 0;
                    while (i < nodeContents.Data.Length)
                    {
                        // Emit symbol definitions if necessary
                        objectWriter.EmitSymbolDefinition(i);

                        if (i == nextRelocOffset)
                        {
                            Relocation reloc = relocs[nextRelocIndex];

                            long delta;
                            unsafe
                            {
                                fixed(void *location = &nodeContents.Data[i])
                                {
                                    delta = Relocation.ReadValue(reloc.RelocType, location);
                                }
                            }
                            ISymbolNode symbolToWrite = reloc.Target;
                            var         eeTypeNode    = reloc.Target as EETypeNode;
                            if (eeTypeNode != null)
                            {
                                if (eeTypeNode.ShouldSkipEmittingObjectNode(factory))
                                {
                                    symbolToWrite = factory.ConstructedTypeSymbol(eeTypeNode.Type);
                                }
                            }

                            int size = objectWriter.EmitSymbolReference(symbolToWrite, (int)delta, reloc.RelocType);

                            /*
                             * WebAssembly has no thumb
                             * // Emit a copy of original Thumb2 instruction that came from RyuJIT
                             * if (reloc.RelocType == RelocType.IMAGE_REL_BASED_THUMB_MOV32 ||
                             *  reloc.RelocType == RelocType.IMAGE_REL_BASED_THUMB_BRANCH24)
                             * {
                             *  unsafe
                             *  {
                             *      fixed (void* location = &nodeContents.Data[i])
                             *      {
                             *          objectWriter.EmitBytes((IntPtr)location, size);
                             *      }
                             *  }
                             * }*/

                            // Update nextRelocIndex/Offset
                            if (++nextRelocIndex < relocs.Length)
                            {
                                nextRelocOffset = relocs[nextRelocIndex].Offset;
                            }
                            else
                            {
                                // This is the last reloc. Set the next reloc offset to -1 in case the last reloc has a zero size,
                                // which means the reloc does not have vacant bytes corresponding to in the data buffer. E.g,
                                // IMAGE_REL_THUMB_BRANCH24 is a kind of 24-bit reloc whose bits scatte over the instruction that
                                // references it. We do not vacate extra bytes in the data buffer for this kind of reloc.
                                nextRelocOffset = -1;
                            }
                            i += size;
                        }
                        else
                        {
                            while (offsetIndex < listOfOffsets.Count && listOfOffsets[offsetIndex] <= i)
                            {
                                offsetIndex++;
                            }

                            int nextOffset = offsetIndex == listOfOffsets.Count ? nodeContents.Data.Length : listOfOffsets[offsetIndex];

                            unsafe
                            {
                                // Todo: Use Span<T> instead once it's available to us in this repo
                                fixed(byte *pContents = &nodeContents.Data[i])
                                {
                                    objectWriter.EmitBytes((IntPtr)(pContents), nextOffset - i);
                                    i += nextOffset - i;
                                }
                            }
                        }
                    }
                    Debug.Assert(i == nodeContents.Data.Length);

                    // It is possible to have a symbol just after all of the data.
                    objectWriter.EmitSymbolDefinition(nodeContents.Data.Length);
                    objectWriter.DoneObjectNode();
                }

                succeeded = true;
            }
            finally
            {
                objectWriter.Dispose();

                if (!succeeded)
                {
                    // If there was an exception while generating the OBJ file, make sure we don't leave the unfinished
                    // object file around.
                    try
                    {
                        File.Delete(objectFilePath);
                    }
                    catch
                    {
                    }
                }
            }
        }
Пример #14
0
        // Returns size of the emitted symbol reference
        public int EmitSymbolReference(ISymbolNode target, int delta, RelocType relocType)
        {
            _sb.Clear();
            AppendExternCPrefix(_sb);
            target.AppendMangledName(NodeFactory.NameMangler, _sb);

            return EmitSymbolRef(_sb, relocType, delta);
        }
Пример #15
0
 public void EmitPointerReloc(ISymbolNode symbol, int delta = 0)
 {
     EmitReloc(symbol, (_target.PointerSize == 8) ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW, delta);
 }
Пример #16
0
 private DelegateCreationInfo(IMethodNode constructor, ISymbolNode target, IMethodNode thunk = null)
 {
     Constructor = constructor;
     Target = target;
     Thunk = thunk;
 }
Пример #17
0
        private void ImportCall(ILOpcode opcode, int token)
        {
            // Strip runtime determined characteristics off of the method (because that's how RyuJIT operates)
            var        runtimeDeterminedMethod = (MethodDesc)_methodIL.GetObject(token);
            MethodDesc method = runtimeDeterminedMethod;

            if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod)
            {
                method = runtimeDeterminedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
            }

            if (method.IsRawPInvoke())
            {
                // Raw P/invokes don't have any dependencies.
                return;
            }

            string reason = null;

            switch (opcode)
            {
            case ILOpcode.newobj:
                reason = "newobj"; break;

            case ILOpcode.call:
                reason = "call"; break;

            case ILOpcode.callvirt:
                reason = "callvirt"; break;

            case ILOpcode.ldftn:
                reason = "ldftn"; break;

            case ILOpcode.ldvirtftn:
                reason = "ldvirtftn"; break;

            default:
                Debug.Assert(false); break;
            }

            // If we're scanning the fallback body because scanning the real body failed, don't trigger cctor.
            // Accessing the cctor could have been a reason why we failed.
            if (!_isFallbackBodyCompilation)
            {
                // Do we need to run the cctor?
                TypeDesc owningType = runtimeDeterminedMethod.OwningType;
                if (_factory.TypeSystemContext.HasLazyStaticConstructor(owningType))
                {
                    // For beforefieldinit, we can wait for field access.
                    if (!((MetadataType)owningType).IsBeforeFieldInit)
                    {
                        // Accessing the static base will trigger the cctor.
                        if (owningType.IsRuntimeDeterminedSubtype)
                        {
                            _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.GetNonGCStaticBase, owningType), reason);
                        }
                        else
                        {
                            _dependencies.Add(_factory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, owningType), reason);
                        }
                    }
                }
            }

            if (opcode == ILOpcode.newobj)
            {
                TypeDesc owningType = runtimeDeterminedMethod.OwningType;
                if (owningType.IsString)
                {
                    // String .ctor handled specially below
                }
                else
                {
                    // Nullable needs to be unwrapped.
                    if (owningType.IsNullable)
                    {
                        owningType = owningType.Instantiation[0];
                    }

                    if (owningType.IsRuntimeDeterminedSubtype)
                    {
                        _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, owningType), reason);
                    }
                    else
                    {
                        _dependencies.Add(_factory.ConstructedTypeSymbol(owningType), reason);
                    }

                    if (owningType.IsMdArray)
                    {
                        _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.NewMultiDimArr_NonVarArg), reason);
                        return;
                    }
                    else
                    {
                        _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.NewObject), reason);
                    }
                }

                if (owningType.IsDelegate)
                {
                    // If this is a verifiable delegate construction sequence, the previous instruction is a ldftn/ldvirtftn
                    if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.prefix1)
                    {
                        // TODO: for ldvirtftn we need to also check for the `dup` instruction, otherwise this is a normal newobj.

                        ILOpcode previousOpcode = (ILOpcode)(0x100 + _ilBytes[_previousInstructionOffset + 1]);
                        if (previousOpcode == ILOpcode.ldvirtftn || previousOpcode == ILOpcode.ldftn)
                        {
                            int                  delTargetToken    = ReadILTokenAt(_previousInstructionOffset + 2);
                            var                  delTargetMethod   = (MethodDesc)_methodIL.GetObject(delTargetToken);
                            TypeDesc             canonDelegateType = method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
                            DelegateCreationInfo info = _compilation.GetDelegateCtor(canonDelegateType, delTargetMethod, previousOpcode == ILOpcode.ldvirtftn);

                            if (info.NeedsRuntimeLookup)
                            {
                                _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.DelegateCtor, info), reason);
                            }
                            else
                            {
                                _dependencies.Add(_factory.ReadyToRunHelper(ReadyToRunHelperId.DelegateCtor, info), reason);
                            }

                            return;
                        }
                    }
                }
            }

            if (method.OwningType.IsDelegate && method.Name == "Invoke")
            {
                // TODO: might not want to do this if scanning for reflection.
                // This is expanded as an intrinsic, not a function call.
                return;
            }

            if (method.IsIntrinsic)
            {
                if (IsRuntimeHelpersInitializeArray(method))
                {
                    if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.ldtoken)
                    {
                        return;
                    }
                }

                if (IsRuntimeTypeHandleGetValueInternal(method))
                {
                    if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.ldtoken)
                    {
                        return;
                    }
                }
            }

            TypeDesc exactType = method.OwningType;

            bool resolvedConstraint    = false;
            bool forceUseRuntimeLookup = false;

            MethodDesc methodAfterConstraintResolution = method;

            if (_constrained != null)
            {
                // We have a "constrained." call.  Try a partial resolve of the constraint call.  Note that this
                // will not necessarily resolve the call exactly, since we might be compiling
                // shared generic code - it may just resolve it to a candidate suitable for
                // JIT compilation, and require a runtime lookup for the actual code pointer
                // to call.

                MethodDesc directMethod = _constrained.GetClosestDefType().TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup);
                if (directMethod == null && _constrained.IsEnum)
                {
                    // Constrained calls to methods on enum methods resolve to System.Enum's methods. System.Enum is a reference
                    // type though, so we would fail to resolve and box. We have a special path for those to avoid boxing.
                    directMethod = _compilation.TypeSystemContext.TryResolveConstrainedEnumMethod(_constrained, method);
                }

                if (directMethod != null)
                {
                    // Either
                    //    1. no constraint resolution at compile time (!directMethod)
                    // OR 2. no code sharing lookup in call
                    // OR 3. we have have resolved to an instantiating stub

                    methodAfterConstraintResolution = directMethod;

                    Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface);
                    resolvedConstraint = true;

                    exactType = _constrained;
                }
                else if (_constrained.IsValueType)
                {
                    // We'll need to box `this`.
                    AddBoxingDependencies(_constrained, reason);
                }

                _constrained = null;
            }

            MethodDesc targetMethod = methodAfterConstraintResolution;

            bool exactContextNeedsRuntimeLookup;

            if (targetMethod.HasInstantiation)
            {
                exactContextNeedsRuntimeLookup = targetMethod.IsSharedByGenericInstantiations;
            }
            else
            {
                exactContextNeedsRuntimeLookup = exactType.IsCanonicalSubtype(CanonicalFormKind.Any);
            }

            //
            // Determine whether to perform direct call
            //

            bool directCall = false;

            if (targetMethod.Signature.IsStatic)
            {
                // Static methods are always direct calls
                directCall = true;
            }
            else if (targetMethod.OwningType.IsInterface)
            {
                // Force all interface calls to be interpreted as if they are virtual.
                directCall = false;
            }
            else if ((opcode != ILOpcode.callvirt && opcode != ILOpcode.ldvirtftn) || resolvedConstraint)
            {
                directCall = true;
            }
            else
            {
                if (!targetMethod.IsVirtual || targetMethod.IsFinal || targetMethod.OwningType.IsSealed())
                {
                    directCall = true;
                }
            }

            bool allowInstParam = opcode != ILOpcode.ldvirtftn && opcode != ILOpcode.ldftn;

            if (directCall && !allowInstParam && targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
            {
                // Needs a single address to call this method but the method needs a hidden argument.
                // We need a fat function pointer for this that captures both things.

                if (exactContextNeedsRuntimeLookup)
                {
                    _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodEntry, runtimeDeterminedMethod), reason);
                }
                else
                {
                    _dependencies.Add(_factory.FatFunctionPointer(runtimeDeterminedMethod), reason);
                }
            }
            else if (directCall)
            {
                bool referencingArrayAddressMethod = false;

                if (targetMethod.IsIntrinsic)
                {
                    // If this is an intrinsic method with a callsite-specific expansion, this will replace
                    // the method with a method the intrinsic expands into. If it's not the special intrinsic,
                    // method stays unchanged.
                    targetMethod = _compilation.ExpandIntrinsicForCallsite(targetMethod, _canonMethod);

                    // Array address method requires special dependency tracking.
                    referencingArrayAddressMethod = targetMethod.IsArrayAddressMethod();
                }

                MethodDesc concreteMethod = targetMethod;
                targetMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);

                if (targetMethod.IsConstructor && targetMethod.OwningType.IsString)
                {
                    _dependencies.Add(_factory.StringAllocator(targetMethod), reason);
                }
                else if (exactContextNeedsRuntimeLookup)
                {
                    if (targetMethod.IsSharedByGenericInstantiations && !resolvedConstraint && !referencingArrayAddressMethod)
                    {
                        _dependencies.Add(_factory.RuntimeDeterminedMethod(runtimeDeterminedMethod), reason);
                    }
                    else
                    {
                        Debug.Assert(!forceUseRuntimeLookup);
                        _dependencies.Add(_factory.MethodEntrypoint(targetMethod), reason);
                    }
                }
                else
                {
                    ISymbolNode instParam = null;

                    if (targetMethod.RequiresInstMethodDescArg())
                    {
                        instParam = _compilation.NodeFactory.MethodGenericDictionary(concreteMethod);
                    }
                    else if (targetMethod.RequiresInstMethodTableArg() || referencingArrayAddressMethod)
                    {
                        // Ask for a constructed type symbol because we need the vtable to get to the dictionary
                        instParam = _compilation.NodeFactory.ConstructedTypeSymbol(concreteMethod.OwningType);
                    }

                    if (instParam != null)
                    {
                        _dependencies.Add(instParam, reason);

                        if (!referencingArrayAddressMethod)
                        {
                            _dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason);
                        }
                        else
                        {
                            // We don't want array Address method to be modeled in the generic dependency analysis.
                            // The method doesn't actually have runtime determined dependencies (won't do
                            // any generic lookups).
                            _dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason);
                        }
                    }
                    else if (targetMethod.AcquiresInstMethodTableFromThis())
                    {
                        _dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason);
                    }
                    else
                    {
                        _dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason);
                    }
                }
            }
            else if (method.HasInstantiation)
            {
                // Generic virtual method call

                if (exactContextNeedsRuntimeLookup)
                {
                    _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodHandle, runtimeDeterminedMethod), reason);
                }
                else
                {
                    _dependencies.Add(_factory.RuntimeMethodHandle(runtimeDeterminedMethod), reason);
                }

                _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.GVMLookupForSlot), reason);
            }
            else
            {
                ReadyToRunHelperId helper;
                if (opcode == ILOpcode.ldvirtftn)
                {
                    helper = ReadyToRunHelperId.ResolveVirtualFunction;
                }
                else
                {
                    Debug.Assert(opcode == ILOpcode.callvirt);
                    helper = ReadyToRunHelperId.VirtualCall;
                }

                if (exactContextNeedsRuntimeLookup && targetMethod.OwningType.IsInterface)
                {
                    _dependencies.Add(GetGenericLookupHelper(helper, runtimeDeterminedMethod), reason);
                }
                else
                {
                    // Get the slot defining method to make sure our virtual method use tracking gets this right.
                    // For normal C# code the targetMethod will always be newslot.
                    MethodDesc slotDefiningMethod = targetMethod.IsNewSlot ?
                                                    targetMethod : MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(targetMethod);

                    _dependencies.Add(_factory.ReadyToRunHelper(helper, slotDefiningMethod), reason);
                }
            }
        }
Пример #18
0
        private void CreateNodeCaches()
        {
            _typeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) =>
            {
                Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
                if (_compilationModuleGroup.ContainsType(type))
                {
                    if (type.IsGenericDefinition)
                    {
                        return(new GenericDefinitionEETypeNode(this, type));
                    }
                    else if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
                    {
                        return(new CanonicalDefinitionEETypeNode(this, type));
                    }
                    else if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                    {
                        if (Target.Abi == TargetAbi.CoreRT)
                        {
                            return(new CanonicalEETypeNode(this, type));
                        }
                        else
                        {
                            // Remove this once we stop using the STS dependency analysis.
                            return(new NecessaryCanonicalEETypeNode(this, type));
                        }
                    }
                    else
                    {
                        return(new EETypeNode(this, type));
                    }
                }
                else
                {
                    return(new ExternEETypeSymbolNode(this, type));
                }
            });

            _constructedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) =>
            {
                // Canonical definition types are *not* constructed types (call NecessaryTypeSymbol to get them)
                Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
                Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type));

                if (_compilationModuleGroup.ContainsType(type))
                {
                    if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                    {
                        return(new CanonicalEETypeNode(this, type));
                    }
                    else
                    {
                        return(new ConstructedEETypeNode(this, type));
                    }
                }
                else
                {
                    return(new ExternEETypeSymbolNode(this, type));
                }
            });

            _clonedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) =>
            {
                // Only types that reside in other binaries should be cloned
                Debug.Assert(_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
                return(new ClonedConstructedEETypeNode(this, type));
            });

            _importedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) =>
            {
                Debug.Assert(_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
                return(new ImportedEETypeSymbolNode(this, type));
            });

            _nonGCStatics = new NodeCache <MetadataType, ISymbolNode>((MetadataType type) =>
            {
                if (_compilationModuleGroup.ContainsType(type))
                {
                    return(new NonGCStaticsNode(type, this));
                }
                else if (_compilationModuleGroup.ShouldReferenceThroughImportTable(type))
                {
                    return(new ImportedNonGCStaticsNode(this, type));
                }
                else
                {
                    return(new ExternSymbolNode(NonGCStaticsNode.GetMangledName(type, NameMangler)));
                }
            });

            _GCStatics = new NodeCache <MetadataType, ISymbolNode>((MetadataType type) =>
            {
                if (_compilationModuleGroup.ContainsType(type))
                {
                    return(new GCStaticsNode(type));
                }
                else if (_compilationModuleGroup.ShouldReferenceThroughImportTable(type))
                {
                    return(new ImportedGCStaticsNode(this, type));
                }
                else
                {
                    return(new ExternSymbolNode(GCStaticsNode.GetMangledName(type, NameMangler)));
                }
            });

            _GCStaticIndirectionNodes = new NodeCache <MetadataType, EmbeddedObjectNode>((MetadataType type) =>
            {
                ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type);
                Debug.Assert(gcStaticsNode is GCStaticsNode);
                return(GCStaticsRegion.NewNode((GCStaticsNode)gcStaticsNode));
            });

            _threadStatics = new NodeCache <MetadataType, ThreadStaticsNode>((MetadataType type) =>
            {
                return(new ThreadStaticsNode(type, this));
            });

            _typeThreadStaticIndices = new NodeCache <MetadataType, TypeThreadStaticIndexNode>(type =>
            {
                return(new TypeThreadStaticIndexNode(type));
            });

            _GCStaticEETypes = new NodeCache <GCPointerMap, GCStaticEETypeNode>((GCPointerMap gcMap) =>
            {
                return(new GCStaticEETypeNode(Target, gcMap));
            });

            _readOnlyDataBlobs = new NodeCache <ReadOnlyDataBlobKey, BlobNode>(key =>
            {
                return(new BlobNode(key.Name, ObjectNodeSection.ReadOnlyDataSection, key.Data, key.Alignment));
            });

            _externSymbols = new NodeCache <string, ExternSymbolNode>((string name) =>
            {
                return(new ExternSymbolNode(name));
            });

            _pInvokeModuleFixups = new NodeCache <string, PInvokeModuleFixupNode>((string name) =>
            {
                return(new PInvokeModuleFixupNode(name));
            });

            _pInvokeMethodFixups = new NodeCache <Tuple <string, string>, PInvokeMethodFixupNode>((Tuple <string, string> key) =>
            {
                return(new PInvokeMethodFixupNode(key.Item1, key.Item2));
            });

            _methodEntrypoints = new NodeCache <MethodDesc, IMethodNode>(CreateMethodEntrypointNode);

            _unboxingStubs = new NodeCache <MethodDesc, IMethodNode>(CreateUnboxingStubNode);

            _fatFunctionPointers = new NodeCache <MethodKey, FatFunctionPointerNode>(method =>
            {
                return(new FatFunctionPointerNode(method.Method, method.IsUnboxingStub));
            });

            _gvmDependenciesNode = new NodeCache <MethodDesc, GVMDependenciesNode>(method =>
            {
                return(new GVMDependenciesNode(method));
            });

            _gvmTableEntries = new NodeCache <TypeDesc, TypeGVMEntriesNode>(type =>
            {
                return(new TypeGVMEntriesNode(type));
            });

            _shadowConcreteMethods = new NodeCache <MethodKey, IMethodNode>(methodKey =>
            {
                MethodDesc canonMethod = methodKey.Method.GetCanonMethodTarget(CanonicalFormKind.Specific);

                if (methodKey.IsUnboxingStub)
                {
                    return(new ShadowConcreteUnboxingThunkNode(methodKey.Method, MethodEntrypoint(canonMethod, true)));
                }
                else
                {
                    return(new ShadowConcreteMethodNode(methodKey.Method, MethodEntrypoint(canonMethod)));
                }
            });

            _runtimeDeterminedMethods = new NodeCache <MethodDesc, IMethodNode>(method =>
            {
                return(new RuntimeDeterminedMethodNode(method,
                                                       MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific))));
            });

            _virtMethods = new NodeCache <MethodDesc, VirtualMethodUseNode>((MethodDesc method) =>
            {
                // We don't need to track virtual method uses for types that are producing full vtables.
                // It's a waste of CPU time and memory.
                Debug.Assert(!CompilationModuleGroup.ShouldProduceFullVTable(method.OwningType));

                return(new VirtualMethodUseNode(method));
            });

            _readyToRunHelpers = new NodeCache <ReadyToRunHelperKey, ISymbolNode>(CreateReadyToRunHelperNode);

            _genericReadyToRunHelpersFromDict = new NodeCache <ReadyToRunGenericHelperKey, ISymbolNode>(data =>
            {
                return(new ReadyToRunGenericLookupFromDictionaryNode(this, data.HelperId, data.Target, data.DictionaryOwner));
            });

            _genericReadyToRunHelpersFromType = new NodeCache <ReadyToRunGenericHelperKey, ISymbolNode>(data =>
            {
                return(new ReadyToRunGenericLookupFromTypeNode(this, data.HelperId, data.Target, data.DictionaryOwner));
            });

            _indirectionNodes = new NodeCache <ISymbolNode, ISymbolNode>(indirectedNode =>
            {
                return(new IndirectionNode(Target, indirectedNode, 0));
            });

            _frozenStringNodes = new NodeCache <string, FrozenStringNode>((string data) =>
            {
                return(new FrozenStringNode(data, Target));
            });

            _interfaceDispatchCells = new NodeCache <DispatchCellKey, InterfaceDispatchCellNode>(callSiteCell =>
            {
                return(new InterfaceDispatchCellNode(callSiteCell.Target, callSiteCell.CallsiteId));
            });

            _interfaceDispatchMaps = new NodeCache <TypeDesc, InterfaceDispatchMapNode>((TypeDesc type) =>
            {
                return(new InterfaceDispatchMapNode(type));
            });

            _runtimeMethodHandles = new NodeCache <MethodDesc, RuntimeMethodHandleNode>((MethodDesc method) =>
            {
                return(new RuntimeMethodHandleNode(method));
            });

            _runtimeFieldHandles = new NodeCache <FieldDesc, RuntimeFieldHandleNode>((FieldDesc field) =>
            {
                return(new RuntimeFieldHandleNode(field));
            });

            _interfaceDispatchMapIndirectionNodes = new NodeCache <TypeDesc, EmbeddedObjectNode>((TypeDesc type) =>
            {
                var dispatchMap = InterfaceDispatchMap(type);
                return(DispatchMapTable.NewNodeWithSymbol(dispatchMap, (indirectionNode) =>
                {
                    dispatchMap.SetDispatchMapIndex(this, DispatchMapTable.IndexOfEmbeddedObject(indirectionNode));
                }));
            });

            _genericCompositions = new NodeCache <GenericCompositionDetails, GenericCompositionNode>((GenericCompositionDetails details) =>
            {
                return(new GenericCompositionNode(details));
            });

            _eagerCctorIndirectionNodes = new NodeCache <MethodDesc, EmbeddedObjectNode>((MethodDesc method) =>
            {
                Debug.Assert(method.IsStaticConstructor);
                Debug.Assert(TypeSystemContext.HasEagerStaticConstructor((MetadataType)method.OwningType));
                return(EagerCctorTable.NewNode(MethodEntrypoint(method)));
            });

            _vTableNodes = new NodeCache <TypeDesc, VTableSliceNode>((TypeDesc type ) =>
            {
                if (CompilationModuleGroup.ShouldProduceFullVTable(type))
                {
                    return(new EagerlyBuiltVTableSliceNode(type));
                }
                else
                {
                    return(new LazilyBuiltVTableSliceNode(type));
                }
            });

            _methodGenericDictionaries = new NodeCache <MethodDesc, ISymbolNode>(method =>
            {
                if (CompilationModuleGroup.ContainsMethod(method))
                {
                    return(new MethodGenericDictionaryNode(method));
                }
                else
                {
                    return(new ImportedMethodGenericDictionaryNode(this, method));
                }
            });

            _typeGenericDictionaries = new NodeCache <TypeDesc, ISymbolNode>(type =>
            {
                if (CompilationModuleGroup.ContainsType(type))
                {
                    return(new TypeGenericDictionaryNode(type));
                }
                else
                {
                    return(new ImportedTypeGenericDictionaryNode(this, type));
                }
            });

            _genericDictionaryLayouts = new NodeCache <TypeSystemEntity, DictionaryLayoutNode>(methodOrType =>
            {
                return(new DictionaryLayoutNode(methodOrType));
            });

            _stringAllocators = new NodeCache <MethodDesc, IMethodNode>(constructor =>
            {
                return(new StringAllocatorMethodNode(constructor));
            });

            NativeLayout = new NativeLayoutHelper(this);
        }
Пример #19
0
        protected override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly)
        {
            switch (Id)
            {
            case ReadyToRunHelperId.VirtualCall:
            {
                MethodDesc targetMethod = (MethodDesc)Target;

                Debug.Assert(!targetMethod.OwningType.IsInterface);
                Debug.Assert(!targetMethod.CanMethodBeInSealedVTable());

                int pointerSize = factory.Target.PointerSize;

                int slot = 0;
                if (!relocsOnly)
                {
                    slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType);
                    Debug.Assert(slot != -1);
                }

                encoder.EmitLDR(encoder.TargetRegister.InterproceduralScratch, encoder.TargetRegister.Arg0, 0);
                encoder.EmitLDR(encoder.TargetRegister.InterproceduralScratch, encoder.TargetRegister.InterproceduralScratch,
                                EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize));
                encoder.EmitJMP(encoder.TargetRegister.InterproceduralScratch);
            }
            break;

            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                MetadataType target = (MetadataType)Target;
                bool         hasLazyStaticConstructor = factory.PreinitializationManager.HasLazyStaticConstructor(target);
                encoder.EmitMOV(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target));

                if (!hasLazyStaticConstructor)
                {
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region.
                    encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target));
                    encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2,
                                    ((short)(factory.Target.PointerSize - NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target))));
                    encoder.EmitCMP(encoder.TargetRegister.Arg3, 1);
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    encoder.EmitMOV(encoder.TargetRegister.Arg0 /*Result*/, encoder.TargetRegister.Arg2);
                    encoder.EmitSUB(encoder.TargetRegister.Arg0, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target));
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.GetThreadStaticBase:
            {
                MetadataType target = (MetadataType)Target;
                encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeThreadStaticIndex(target));

                // First arg: address of the TypeManager slot that provides the helper with
                // information about module index and the type manager instance (which is used
                // for initialization on first access).
                encoder.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2);

                // Second arg: index of the type in the ThreadStatic section of the modules
                encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg2, factory.Target.PointerSize);

                if (!factory.PreinitializationManager.HasLazyStaticConstructor(target))
                {
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType));
                }
                else
                {
                    encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target));
                    encoder.EmitSUB(encoder.TargetRegister.Arg2, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target));
                    // TODO: performance optimization - inline the check verifying whether we need to trigger the cctor
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.GetGCStaticBase:
            {
                MetadataType target = (MetadataType)Target;
                encoder.EmitMOV(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target));
                encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result);
                encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result);
                if (!factory.PreinitializationManager.HasLazyStaticConstructor(target))
                {
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region.
                    encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target));
                    encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2,
                                    ((short)(factory.Target.PointerSize - NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target))));
                    encoder.EmitCMP(encoder.TargetRegister.Arg3, 1);
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    encoder.EmitMOV(encoder.TargetRegister.Arg0 /*Result*/, encoder.TargetRegister.Arg2);
                    encoder.EmitSUB(encoder.TargetRegister.Arg0, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target));
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.DelegateCtor:
            {
                DelegateCreationInfo target = (DelegateCreationInfo)Target;

                if (target.TargetNeedsVTableLookup)
                {
                    Debug.Assert(!target.TargetMethod.CanMethodBeInSealedVTable());

                    encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg1);

                    int slot = 0;
                    if (!relocsOnly)
                    {
                        slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, target.TargetMethod, target.TargetMethod.OwningType);
                    }

                    Debug.Assert(slot != -1);
                    encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2,
                                    EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize));
                }
                else
                {
                    ISymbolNode targetMethodNode = target.GetTargetNode(factory);
                    encoder.EmitMOV(encoder.TargetRegister.Arg2, target.GetTargetNode(factory));
                }

                if (target.Thunk != null)
                {
                    Debug.Assert(target.Constructor.Method.Signature.Length == 3);
                    encoder.EmitMOV(encoder.TargetRegister.Arg3, target.Thunk);
                }
                else
                {
                    Debug.Assert(target.Constructor.Method.Signature.Length == 2);
                }

                encoder.EmitJMP(target.Constructor);
            }
            break;

            case ReadyToRunHelperId.ResolveVirtualFunction:
            {
                ARMDebug.EmitHelperNYIAssert(factory, ref encoder, ReadyToRunHelperId.ResolveVirtualFunction);

                /*
                 ***
                 ***NOT TESTED!!!
                 ***
                 ***MethodDesc targetMethod = (MethodDesc)Target;
                 ***if (targetMethod.OwningType.IsInterface)
                 ***{
                 ***encoder.EmitMOV(encoder.TargetRegister.Arg1, factory.InterfaceDispatchCell(targetMethod));
                 ***encoder.EmitJMP(factory.ExternSymbol("RhpResolveInterfaceMethod"));
                 ***}
                 ***else
                 ***{
                 ***if (relocsOnly)
                 ***    break;
                 ***
                 ***encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0);
                 ***
                 ***Debug.Assert(!targetMethod.CanMethodBeInSealedVTable());
                 ***
                 ***int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType);
                 ***Debug.Assert(slot != -1);
                 ***encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result,
                 ***                ((short)(EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize))));
                 ***encoder.EmitRET();
                 ***}
                 */
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
        public override void AttachToDependencyGraph(DependencyAnalyzerBase <NodeFactory> graph)
        {
            Header = new HeaderNode(Target);

            var compilerIdentifierNode = new CompilerIdentifierNode(Target);

            Header.Add(Internal.Runtime.ReadyToRunSectionType.CompilerIdentifier, compilerIdentifierNode, compilerIdentifierNode);

            RuntimeFunctionsTable = new RuntimeFunctionsTableNode(this);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.RuntimeFunctions, RuntimeFunctionsTable, RuntimeFunctionsTable);

            RuntimeFunctionsGCInfo = new RuntimeFunctionsGCInfoNode();
            graph.AddRoot(RuntimeFunctionsGCInfo, "GC info is always generated");

            ExceptionInfoLookupTableNode exceptionInfoLookupTableNode = new ExceptionInfoLookupTableNode(this);

            Header.Add(Internal.Runtime.ReadyToRunSectionType.ExceptionInfo, exceptionInfoLookupTableNode, exceptionInfoLookupTableNode);
            graph.AddRoot(exceptionInfoLookupTableNode, "ExceptionInfoLookupTable is always generated");

            MethodEntryPointTable = new MethodEntryPointTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.MethodDefEntryPoints, MethodEntryPointTable, MethodEntryPointTable);

            InstanceEntryPointTable = new InstanceEntryPointTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.InstanceMethodEntryPoints, InstanceEntryPointTable, InstanceEntryPointTable);

            TypesTable = new TypesTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.AvailableTypes, TypesTable, TypesTable);

            ImportSectionsTable = new ImportSectionsTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.ImportSections, ImportSectionsTable, ImportSectionsTable.StartSymbol);

            DebugInfoTable = new DebugInfoTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.DebugInfo, DebugInfoTable, DebugInfoTable);

            EagerImports = new ImportSectionNode(
                "EagerImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_EAGER,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(EagerImports);

            // All ready-to-run images have a module import helper which gets patched by the runtime on image load
            ModuleImport = new Import(EagerImports, new ReadyToRunHelperSignature(
                                          ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_Module));
            graph.AddRoot(ModuleImport, "Module import is required by the R2R format spec");

            if (Target.Architecture != TargetArchitecture.X86)
            {
                Import personalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
                                                                 ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutine));
                PersonalityRoutine = new ImportThunk(
                    ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutine, this, personalityRoutineImport);
                graph.AddRoot(PersonalityRoutine, "Personality routine is faster to root early rather than referencing it from each unwind info");

                Import filterFuncletPersonalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
                                                                              ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutineFilterFunclet));
                FilterFuncletPersonalityRoutine = new ImportThunk(
                    ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutineFilterFunclet, this, filterFuncletPersonalityRoutineImport);
                graph.AddRoot(FilterFuncletPersonalityRoutine, "Filter funclet personality routine is faster to root early rather than referencing it from each unwind info");
            }

            MethodImports = new ImportSectionNode(
                "MethodImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: true);
            ImportSectionsTable.AddEmbeddedObject(MethodImports);

            DispatchImports = new ImportSectionNode(
                "DispatchImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: true);
            ImportSectionsTable.AddEmbeddedObject(DispatchImports);

            HelperImports = new ImportSectionNode(
                "HelperImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(HelperImports);

            PrecodeImports = new ImportSectionNode(
                "PrecodeImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: true,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(PrecodeImports);

            StringImports = new ImportSectionNode(
                "StringImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STRING_HANDLE,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_UNKNOWN,
                (byte)Target.PointerSize,
                emitPrecode: true,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(StringImports);

            graph.AddRoot(ImportSectionsTable, "Import sections table is always generated");
            graph.AddRoot(ModuleImport, "Module import is always generated");
            graph.AddRoot(EagerImports, "Eager imports are always generated");
            graph.AddRoot(MethodImports, "Method imports are always generated");
            graph.AddRoot(DispatchImports, "Dispatch imports are always generated");
            graph.AddRoot(HelperImports, "Helper imports are always generated");
            graph.AddRoot(PrecodeImports, "Precode imports are always generated");
            graph.AddRoot(StringImports, "String imports are always generated");
            graph.AddRoot(Header, "ReadyToRunHeader is always generated");

            MetadataManager.AttachToDependencyGraph(graph);
        }
Пример #21
0
        public static void EmitObject(string objectFilePath, IEnumerable <DependencyNode> nodes, NodeFactory factory, IObjectDumper dumper)
        {
            ObjectWriter objectWriter = new ObjectWriter(objectFilePath, factory);
            bool         succeeded    = false;

            try
            {
                ObjectNodeSection managedCodeSection;
                if (factory.Target.OperatingSystem == TargetOS.Windows)
                {
                    managedCodeSection = MethodCodeNode.WindowsContentSection;

                    // Emit sentinels for managed code section.
                    ObjectNodeSection codeStartSection = factory.CompilationModuleGroup.IsSingleFileCompilation ?
                                                         MethodCodeNode.StartSection :
                                                         objectWriter.GetSharedSection(MethodCodeNode.StartSection, "__managedcode_a");
                    objectWriter.SetSection(codeStartSection);
                    objectWriter.EmitSymbolDef(new Utf8StringBuilder().Append("__managedcode_a"));
                    objectWriter.EmitIntValue(0, 1);
                    ObjectNodeSection codeEndSection = factory.CompilationModuleGroup.IsSingleFileCompilation ?
                                                       MethodCodeNode.EndSection :
                                                       objectWriter.GetSharedSection(MethodCodeNode.EndSection, "__managedcode_z");
                    objectWriter.SetSection(codeEndSection);
                    objectWriter.EmitSymbolDef(new Utf8StringBuilder().Append("__managedcode_z"));
                    objectWriter.EmitIntValue(1, 1);
                }
                else
                {
                    managedCodeSection = MethodCodeNode.UnixContentSection;
                    // TODO 2916: managed code section has to be created here, switch is not necessary.
                    objectWriter.SetSection(MethodCodeNode.UnixContentSection);
                    objectWriter.SetSection(LsdaSection);
                }
                objectWriter.SetCodeSectionAttribute(managedCodeSection);

                // Build file info map.
                objectWriter.BuildFileInfoMap(nodes);

                var listOfOffsets = new List <int>();
                foreach (DependencyNode depNode in nodes)
                {
                    ObjectNode node = depNode as ObjectNode;
                    if (node == null)
                    {
                        continue;
                    }

                    if (node.ShouldSkipEmittingObjectNode(factory))
                    {
                        continue;
                    }

                    ObjectData nodeContents = node.GetData(factory);

                    if (dumper != null)
                    {
                        dumper.DumpObjectNode(factory.NameMangler, node, nodeContents);
                    }

#if DEBUG
                    foreach (ISymbolNode definedSymbol in nodeContents.DefinedSymbols)
                    {
                        try
                        {
                            _previouslyWrittenNodeNames.Add(definedSymbol.GetMangledName(factory.NameMangler), definedSymbol);
                        }
                        catch (ArgumentException)
                        {
                            ISymbolNode alreadyWrittenSymbol = _previouslyWrittenNodeNames[definedSymbol.GetMangledName(factory.NameMangler)];
                            Debug.Assert(false, "Duplicate node name emitted to file",
                                         $"Symbol {definedSymbol.GetMangledName(factory.NameMangler)} has already been written to the output object file {objectFilePath} with symbol {alreadyWrittenSymbol}");
                        }
                    }
#endif


                    ObjectNodeSection section = node.Section;
                    if (objectWriter.ShouldShareSymbol(node))
                    {
                        section = objectWriter.GetSharedSection(section, ((ISymbolNode)node).GetMangledName(factory.NameMangler));
                    }

                    // Ensure section and alignment for the node.
                    objectWriter.SetSection(section);
                    objectWriter.EmitAlignment(nodeContents.Alignment);

                    objectWriter.ResetByteRunInterruptionOffsets(nodeContents.Relocs);

                    // Build symbol definition map.
                    objectWriter.BuildSymbolDefinitionMap(node, nodeContents.DefinedSymbols);

                    if (!factory.Target.IsWindows)
                    {
                        objectWriter.BuildCFIMap(factory, node);
                    }

                    // Build debug location map
                    objectWriter.BuildDebugLocInfoMap(node);

                    Relocation[] relocs          = nodeContents.Relocs;
                    int          nextRelocOffset = -1;
                    int          nextRelocIndex  = -1;
                    if (relocs.Length > 0)
                    {
                        nextRelocOffset = relocs[0].Offset;
                        nextRelocIndex  = 0;
                    }

                    int i = 0;

                    listOfOffsets.Clear();
                    listOfOffsets.AddRange(objectWriter._byteInterruptionOffsets);

                    int offsetIndex = 0;
                    while (i < nodeContents.Data.Length)
                    {
                        // Emit symbol definitions if necessary
                        objectWriter.EmitSymbolDefinition(i);

                        // Emit CFI codes for the given offset.
                        objectWriter.EmitCFICodes(i);

                        // Emit debug loc info if needed.
                        objectWriter.EmitDebugLocInfo(i);

                        if (i == nextRelocOffset)
                        {
                            Relocation reloc = relocs[nextRelocIndex];

                            long delta;
                            unsafe
                            {
                                fixed(void *location = &nodeContents.Data[i])
                                {
                                    delta = Relocation.ReadValue(reloc.RelocType, location);
                                }
                            }
                            int size = objectWriter.EmitSymbolReference(reloc.Target, (int)delta, reloc.RelocType);

                            // Update nextRelocIndex/Offset
                            if (++nextRelocIndex < relocs.Length)
                            {
                                nextRelocOffset = relocs[nextRelocIndex].Offset;
                            }
                            else
                            {
                                // This is the last reloc. Set the next reloc offset to -1 in case the last reloc has a zero size,
                                // which means the reloc does not have vacant bytes corresponding to in the data buffer. E.g,
                                // IMAGE_REL_THUMB_BRANCH24 is a kind of 24-bit reloc whose bits scatte over the instruction that
                                // references it. We do not vacate extra bytes in the data buffer for this kind of reloc.
                                nextRelocOffset = -1;
                            }
                            i += size;
                        }
                        else
                        {
                            while (offsetIndex < listOfOffsets.Count && listOfOffsets[offsetIndex] <= i)
                            {
                                offsetIndex++;
                            }

                            int nextOffset = offsetIndex == listOfOffsets.Count ? nodeContents.Data.Length : listOfOffsets[offsetIndex];

                            unsafe
                            {
                                // Todo: Use Span<T> instead once it's available to us in this repo
                                fixed(byte *pContents = &nodeContents.Data[i])
                                {
                                    objectWriter.EmitBytes((IntPtr)(pContents), nextOffset - i);
                                    i += nextOffset - i;
                                }
                            }
                        }
                    }
                    Debug.Assert(i == nodeContents.Data.Length);

                    // It is possible to have a symbol just after all of the data.
                    objectWriter.EmitSymbolDefinition(nodeContents.Data.Length);

                    // Publish Windows unwind info.
                    if (factory.Target.IsWindows)
                    {
                        objectWriter.PublishUnwindInfo(node);
                    }

                    // Emit the last CFI to close the frame.
                    objectWriter.EmitCFICodes(nodeContents.Data.Length);

                    if (objectWriter.HasFunctionDebugInfo())
                    {
                        if (factory.Target.OperatingSystem == TargetOS.Windows)
                        {
                            // Build debug local var info.
                            // It currently supports only Windows CodeView format.
                            objectWriter.EmitDebugVarInfo(node);
                        }
                        objectWriter.EmitDebugFunctionInfo(nodeContents.Data.Length);
                    }
                }

                objectWriter.EmitDebugModuleInfo();

                succeeded = true;
            }
            finally
            {
                objectWriter.Dispose();

                if (!succeeded)
                {
                    // If there was an exception while generating the OBJ file, make sure we don't leave the unfinished
                    // object file around.
                    try
                    {
                        File.Delete(objectFilePath);
                    }
                    catch
                    {
                    }
                }
            }
        }
Пример #22
0
 public void BuildSymbolDefinitionMap(ISymbolNode[] definedSymbols)
 {
     _offsetToDefSymbol.Clear();
     foreach (ISymbolNode n in definedSymbols)
     {
         if (!_offsetToDefSymbol.ContainsKey(n.Offset))
         {
             _offsetToDefSymbol[n.Offset] = new List<ISymbolNode>();
         }
         _offsetToDefSymbol[n.Offset].Add(n);
     }
 }
Пример #23
0
 public HeaderItem(ReadyToRunSectionType id, ObjectNode node, ISymbolNode startSymbol, ISymbolNode endSymbol)
 {
     Id          = id;
     Node        = node;
     StartSymbol = startSymbol;
     EndSymbol   = endSymbol;
 }
Пример #24
0
        public static void EmitObject(string OutputPath, IEnumerable<DependencyNode> nodes, ISymbolNode mainMethodNode, NodeFactory factory)
        {
            using (ObjectWriter objectWriter = new ObjectWriter(OutputPath))
            {
                string currentSection = "";

                // Build file info map.
                string[] debugFileInfos = objectWriter.BuildFileInfoMap(nodes);
                if (debugFileInfos != null)
                {
                    objectWriter.EmitDebugFileInfo(debugFileInfos.Length, debugFileInfos);
                }

                foreach (DependencyNode depNode in nodes)
                {
                    ObjectNode node = depNode as ObjectNode;
                    if (node == null)
                        continue;

                    if (node.ShouldSkipEmittingObjectNode(factory))
                        continue;

                    ObjectNode.ObjectData nodeContents = node.GetData(factory);

                    if (currentSection != node.Section)
                    {
                        currentSection = node.Section;
                        objectWriter.SwitchSection(currentSection);
                    }

                    objectWriter.EmitAlignment(nodeContents.Alignment);

                    Relocation[] relocs = nodeContents.Relocs;
                    int nextRelocOffset = -1;
                    int nextRelocIndex = -1;
                    if (relocs != null && relocs.Length > 0)
                    {
                        nextRelocOffset = relocs[0].Offset;
                        nextRelocIndex = 0;
                    }

                    if (mainMethodNode == node)
                    {
                        objectWriter.EmitSymbolDef(MainEntryNodeName);
                    }

                    // Build symbol definition map.
                    objectWriter.BuildSymbolDefinitionMap(nodeContents.DefinedSymbols);

                    // Build debug location map
                    objectWriter.BuildDebugLocInfoMap(node);

                    for (int i = 0; i < nodeContents.Data.Length; i++)
                    {
                        // Emit symbol definitions if necessary
                        objectWriter.EmitSymbolDefinition(i);

                        // Emit debug loc info if needed.
                        objectWriter.EmitDebugLocInfo(i);

                        if (i == nextRelocOffset)
                        {
                            Relocation reloc = relocs[nextRelocIndex];

                            ISymbolNode target = reloc.Target;
                            string targetName = target.MangledName;
                            int size = 0;
                            bool isPCRelative = false;
                            switch (reloc.RelocType)
                            {
                                // REVIEW: I believe the JIT is emitting 0x3 instead of 0xA
                                // for x64, because emitter from x86 is ported for RyuJIT.
                                // I will consult with Bruce and if he agrees, I will delete
                                // this "case" duplicated by IMAGE_REL_BASED_DIR64.
                                case (RelocType)0x03: // IMAGE_REL_BASED_HIGHLOW
                                case RelocType.IMAGE_REL_BASED_DIR64:
                                    size = 8;
                                    break;
                                case RelocType.IMAGE_REL_BASED_REL32:
                                    size = 4;
                                    isPCRelative = true;
                                    break;
                                default:
                                    throw new NotImplementedException();
                            }
                            // Emit symbol reference
                            objectWriter.EmitSymbolRef(targetName, size, isPCRelative, reloc.Delta);

                            // Update nextRelocIndex/Offset
                            if (++nextRelocIndex < relocs.Length)
                            {
                                nextRelocOffset = relocs[nextRelocIndex].Offset;
                            }
                            i += size - 1;
                            continue;
                        }

                        objectWriter.EmitIntValue(nodeContents.Data[i], 1);
                    }

                    // It is possible to have a symbol just after all of the data.
                    objectWriter.EmitSymbolDefinition(nodeContents.Data.Length);

                    // The first definition is the main node name
                    string nodeName = objectWriter._offsetToDefSymbol[0][0].MangledName;
                    // Emit frame info for object code.
                    if (node is INodeWithFrameInfo)
                    {
                        FrameInfo[] frameInfos = ((INodeWithFrameInfo) node).FrameInfos;
                        if (frameInfos != null)
                        {
                            foreach (var frameInfo in frameInfos)
                            {
                                objectWriter.EmitFrameInfo(nodeName,
                                    frameInfo.StartOffset,
                                    frameInfo.EndOffset,
                                    frameInfo.BlobData.Length,
                                    frameInfo.BlobData);
                            }
                        }
                    }

                    objectWriter.FlushDebugLocs(nodeName, nodeContents.Data.Length);
                    objectWriter.SwitchSection(currentSection);
                }
            }
        }
Пример #25
0
 public void Add(ReadyToRunSectionType id, ObjectNode node, ISymbolNode startSymbol, ISymbolNode endSymbol = null)
 {
     _items.Add(new HeaderItem(id, node, startSymbol, endSymbol));
 }
Пример #26
0
        public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
        {
            _relocs.Add(new Relocation(relocType, _data.Count, symbol));

            // And add space for the reloc
            switch (relocType)
            {
                case RelocType.IMAGE_REL_BASED_REL32:
                case RelocType.IMAGE_REL_BASED_ABSOLUTE:
                    EmitInt(delta);
                    break;
                case RelocType.IMAGE_REL_BASED_DIR64:
                    EmitLong(delta);
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
Пример #27
0
 public SymbolAndDelta(ISymbolNode symbol, int delta)
 {
     Symbol = symbol;
     Delta  = delta;
 }
Пример #28
0
        public void BuildSymbolDefinitionMap(ObjectNode node, ISymbolNode[] definedSymbols)
        {
            _offsetToDefName.Clear();
            foreach (ISymbolNode n in definedSymbols)
            {
                if (!_offsetToDefName.ContainsKey(n.Offset))
                {
                    _offsetToDefName[n.Offset] = new List<string>();
                }

                string symbolToEmit = GetSymbolToEmitForTargetPlatform(n.MangledName);
                _offsetToDefName[n.Offset].Add(symbolToEmit);

                string alternateName = _nodeFactory.GetSymbolAlternateName(n);
                if (alternateName != null)
                {
                    symbolToEmit = GetSymbolToEmitForTargetPlatform(alternateName);
                    _offsetToDefName[n.Offset].Add(symbolToEmit);
                }
            }

            var symbolNode = node as ISymbolNode;
            if (symbolNode != null)
            {
                _currentNodeName = GetSymbolToEmitForTargetPlatform(symbolNode.MangledName);
                Debug.Assert(_offsetToDefName[symbolNode.Offset].Contains(_currentNodeName));
            }
            else
            {
                _currentNodeName = null;
            }
        }
Пример #29
0
 /// <summary>
 /// Construct the export symbol instance filling in its arguments
 /// </summary>
 /// <param name="name">Export symbol identifier</param>
 /// <param name="ordinal">Ordinal ID of the export symbol</param>
 /// <param name="symbol">Symbol to export</param>
 public ExportSymbol(string name, int ordinal, ISymbolNode symbol)
 {
     Name    = name;
     Ordinal = ordinal;
     Symbol  = symbol;
 }
Пример #30
0
 private DelegateCreationInfo(IMethodNode constructor, ISymbolNode target, IMethodNode thunk = null)
 {
     Constructor = constructor;
     Target      = target;
     Thunk       = thunk;
 }
Пример #31
0
 /// <summary>
 /// Override entry point for the app.
 /// </summary>
 /// <param name="symbol">Symbol representing the new entry point</param>
 public void SetEntryPoint(ISymbolNode symbol)
 {
     _entryPointSymbol = symbol;
 }
Пример #32
0
        private void CreateNodeCaches()
        {
            _typeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) =>
            {
                if (_compilationModuleGroup.ContainsType(type))
                {
                    if (type.IsGenericDefinition)
                    {
                        return(new GenericDefinitionEETypeNode(this, type));
                    }
                    else if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
                    {
                        return(new CanonicalDefinitionEETypeNode(this, type));
                    }
                    else if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                    {
                        return(new CanonicalEETypeNode(this, type));
                    }
                    else
                    {
                        return(new EETypeNode(this, type));
                    }
                }
                else
                {
                    return(new ExternEETypeSymbolNode(this, type));
                }
            });

            _constructedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) =>
            {
                if (_compilationModuleGroup.ContainsType(type))
                {
                    if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                    {
                        return(new CanonicalEETypeNode(this, type));
                    }
                    else
                    {
                        return(new ConstructedEETypeNode(this, type));
                    }
                }
                else
                {
                    return(new ExternEETypeSymbolNode(this, type));
                }
            });

            _clonedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) =>
            {
                // Only types that reside in other binaries should be cloned
                Debug.Assert(_compilationModuleGroup.ShouldReferenceThroughImportTable(type));
                return(new ClonedConstructedEETypeNode(this, type));
            });

            _nonGCStatics = new NodeCache <MetadataType, NonGCStaticsNode>((MetadataType type) =>
            {
                return(new NonGCStaticsNode(type, this));
            });

            _GCStatics = new NodeCache <MetadataType, GCStaticsNode>((MetadataType type) =>
            {
                return(new GCStaticsNode(type));
            });

            _GCStaticIndirectionNodes = new NodeCache <MetadataType, EmbeddedObjectNode>((MetadataType type) =>
            {
                ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type);
                Debug.Assert(gcStaticsNode is GCStaticsNode);
                return(GCStaticsRegion.NewNode((GCStaticsNode)gcStaticsNode));
            });

            _threadStatics = new NodeCache <MetadataType, ThreadStaticsNode>((MetadataType type) =>
            {
                return(new ThreadStaticsNode(type, this));
            });

            _typeThreadStaticIndices = new NodeCache <MetadataType, TypeThreadStaticIndexNode>(type =>
            {
                return(new TypeThreadStaticIndexNode(type));
            });

            _GCStaticEETypes = new NodeCache <GCPointerMap, GCStaticEETypeNode>((GCPointerMap gcMap) =>
            {
                return(new GCStaticEETypeNode(Target, gcMap));
            });

            _readOnlyDataBlobs = new NodeCache <Tuple <Utf8String, byte[], int>, BlobNode>((Tuple <Utf8String, byte[], int> key) =>
            {
                return(new BlobNode(key.Item1, ObjectNodeSection.ReadOnlyDataSection, key.Item2, key.Item3));
            }, new BlobTupleEqualityComparer());

            _externSymbols = new NodeCache <string, ExternSymbolNode>((string name) =>
            {
                return(new ExternSymbolNode(name));
            });

            _pInvokeModuleFixups = new NodeCache <string, PInvokeModuleFixupNode>((string name) =>
            {
                return(new PInvokeModuleFixupNode(name));
            });

            _pInvokeMethodFixups = new NodeCache <Tuple <string, string>, PInvokeMethodFixupNode>((Tuple <string, string> key) =>
            {
                return(new PInvokeMethodFixupNode(key.Item1, key.Item2));
            });

            _methodEntrypoints = new NodeCache <MethodDesc, IMethodNode>(CreateMethodEntrypointNode);

            _unboxingStubs = new NodeCache <MethodDesc, IMethodNode>(CreateUnboxingStubNode);

            _fatFunctionPointers = new NodeCache <MethodDesc, FatFunctionPointerNode>(method =>
            {
                return(new FatFunctionPointerNode(method));
            });

            _gvmDependenciesNode = new NodeCache <MethodDesc, GVMDependenciesNode>(method =>
            {
                return(new GVMDependenciesNode(method));
            });

            _gvmTableEntries = new NodeCache <TypeDesc, TypeGVMEntriesNode>(type =>
            {
                return(new TypeGVMEntriesNode(type));
            });

            _shadowConcreteMethods = new NodeCache <MethodDesc, IMethodNode>(method =>
            {
                return(new ShadowConcreteMethodNode <MethodCodeNode>(method,
                                                                     (MethodCodeNode)MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific))));
            });

            _runtimeDeterminedMethods = new NodeCache <MethodDesc, IMethodNode>(method =>
            {
                return(new RuntimeDeterminedMethodNode(method,
                                                       MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific))));
            });

            _virtMethods = new NodeCache <MethodDesc, VirtualMethodUseNode>((MethodDesc method) =>
            {
                return(new VirtualMethodUseNode(method));
            });

            _readyToRunHelpers = new NodeCache <Tuple <ReadyToRunHelperId, Object>, ISymbolNode>(CreateReadyToRunHelperNode);

            _genericReadyToRunHelpersFromDict = new NodeCache <Tuple <ReadyToRunHelperId, object, TypeSystemEntity>, ISymbolNode>(data =>
            {
                return(new ReadyToRunGenericLookupFromDictionaryNode(this, data.Item1, data.Item2, data.Item3));
            });

            _genericReadyToRunHelpersFromType = new NodeCache <Tuple <ReadyToRunHelperId, object, TypeSystemEntity>, ISymbolNode>(data =>
            {
                return(new ReadyToRunGenericLookupFromTypeNode(this, data.Item1, data.Item2, data.Item3));
            });

            _indirectionNodes = new NodeCache <ISymbolNode, IndirectionNode>(symbol =>
            {
                return(new IndirectionNode(symbol));
            });

            _frozenStringNodes = new NodeCache <string, FrozenStringNode>((string data) =>
            {
                return(new FrozenStringNode(data, Target));
            });

            _interfaceDispatchCells = new NodeCache <Tuple <MethodDesc, string>, InterfaceDispatchCellNode>((Tuple <MethodDesc, string> callSiteCell) =>
            {
                return(new InterfaceDispatchCellNode(callSiteCell.Item1, callSiteCell.Item2));
            });

            _interfaceDispatchMaps = new NodeCache <TypeDesc, InterfaceDispatchMapNode>((TypeDesc type) =>
            {
                return(new InterfaceDispatchMapNode(type));
            });

            _runtimeMethodHandles = new NodeCache <MethodDesc, RuntimeMethodHandleNode>((MethodDesc method) =>
            {
                return(new RuntimeMethodHandleNode(this, method));
            });

            _interfaceDispatchMapIndirectionNodes = new NodeCache <TypeDesc, EmbeddedObjectNode>((TypeDesc type) =>
            {
                var dispatchMap = InterfaceDispatchMap(type);
                return(DispatchMapTable.NewNodeWithSymbol(dispatchMap, (indirectionNode) =>
                {
                    dispatchMap.SetDispatchMapIndex(this, DispatchMapTable.IndexOfEmbeddedObject(indirectionNode));
                }));
            });

            _genericCompositions = new NodeCache <GenericCompositionDetails, GenericCompositionNode>((GenericCompositionDetails details) =>
            {
                return(new GenericCompositionNode(details));
            });

            _eagerCctorIndirectionNodes = new NodeCache <MethodDesc, EmbeddedObjectNode>((MethodDesc method) =>
            {
                Debug.Assert(method.IsStaticConstructor);
                Debug.Assert(TypeSystemContext.HasEagerStaticConstructor((MetadataType)method.OwningType));
                return(EagerCctorTable.NewNode(MethodEntrypoint(method)));
            });

            _vTableNodes = new NodeCache <TypeDesc, VTableSliceNode>((TypeDesc type ) =>
            {
                if (CompilationModuleGroup.ShouldProduceFullType(type))
                {
                    return(new EagerlyBuiltVTableSliceNode(type));
                }
                else
                {
                    return(new LazilyBuiltVTableSliceNode(type));
                }
            });

            _methodGenericDictionaries = new NodeCache <MethodDesc, GenericDictionaryNode>(method =>
            {
                return(new MethodGenericDictionaryNode(method));
            });

            _typeGenericDictionaries = new NodeCache <TypeDesc, GenericDictionaryNode>(type =>
            {
                return(new TypeGenericDictionaryNode(type));
            });

            _genericDictionaryLayouts = new NodeCache <TypeSystemEntity, DictionaryLayoutNode>(methodOrType =>
            {
                return(new DictionaryLayoutNode(methodOrType));
            });

            _stringAllocators = new NodeCache <MethodDesc, IMethodNode>(constructor =>
            {
                return(new StringAllocatorMethodNode(constructor));
            });

            NativeLayout = new NativeLayoutHelper(this);
        }
Пример #33
0
 public void SetCorHeader(ISymbolNode symbol, int headerSize)
 {
     _corHeaderSymbol = symbol;
     _corHeaderSize   = headerSize;
 }
Пример #34
0
 public void AddRelocAtOffset(ISymbolNode symbol, RelocType relocType, int offset, int delta = 0)
 {
     Relocation symbolReloc = new Relocation(relocType, offset, symbol, delta);
     _relocs.Add(symbolReloc);
 }
Пример #35
0
 public void SetDebugDirectory(ISymbolNode symbol, int size)
 {
     _debugDirectorySymbol = symbol;
     _debugDirectorySize   = size;
 }
Пример #36
0
 private static bool IsSameSymbolNode(ISymbolNode symbolParameterNode, ISymbolNode symbolCompareNode)
 {
     return symbolParameterNode.Symbol.Equals(symbolCompareNode.Symbol);
 }
Пример #37
0
 internal void Add(ReadyToRunSectionType id, ObjectNode node, ISymbolNode startSymbol, ISymbolNode endSymbol = null)
 {
     _items.Add(new HeaderItem(id, node, startSymbol, endSymbol));
 }
Пример #38
0
 public int GetSymbolFilePosition(ISymbolNode symbol)
 {
     return(_sectionBuilder.GetSymbolFilePosition(symbol));
 }
Пример #39
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            var writer            = new NativeWriter();
            var fieldMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(fieldMapHashTable);

            foreach (var fieldMapping in factory.MetadataManager.GetFieldMapping(factory))
            {
                FieldDesc field = fieldMapping.Entity;

                if (field.IsLiteral || field.HasRva)
                {
                    continue;
                }

                FieldTableFlags flags;
                if (field.IsThreadStatic)
                {
                    flags = FieldTableFlags.ThreadStatic | FieldTableFlags.FieldOffsetEncodedDirectly;
                }
                else if (field.IsStatic)
                {
                    flags = FieldTableFlags.Static;

                    if (field.HasGCStaticBase)
                    {
                        flags |= FieldTableFlags.IsGcSection;
                    }

                    if (field.OwningType.HasInstantiation)
                    {
                        flags |= FieldTableFlags.FieldOffsetEncodedDirectly;
                    }
                }
                else
                {
                    flags = FieldTableFlags.Instance | FieldTableFlags.FieldOffsetEncodedDirectly;
                }

                if (fieldMapping.MetadataHandle != 0)
                {
                    flags |= FieldTableFlags.HasMetadataHandle;
                }

                if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    flags |= FieldTableFlags.IsAnyCanonicalEntry;
                }

                if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Universal))
                {
                    flags |= FieldTableFlags.IsUniversalCanonicalEntry;
                }

                // Grammar of a hash table entry:
                // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset

                Vertex vertex = writer.GetUnsignedConstant((uint)flags);

                uint declaringTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(field.OwningType));
                vertex = writer.GetTuple(vertex,
                                         writer.GetUnsignedConstant(declaringTypeId));

                if ((flags & FieldTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)(fieldMapping.MetadataHandle & MetadataManager.MetadataOffsetMask)));
                }
                else
                {
                    // No metadata handle means we need to store name
                    vertex = writer.GetTuple(vertex,
                                             writer.GetStringConstant(field.Name));
                }

                if ((flags & FieldTableFlags.IsUniversalCanonicalEntry) != 0)
                {
                    vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(checked ((uint)field.GetFieldOrdinal())));
                }
                else
                {
                    switch (flags & FieldTableFlags.StorageClass)
                    {
                    case FieldTableFlags.ThreadStatic:
                        // TODO: CoreRT
                        continue;

                    case FieldTableFlags.Static:
                    {
                        if (field.OwningType.HasInstantiation)
                        {
                            vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt)));
                        }
                        else
                        {
                            MetadataType metadataType = (MetadataType)field.OwningType;

                            ISymbolNode staticsNode = field.HasGCStaticBase ?
                                                      factory.TypeGCStaticsSymbol(metadataType) :
                                                      factory.TypeNonGCStaticsSymbol(metadataType);

                            if (!field.HasGCStaticBase)
                            {
                                uint index = _externalReferences.GetIndex(staticsNode, field.Offset.AsInt);
                                vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index));
                            }
                            else if (factory.Target.Abi == TargetAbi.CoreRT || factory.Target.Abi == TargetAbi.CppCodegen)
                            {
                                Debug.Assert(field.HasGCStaticBase);

                                uint index = _externalReferences.GetIndex(staticsNode);
                                vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index));
                                vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt)));
                            }
                        }
                    }
                    break;

                    case FieldTableFlags.Instance:
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)field.Offset.AsInt));
                        break;
                    }
                }

                int hashCode = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific).GetHashCode();
                fieldMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            byte[] hashTableBytes = writer.Save();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
Пример #40
0
        public void BuildSymbolDefinitionMap(ObjectNode node, ISymbolNode[] definedSymbols)
        {
            _offsetToDefName.Clear();
            foreach (ISymbolNode n in definedSymbols)
            {
                if (!_offsetToDefName.ContainsKey(n.Offset))
                {
                    _offsetToDefName[n.Offset] = new List<ISymbolNode>();
                }

                _offsetToDefName[n.Offset].Add(n);
            }

            var symbolNode = node as ISymbolNode;
            if (symbolNode != null)
            {
                _sb.Clear();
                AppendExternCPrefix(_sb);
                symbolNode.AppendMangledName(NodeFactory.NameMangler, _sb);
                _currentNodeZeroTerminatedName = _sb.Append('\0').ToUtf8String();
            }
            else
            {
                _currentNodeZeroTerminatedName = default(Utf8String);
            }
        }
Пример #41
0
 public Relocation(RelocType relocType, int offset, ISymbolNode target)
 {
     RelocType = relocType;
     Offset = offset;
     Target = target;
 }
Пример #42
0
 /// <summary>
 /// Add a symbol to the symbol map which defines the area of the binary between the two emitted symbols.
 /// This allows relocations (both position and size) to regions of the image. Both nodes must be in the
 /// same section and firstNode must be emitted before secondNode.
 /// </summary>
 public void AddSymbolForRange(ISymbolNode symbol, ISymbolNode firstNode, ISymbolNode secondNode)
 {
     _sectionBuilder.AddSymbolForRange(symbol, firstNode, secondNode);
 }
Пример #43
0
 public void EmitPointerReloc(ISymbolNode symbol)
 {
     if (_target.PointerSize == 8)
     {
         EmitReloc(symbol, RelocType.IMAGE_REL_BASED_DIR64);
     }
     else
     {
         throw new NotImplementedException();
     }
 }
Пример #44
0
 public void SetWin32Resources(ISymbolNode symbol, int resourcesSize)
 {
     _win32ResourcesSymbol = symbol;
     _win32ResourcesSize   = resourcesSize;
 }
Пример #45
0
 //------------------------------------------------------------
 // コンストラクタ。
 public EvaluatedSymbolNode(ISymbolNode aSymbolNode, IEvaluateNode aEvaluateNode)
 {
     SymbolNode   = aSymbolNode;
     EvaluateNode = aEvaluateNode;
 }
Пример #46
0
        public void BuildSymbolDefinitionMap(ISymbolNode[] definedSymbols)
        {
            _offsetToDefName.Clear();
            foreach (ISymbolNode n in definedSymbols)
            {
                if (!_offsetToDefName.ContainsKey(n.Offset))
                {
                    _offsetToDefName[n.Offset] = new List<string>();
                }

                string symbolToEmit = GetSymbolToEmitForTargetPlatform(n.MangledName);
                _offsetToDefName[n.Offset].Add(symbolToEmit);

                string alternateName = _nodeFactory.GetSymbolAlternateName(n);
                if (alternateName != null)
                {
                    symbolToEmit = GetSymbolToEmitForTargetPlatform(alternateName);
                    _offsetToDefName[n.Offset].Add(symbolToEmit);
                }
            }

            // First entry is the node (entry point) name.
            _currentNodeName = _offsetToDefName[0][0];
            // Publish it first.
            EmitSymbolDef(_currentNodeName);
        }
Пример #47
0
        public readonly ushort Index;           // インデックス値。

        //------------------------------------------------------------
        // コンストラクタ。
        public BCSymbolLink(ISymbolNode aSymbol, ushort aIndex)
        {
            TargetNode = aSymbol;
            Index      = aIndex;
        }
Пример #48
0
 public void EmitJMP(ISymbolNode symbol)
 {
     Builder.EmitByte(0xE9);
     Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
 }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            // Ensure the native layout blob has been saved
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            var writer           = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            Dictionary <int, HashSet <TypeDesc> > methodsEmitted = new Dictionary <int, HashSet <TypeDesc> >();

            // Get a list of all methods that have a method body and metadata from the metadata manager.
            foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping(factory))
            {
                MethodDesc method = mappingEntry.Entity;

                // The current format requires us to have an EEType for the owning type. We might want to lift this.
                if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType))
                {
                    continue;
                }

                // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail.
                if (!factory.MetadataManager.IsReflectionInvokable(method))
                {
                    continue;
                }

                // Only virtual methods are interesting
                if (!NeedsVirtualInvokeInfo(method))
                {
                    continue;
                }

                //
                // The vtable entries for each instantiated type might not necessarily exist.
                // Example 1:
                //      If there's a call to Foo<string>.Method1 and a call to Foo<int>.Method2, Foo<string> will
                //      not have Method2 in its vtable and Foo<int> will not have Method1.
                // Example 2:
                //      If there's a call to Foo<string>.Method1 and a call to Foo<object>.Method2, given that both
                //      of these instantiations share the same canonical form, Foo<__Canon> will have both method
                //      entries, and therefore Foo<string> and Foo<object> will have both entries too.
                // For this reason, the entries that we write to the map in CoreRT will be based on the canonical form
                // of the method's containing type instead of the open type definition.
                //

                TypeDesc containingTypeKey = method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);

                HashSet <TypeDesc> cache;
                if (!methodsEmitted.TryGetValue(mappingEntry.MetadataHandle, out cache))
                {
                    methodsEmitted[mappingEntry.MetadataHandle] = cache = new HashSet <TypeDesc>();
                }

                // Only one record is needed for any instantiation.
                if (!cache.Add(containingTypeKey))
                {
                    continue;
                }

                // Grammar of an entry in the hash table:
                // Virtual Method uses a normal slot
                // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1) + slot
                // OR
                // Generic Virtual Method
                // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1 + 1)

                int        parentHierarchyDistance;
                MethodDesc declaringMethodForSlot = GetDeclaringVirtualMethodAndHierarchyDistance(method, out parentHierarchyDistance);

                Vertex vertex = null;

                ISymbolNode containingTypeKeyNode = factory.NecessaryTypeSymbol(containingTypeKey);
                NativeLayoutMethodNameAndSignatureVertexNode nameAndSig       = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition());
                NativeLayoutPlacedSignatureVertexNode        placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig);

                if (method.HasInstantiation)
                {
                    vertex = writer.GetTuple(
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)),
                        writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset),
                        writer.GetUnsignedConstant(((uint)parentHierarchyDistance << 1) + VirtualInvokeTableEntry.GenericVirtualMethod));
                }
                else
                {
                    // Get the declaring method for slot on the instantiated declaring type
                    int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, declaringMethodForSlot, declaringMethodForSlot.OwningType, true);
                    Debug.Assert(slot != -1);

                    vertex = writer.GetTuple(
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)),
                        writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset));

                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)parentHierarchyDistance << 1),
                                             writer.GetUnsignedConstant((uint)slot));
                }

                int hashCode = containingTypeKey.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            byte[] hashTableBytes = writer.Save();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
Пример #50
0
        public void EmitReloc(ISymbolNode symbol, RelocType relocType)
        {
            AddRelocAtOffset(symbol, relocType, _data.Count);

            // And add space for the reloc
            switch (relocType)
            {
                case RelocType.IMAGE_REL_BASED_REL32:
                    EmitInt(0);
                    break;
                case RelocType.IMAGE_REL_BASED_DIR64:
                    EmitLong(0);
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
Пример #51
0
        protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly)
        {
            switch (Id)
            {
            case ReadyToRunHelperId.NewHelper:
            {
                TypeDesc target = (TypeDesc)Target;
                encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target));
                encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewObjectHelperForType(target)));
            }
            break;

            case ReadyToRunHelperId.VirtualCall:
            {
                MethodDesc targetMethod = (MethodDesc)Target;

                if (targetMethod.OwningType.IsInterface)
                {
                    encoder.EmitLEAQ(Register.R10, factory.InterfaceDispatchCell((MethodDesc)Target));
                    AddrMode jmpAddrMode = new AddrMode(Register.R10, null, 0, 0, AddrModeSize.Int64);
                    encoder.EmitJmpToAddrMode(ref jmpAddrMode);
                }
                else
                {
                    if (relocsOnly)
                    {
                        break;
                    }

                    AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64);
                    encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr);

                    int pointerSize = factory.Target.PointerSize;

                    int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod);
                    Debug.Assert(slot != -1);
                    AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize), 0, AddrModeSize.Int64);
                    encoder.EmitJmpToAddrMode(ref jmpAddrMode);
                }
            }
            break;

            case ReadyToRunHelperId.IsInstanceOf:
            {
                TypeDesc target = (TypeDesc)Target;
                encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target));
                encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, false)));
            }
            break;

            case ReadyToRunHelperId.CastClass:
            {
                TypeDesc target = (TypeDesc)Target;
                encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target));
                encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, true)));
            }
            break;

            case ReadyToRunHelperId.NewArr1:
            {
                TypeDesc target = (TypeDesc)Target;

                // TODO: Swap argument order instead
                encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0);
                encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target));
                encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewArrayHelperForType(target)));
            }
            break;

            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                MetadataType target = (MetadataType)Target;
                bool         hasLazyStaticConstructor = factory.TypeSystemContext.HasLazyStaticConstructor(target);
                encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target));

                if (!hasLazyStaticConstructor)
                {
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region.
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target));

                    AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32);
                    encoder.EmitCMP(ref initialized, 1);
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.GetThreadStaticBase:
            {
                MetadataType target = (MetadataType)Target;

                encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.TypeThreadStaticIndex(target));

                // First arg: address of the TypeManager slot that provides the helper with
                // information about module index and the type manager instance (which is used
                // for initialization on first access).
                AddrMode loadFromArg2 = new AddrMode(encoder.TargetRegister.Arg2, null, 0, 0, AddrModeSize.Int64);
                encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadFromArg2);

                // Second arg: index of the type in the ThreadStatic section of the modules
                AddrMode loadFromArg2AndDelta = new AddrMode(encoder.TargetRegister.Arg2, null, factory.Target.PointerSize, 0, AddrModeSize.Int64);
                encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromArg2AndDelta);

                if (!factory.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType));
                }
                else
                {
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target));
                    // TODO: performance optimization - inline the check verifying whether we need to trigger the cctor
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.GetGCStaticBase:
            {
                MetadataType target = (MetadataType)Target;

                encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target));
                AddrMode loadFromRax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64);
                encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax);
                encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax);

                if (!factory.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region.
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target));

                    AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32);
                    encoder.EmitCMP(ref initialized, 1);
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);

                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.DelegateCtor:
            {
                DelegateCreationInfo target = (DelegateCreationInfo)Target;

                if (target.TargetNeedsVTableLookup)
                {
                    AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64);
                    encoder.EmitMOV(encoder.TargetRegister.Arg2, ref loadFromThisPtr);

                    int slot = 0;
                    if (!relocsOnly)
                    {
                        slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, target.TargetMethod);
                    }

                    Debug.Assert(slot != -1);
                    AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Arg2, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64);
                    encoder.EmitMOV(encoder.TargetRegister.Arg2, ref loadFromSlot);
                }
                else
                {
                    ISymbolNode targetMethodNode = target.GetTargetNode(factory);
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.GetTargetNode(factory));
                }

                if (target.Thunk != null)
                {
                    Debug.Assert(target.Constructor.Method.Signature.Length == 3);
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg3, target.Thunk);
                }
                else
                {
                    Debug.Assert(target.Constructor.Method.Signature.Length == 2);
                }

                encoder.EmitJMP(target.Constructor);
            }
            break;

            case ReadyToRunHelperId.ResolveVirtualFunction:
            {
                MethodDesc targetMethod = (MethodDesc)Target;
                if (targetMethod.OwningType.IsInterface)
                {
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.InterfaceDispatchCell(targetMethod));
                    encoder.EmitJMP(factory.ExternSymbol("RhpResolveInterfaceMethod"));
                }
                else
                {
                    if (relocsOnly)
                    {
                        break;
                    }

                    AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64);
                    encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr);

                    int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod);
                    Debug.Assert(slot != -1);
                    AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64);
                    encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromSlot);
                    encoder.EmitRET();
                }
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
Пример #52
0
 public void AddRelocAtOffset(ISymbolNode symbol, RelocType relocType, int offset, int delta = 0)
 {
     Relocation symbolReloc = new Relocation();
     symbolReloc.Target = symbol;
     symbolReloc.RelocType = relocType;
     symbolReloc.Offset = offset;
     symbolReloc.Delta = delta;
     _relocs.Add(symbolReloc);
 }
Пример #53
0
        public override void AttachToDependencyGraph(DependencyAnalyzerBase <NodeFactory> graph)
        {
            Header = new HeaderNode(Target);

            var compilerIdentifierNode = new CompilerIdentifierNode(Target);

            Header.Add(Internal.Runtime.ReadyToRunSectionType.CompilerIdentifier, compilerIdentifierNode, compilerIdentifierNode);

            RuntimeFunctionsTable = new RuntimeFunctionsTableNode(this);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.RuntimeFunctions, RuntimeFunctionsTable, RuntimeFunctionsTable);

            RuntimeFunctionsGCInfo = new RuntimeFunctionsGCInfoNode();
            graph.AddRoot(RuntimeFunctionsGCInfo, "GC info is always generated");

            ProfileDataSection = new ProfileDataSectionNode();
            Header.Add(Internal.Runtime.ReadyToRunSectionType.ProfileDataInfo, ProfileDataSection, ProfileDataSection.StartSymbol);

            ExceptionInfoLookupTableNode exceptionInfoLookupTableNode = new ExceptionInfoLookupTableNode(this);

            Header.Add(Internal.Runtime.ReadyToRunSectionType.ExceptionInfo, exceptionInfoLookupTableNode, exceptionInfoLookupTableNode);
            graph.AddRoot(exceptionInfoLookupTableNode, "ExceptionInfoLookupTable is always generated");

            MethodEntryPointTable = new MethodEntryPointTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.MethodDefEntryPoints, MethodEntryPointTable, MethodEntryPointTable);

            ManifestMetadataTable = new ManifestMetadataTableNode(InputModuleContext.GlobalContext);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.ManifestMetadata, ManifestMetadataTable, ManifestMetadataTable);

            Resolver.SetModuleIndexLookup(ManifestMetadataTable.ModuleToIndex);

            InstanceEntryPointTable = new InstanceEntryPointTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.InstanceMethodEntryPoints, InstanceEntryPointTable, InstanceEntryPointTable);

            TypesTable = new TypesTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.AvailableTypes, TypesTable, TypesTable);

            ImportSectionsTable = new ImportSectionsTableNode(this);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.ImportSections, ImportSectionsTable, ImportSectionsTable.StartSymbol);

            DebugInfoTable = new DebugInfoTableNode(Target);
            Header.Add(Internal.Runtime.ReadyToRunSectionType.DebugInfo, DebugInfoTable, DebugInfoTable);

            // Core library attributes are checked FAR more often than other dlls
            // attributes, so produce a highly efficient table for determining if they are
            // present. Other assemblies *MAY* benefit from this feature, but it doesn't show
            // as useful at this time.
            if (this.AttributePresenceFilter != null)
            {
                Header.Add(Internal.Runtime.ReadyToRunSectionType.AttributePresence, AttributePresenceFilter, AttributePresenceFilter);
            }

            EagerImports = new ImportSectionNode(
                "EagerImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_EAGER,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(EagerImports);

            // All ready-to-run images have a module import helper which gets patched by the runtime on image load
            ModuleImport = new Import(EagerImports, new ReadyToRunHelperSignature(
                                          ILCompiler.ReadyToRunHelper.Module));
            graph.AddRoot(ModuleImport, "Module import is required by the R2R format spec");

            if (Target.Architecture != TargetArchitecture.X86)
            {
                Import personalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
                                                                 ILCompiler.ReadyToRunHelper.PersonalityRoutine));
                PersonalityRoutine = new ImportThunk(
                    ILCompiler.ReadyToRunHelper.PersonalityRoutine, this, personalityRoutineImport, useVirtualCall: false);
                graph.AddRoot(PersonalityRoutine, "Personality routine is faster to root early rather than referencing it from each unwind info");

                Import filterFuncletPersonalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
                                                                              ILCompiler.ReadyToRunHelper.PersonalityRoutineFilterFunclet));
                FilterFuncletPersonalityRoutine = new ImportThunk(
                    ILCompiler.ReadyToRunHelper.PersonalityRoutineFilterFunclet, this, filterFuncletPersonalityRoutineImport, useVirtualCall: false);
                graph.AddRoot(FilterFuncletPersonalityRoutine, "Filter funclet personality routine is faster to root early rather than referencing it from each unwind info");
            }

            MethodImports = new ImportSectionNode(
                "MethodImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: true);
            ImportSectionsTable.AddEmbeddedObject(MethodImports);

            DispatchImports = new ImportSectionNode(
                "DispatchImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: true);
            ImportSectionsTable.AddEmbeddedObject(DispatchImports);

            HelperImports = new ImportSectionNode(
                "HelperImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: false,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(HelperImports);

            PrecodeImports = new ImportSectionNode(
                "PrecodeImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE,
                (byte)Target.PointerSize,
                emitPrecode: true,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(PrecodeImports);

            StringImports = new ImportSectionNode(
                "StringImports",
                CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STRING_HANDLE,
                CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_UNKNOWN,
                (byte)Target.PointerSize,
                emitPrecode: true,
                emitGCRefMap: false);
            ImportSectionsTable.AddEmbeddedObject(StringImports);

            graph.AddRoot(ImportSectionsTable, "Import sections table is always generated");
            graph.AddRoot(ModuleImport, "Module import is always generated");
            graph.AddRoot(EagerImports, "Eager imports are always generated");
            graph.AddRoot(MethodImports, "Method imports are always generated");
            graph.AddRoot(DispatchImports, "Dispatch imports are always generated");
            graph.AddRoot(HelperImports, "Helper imports are always generated");
            graph.AddRoot(PrecodeImports, "Precode helper imports are always generated");
            graph.AddRoot(StringImports, "String imports are always generated");
            graph.AddRoot(Header, "ReadyToRunHeader is always generated");
            graph.AddRoot(CopiedCorHeaderNode, "MSIL COR header is always generated");

            if (Win32ResourcesNode != null)
            {
                graph.AddRoot(Win32ResourcesNode, "Win32 Resources are placed if not empty");
            }

            MetadataManager.AttachToDependencyGraph(graph);
        }
Пример #54
0
 public void EmitPointerReloc(ISymbolNode symbol, int delta = 0)
 {
     EmitReloc(symbol, (_target.PointerSize == 8) ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW, delta);
 }
Пример #55
0
        private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup)
        {
            switch (id)
            {
            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEW:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                Debug.Assert(type.IsDefType);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewHelper, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEWARR_1:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                Debug.Assert(type.IsSzArray);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewArr1, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_ISINSTANCEOF:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                // ECMA-335 III.4.3:  If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T
                if (type.IsNullable)
                {
                    type = type.Instantiation[0];
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.IsInstanceOf, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_CHKCAST:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                // ECMA-335 III.4.3:  If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T
                if (type.IsNullable)
                {
                    type = type.Instantiation[0];
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.CastClass, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE:
            {
                var type = HandleToObject(pResolvedToken.hClass);
                if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    return(false);
                }

                pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, type, _signatureContext));
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
            {
                // Token == 0 means "initialize this class". We only expect RyuJIT to call it for this case.
                Debug.Assert(pResolvedToken.token == 0 && pResolvedToken.tokenScope == null);
                Debug.Assert(pGenericLookupKind.needsRuntimeLookup);

                DefType typeToInitialize = (DefType)MethodBeingCompiled.OwningType;
                Debug.Assert(typeToInitialize.IsCanonicalSubtype(CanonicalFormKind.Any));

                DefType  helperArg = typeToInitialize.ConvertToSharedRuntimeDeterminedForm();
                TypeDesc contextType;
                if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ)
                {
                    contextType = methodFromContext(pResolvedToken.tokenContext).OwningType;
                }
                else
                {
                    contextType = null;
                }
                ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper(
                    pGenericLookupKind.runtimeLookupKind,
                    ReadyToRunHelperId.GetNonGCStaticBase,
                    helperArg,
                    contextType,
                    _signatureContext);
                pLookup = CreateConstLookupToSymbol(helper);
            }
            break;

            case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_HANDLE:
            {
                Debug.Assert(pGenericLookupKind.needsRuntimeLookup);

                ReadyToRunHelperId helperId  = (ReadyToRunHelperId)pGenericLookupKind.runtimeLookupFlags;
                object             helperArg = HandleToObject((IntPtr)pGenericLookupKind.runtimeLookupArgs);
                if (helperArg is MethodDesc methodArg)
                {
                    helperArg = new MethodWithToken(methodArg, new ModuleToken(_tokenContext, pResolvedToken.token));
                }
                TypeDesc contextType;
                if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ)
                {
                    contextType = methodFromContext(pResolvedToken.tokenContext).OwningType;
                }
                else
                {
                    contextType = null;
                }
                ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper(
                    pGenericLookupKind.runtimeLookupKind,
                    helperId,
                    helperArg,
                    contextType,
                    _signatureContext);
                pLookup = CreateConstLookupToSymbol(helper);
            }
            break;

            default:
                throw new NotImplementedException("ReadyToRun: " + id.ToString());
            }
            return(true);
        }
Пример #56
0
 public IndirectionNode(ISymbolNode indirectedNode)
 {
     _indirectedNode = indirectedNode;
 }
Пример #57
0
        private void ComputeLookup(ref CORINFO_RESOLVED_TOKEN pResolvedToken, object entity, ReadyToRunHelperId helperId, ref CORINFO_LOOKUP lookup)
        {
            if (_compilation.NeedsRuntimeLookup(helperId, entity))
            {
                lookup.lookupKind.needsRuntimeLookup = true;
                lookup.runtimeLookup.signature       = null;

                MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext);

                // Do not bother computing the runtime lookup if we are inlining. The JIT is going
                // to abort the inlining attempt anyway.
                if (contextMethod != MethodBeingCompiled)
                {
                    return;
                }

                // Necessary type handle is not something that can be in a dictionary (only a constructed type).
                // We only use necessary type handles if we can do a constant lookup.
                if (helperId == ReadyToRunHelperId.NecessaryTypeHandle)
                {
                    helperId = ReadyToRunHelperId.TypeHandle;
                }

                GenericDictionaryLookup genericLookup = _compilation.ComputeGenericLookup(contextMethod, helperId, entity);

                if (genericLookup.UseHelper)
                {
                    lookup.runtimeLookup.indirections    = CORINFO.USEHELPER;
                    lookup.lookupKind.runtimeLookupFlags = (ushort)helperId;
                    lookup.lookupKind.runtimeLookupArgs  = (void *)ObjectToHandle(entity);
                }
                else
                {
                    if (genericLookup.ContextSource == GenericContextSource.MethodParameter)
                    {
                        lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_METHOD;
                    }
                    else
                    {
                        lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_CLASS;
                    }

                    lookup.runtimeLookup.indirections = (ushort)genericLookup.NumberOfIndirections;
                    lookup.runtimeLookup.offset0      = (IntPtr)genericLookup[0];
                    if (genericLookup.NumberOfIndirections > 1)
                    {
                        lookup.runtimeLookup.offset1 = (IntPtr)genericLookup[1];
                    }
                    lookup.runtimeLookup.testForFixup         = false; // TODO: this will be needed in true multifile
                    lookup.runtimeLookup.testForNull          = false;
                    lookup.runtimeLookup.indirectFirstOffset  = false;
                    lookup.runtimeLookup.indirectSecondOffset = false;
                    lookup.lookupKind.runtimeLookupFlags      = 0;
                    lookup.lookupKind.runtimeLookupArgs       = null;
                }

                lookup.lookupKind.runtimeLookupKind = GetLookupKindFromContextSource(genericLookup.ContextSource);
            }
            else
            {
                lookup.lookupKind.needsRuntimeLookup = false;
                ISymbolNode constLookup = _compilation.SymbolNodeFactory.ComputeConstantLookup(helperId, entity, _signatureContext);
                lookup.constLookup = CreateConstLookupToSymbol(constLookup);
            }
        }
Пример #58
0
        // Returns size of the emitted symbol reference
        public int EmitSymbolReference(ISymbolNode target, int delta, RelocType relocType)
        {
            string targetName = GetSymbolToEmitForTargetPlatform(target.MangledName);

            return EmitSymbolRef(targetName, relocType, delta);
        }
Пример #59
0
 public void EmitJMP(ISymbolNode symbol)
 {
     Builder.EmitByte(0xE9);
     Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
 }