private void AddTypeNode(EETypeNode node)
 {
     if (node != null && !_nodes.Contains(node) && !_visited.Contains(node))
     {
         _visited.Add(node);
         EETypeNode baseTypeNode;
         if (node.Type.BaseType != null)
         {
             _typeToNodeMap.TryGetValue(node.Type.BaseType, out baseTypeNode);
             if (!node.Type.IsPrimitive)
                 AddTypeNode(baseTypeNode);
             else if (!_nodes.Contains(baseTypeNode)) _nodes.Add(baseTypeNode);
         }
         foreach (var field in node.Type.GetFields())
         {
             EETypeNode fieldNode;
             _typeToNodeMap.TryGetValue(field.FieldType, out fieldNode);
             if (fieldNode != null)
             {
                 if (fieldNode.Type.IsValueType)
                 {
                     if (!fieldNode.Type.IsPrimitive)
                         AddTypeNode(fieldNode);
                     else if (!_nodes.Contains(fieldNode)) _nodes.Add(fieldNode);
                 }
             }
         }
         if (!_nodes.Contains(node)) _nodes.Add(node);
     }
 }
Beispiel #2
0
        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencyList = new DependencyList();

            if (factory.TypeSystemContext.HasEagerStaticConstructor(_type))
            {
                dependencyList.Add(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor");
            }

            dependencyList.Add(factory.GCStaticsRegion, "GCStatics Region");
            if (factory.Target.Abi == TargetAbi.CoreRT)
            {
                dependencyList.Add(GetGCStaticEETypeNode(factory), "GCStatic EEType");
                if (_preInitFieldInfos != null)
                {
                    dependencyList.Add(factory.GCStaticsPreInitDataNode(_type), "PreInitData node");
                }
            }
            else
            {
                dependencyList.Add(((UtcNodeFactory)factory).TypeGCStaticDescSymbol(_type), "GC Desc");
            }

            dependencyList.Add(factory.GCStaticIndirection(_type), "GC statics indirection");
            EETypeNode.AddDependenciesForStaticsNode(factory, _type, ref dependencyList);

            return(dependencyList);
        }
Beispiel #3
0
        public ExternEETypeSymbolNode(NodeFactory factory, TypeDesc type)
            : base("__EEType_" + factory.NameMangler.GetMangledTypeName(type))
        {
            _type = type;

            EETypeNode.CheckCanGenerateEEType(factory, type);
        }
        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 ISymbolNode[] { this }));
            }

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

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            foreach (var mappingEntry in factory.MetadataManager.GetTypeDefinitionMapping())
            {
                if (!factory.CompilationModuleGroup.ContainsType(mappingEntry.Entity))
                {
                    continue;
                }

                // We are looking for any EEType - constructed or not, it has to be in the mapping
                // table so that we can map it to metadata.
                EETypeNode node = null;

                if (!mappingEntry.Entity.IsGenericDefinition)
                {
                    node = factory.ConstructedTypeSymbol(mappingEntry.Entity) as EETypeNode;
                }

                if (node == null || !node.Marked)
                {
                    // This might have been a typeof() expression.
                    node = factory.NecessaryTypeSymbol(mappingEntry.Entity) as EETypeNode;
                }

                if (node.Marked)
                {
                    Vertex vertex = writer.GetTuple(
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(node)),
                        writer.GetUnsignedConstant((uint)mappingEntry.MetadataHandle)
                        );

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

            MemoryStream ms = new MemoryStream();

            writer.Save(ms);
            byte[] hashTableBytes = ms.ToArray();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol }));
        }
Beispiel #5
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 ISymbolNode[] { this }));
            }

            ObjectDataBuilder builder = new ObjectDataBuilder(factory);

            foreach (var mappingEntry in factory.MetadataManager.GetTypeDefinitionMapping())
            {
                if (!factory.CompilationModuleGroup.ContainsType(mappingEntry.Entity))
                {
                    continue;
                }

                // We are looking for any EEType - constructed or not, it has to be in the mapping
                // table so that we can map it to metadata.
                EETypeNode node = null;

                if (!mappingEntry.Entity.IsGenericDefinition)
                {
                    node = factory.ConstructedTypeSymbol(mappingEntry.Entity) as EETypeNode;
                }

                if (node == null || !node.Marked)
                {
                    // This might have been a typeof() expression.
                    node = factory.NecessaryTypeSymbol(mappingEntry.Entity) as EETypeNode;
                }

                if (node.Marked)
                {
                    // TODO: this format got very inefficient due to not being able to use RVAs
                    //       replace with a hash table

                    builder.EmitPointerReloc(node);
                    builder.EmitInt(mappingEntry.MetadataHandle);

                    if (factory.Target.PointerSize == 8)
                    {
                        builder.EmitInt(0); // Pad
                    }
                }
            }

            _endSymbol.SetSymbolOffset(builder.CountBytes);

            builder.DefinedSymbols.Add(this);
            builder.DefinedSymbols.Add(_endSymbol);

            return(builder.ToObjectData());
        }
Beispiel #6
0
        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencyList = new DependencyList();

            if (factory.TypeSystemContext.HasEagerStaticConstructor(_type))
            {
                dependencyList.Add(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor");
            }

            dependencyList.Add(((UtcNodeFactory)factory).TypeThreadStaticGCDescNode(_type), "GC Desc");
            EETypeNode.AddDependenciesForStaticsNode(factory, _type, ref dependencyList);
            return(dependencyList);
        }
Beispiel #7
0
        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencyList = null;

            if (factory.PreinitializationManager.HasEagerStaticConstructor(_type))
            {
                dependencyList = new DependencyList();
                dependencyList.Add(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor");
            }

            EETypeNode.AddDependenciesForStaticsNode(factory, _type, ref dependencyList);

            return(dependencyList);
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            Debug.Assert((EETypeNode.GetVTableOffset(factory.Target.PointerSize) % factory.Target.PointerSize) == 0, "vtable offset must be aligned");
            ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly);

            objData.AddSymbol(this);

            if (!relocsOnly)
            {
                var tableOffset = EETypeNode.GetVTableOffset(factory.Target.PointerSize) / factory.Target.PointerSize;
                objData.EmitInt(tableOffset + VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, _targetMethod, _targetMethod.OwningType));
            }
            return(objData.ToObjectData());
        }
Beispiel #9
0
        public override IEnumerable <DependencyListEntry> GetStaticDependencies(NodeFactory factory)
        {
            DependencyList result = new DependencyList();

            result.Add(new DependencyListEntry(GetGCStaticEETypeNode(factory), "ThreadStatic EEType"));

            if (factory.PreinitializationManager.HasEagerStaticConstructor(_type))
            {
                result.Add(new DependencyListEntry(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor"));
            }

            EETypeNode.AddDependenciesForStaticsNode(factory, _type, ref result);
            return(result);
        }
Beispiel #10
0
        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencyList = new DependencyList();

            if (factory.PreinitializationManager.HasEagerStaticConstructor(_type))
            {
                dependencyList.Add(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor");
            }

            if (_type.Module.GetGlobalModuleType().GetStaticConstructor() is MethodDesc moduleCctor)
            {
                dependencyList.Add(factory.MethodEntrypoint(moduleCctor), "Static base in a module with initializer");
            }

            EETypeNode.AddDependenciesForStaticsNode(factory, _type, ref dependencyList);

            return(dependencyList);
        }
Beispiel #11
0
        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
        {
            DependencyList dependencyList = new DependencyList();

            if (factory.PreinitializationManager.HasEagerStaticConstructor(_type))
            {
                dependencyList.Add(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor");
            }

            ModuleUseBasedDependencyAlgorithm.AddDependenciesDueToModuleUse(ref dependencyList, factory, _type.Module);

            dependencyList.Add(factory.GCStaticsRegion, "GCStatics Region");

            dependencyList.Add(factory.GCStaticIndirection(_type), "GC statics indirection");
            EETypeNode.AddDependenciesForStaticsNode(factory, _type, ref dependencyList);

            return(dependencyList);
        }
Beispiel #12
0
        public override IEnumerable <DependencyListEntry> GetStaticDependencies(NodeFactory factory)
        {
            DependencyList result = new DependencyList();

            result.Add(new DependencyListEntry(GetGCStaticEETypeNode(factory), "ThreadStatic MethodTable"));

            if (factory.PreinitializationManager.HasEagerStaticConstructor(_type))
            {
                result.Add(new DependencyListEntry(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor"));
            }

            if (_type.Module.GetGlobalModuleType().GetStaticConstructor() is MethodDesc moduleCctor)
            {
                result.Add(factory.MethodEntrypoint(moduleCctor), "Static base in a module with initializer");
            }

            EETypeNode.AddDependenciesForStaticsNode(factory, _type, ref result);
            return(result);
        }
Beispiel #13
0
        public override IEnumerable <CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
        {
            // The generic dictionary layout is shared between all the canonically equivalent
            // instantiations. We need to track the dependencies of all canonical method bodies
            // that use the same dictionary layout.
            foreach (var method in _owningType.GetAllMethods())
            {
                if (!EETypeNode.MethodHasNonGenericILMethodBody(method))
                {
                    continue;
                }

                // If a canonical method body was compiled, we need to track the dictionary
                // dependencies in the context of the concrete type that owns this dictionary.
                yield return(new CombinedDependencyListEntry(
                                 factory.ShadowConcreteMethod(method),
                                 factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)),
                                 "Generic dictionary dependency"));
            }
        }
        protected override void EmitLoadGenericContext(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly)
        {
            // We start with context register pointing to the MethodTable
            Register contextRegister = GetContextRegister(ref encoder);

            // Locate the VTable slot that points to the dictionary
            int vtableSlot = 0;

            if (!relocsOnly)
            {
                // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly.
                vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)_dictionaryOwner);
            }

            int pointerSize = factory.Target.PointerSize;
            int slotOffset  = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize);

            // Load the dictionary pointer from the VTable
            encoder.EmitLDR(contextRegister, contextRegister, slotOffset);
        }
        public TypeFixupSignature TypeSignature(ReadyToRunFixupKind fixupKind, TypeDesc typeDesc, SignatureContext signatureContext)
        {
            Dictionary <TypeDesc, TypeFixupSignature> perFixupKindMap;

            if (!_typeSignatures.TryGetValue(fixupKind, out perFixupKindMap))
            {
                perFixupKindMap = new Dictionary <TypeDesc, TypeFixupSignature>();
                _typeSignatures.Add(fixupKind, perFixupKindMap);
            }

            TypeFixupSignature signature;

            if (!perFixupKindMap.TryGetValue(typeDesc, out signature))
            {
                EETypeNode.CheckCanGenerateEEType(this, typeDesc);
                signature = new TypeFixupSignature(fixupKind, typeDesc, signatureContext);
                perFixupKindMap.Add(typeDesc, signature);
            }
            return(signature);
        }
        protected override void EmitLoadGenericContext(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly)
        {
            // We start with Arg0 pointing to the EEType

            // Locate the VTable slot that points to the dictionary
            int vtableSlot = 0;

            if (!relocsOnly)
            {
                // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly.
                vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)_dictionaryOwner);
            }

            int pointerSize = factory.Target.PointerSize;
            int slotOffset  = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize);

            // Load the dictionary pointer from the VTable
            AddrMode loadDictionary = new AddrMode(encoder.TargetRegister.Arg0, null, slotOffset, 0, AddrModeSize.Int64);

            encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadDictionary);
        }
        protected override void EmitCode(NodeFactory factory, ref ARM64Emitter 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.IntraProcedureCallScratch1, encoder.TargetRegister.Arg0, 0);
                encoder.EmitLDR(encoder.TargetRegister.IntraProcedureCallScratch1, encoder.TargetRegister.IntraProcedureCallScratch1,
                                EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize));
                encoder.EmitJMP(encoder.TargetRegister.IntraProcedureCallScratch1);
            }
            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.EmitSUB(encoder.TargetRegister.Arg3, encoder.TargetRegister.Result, NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
                    encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg3, (short)factory.Target.PointerSize);
                    encoder.EmitCMP(encoder.TargetRegister.Arg2, 1);
                    encoder.EmitRETIfEqual();

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

                    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.GetClassConstructorContextSize(factory.Target));

                    encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, (short)factory.Target.PointerSize);
                    encoder.EmitCMP(encoder.TargetRegister.Arg3, 1);
                    encoder.EmitJE(factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType));

                    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);

                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.EmitSUB(encoder.TargetRegister.Arg2, NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
                    encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, (short)factory.Target.PointerSize);
                    encoder.EmitCMP(encoder.TargetRegister.Arg3, 1);
                    encoder.EmitRETIfEqual();

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

                    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
                {
                    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:
            {
                MethodDesc targetMethod = (MethodDesc)Target;
                if (targetMethod.OwningType.IsInterface)
                {
                    // Not tested
                    encoder.EmitINT3();

                    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();
            }
        }
Beispiel #18
0
        public override IEnumerable <CombinedDependencyListEntry> SearchDynamicDependencies(List <DependencyNodeCore <NodeFactory> > markedNodes, int firstNode, NodeFactory factory)
        {
            Debug.Assert(_method.IsVirtual && _method.HasInstantiation);

            List <CombinedDependencyListEntry> dynamicDependencies = new List <CombinedDependencyListEntry>();

            for (int i = firstNode; i < markedNodes.Count; i++)
            {
                DependencyNodeCore <NodeFactory> entry = markedNodes[i];
                EETypeNode entryAsEETypeNode           = entry as EETypeNode;

                if (entryAsEETypeNode == null)
                {
                    continue;
                }

                TypeDesc potentialOverrideType = entryAsEETypeNode.Type;
                if (!(potentialOverrideType is DefType))
                {
                    continue;
                }

                Debug.Assert(!potentialOverrideType.IsRuntimeDeterminedSubtype);

                if (_method.OwningType.HasSameTypeDefinition(potentialOverrideType) && potentialOverrideType.IsInterface && (potentialOverrideType != _method.OwningType))
                {
                    if (_method.OwningType.CanCastTo(potentialOverrideType))
                    {
                        // Variance expansion
                        MethodDesc matchingMethodOnRelatedVariantMethod = potentialOverrideType.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
                        matchingMethodOnRelatedVariantMethod = _method.Context.GetInstantiatedMethod(matchingMethodOnRelatedVariantMethod, _method.Instantiation);
                        dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(matchingMethodOnRelatedVariantMethod), null, "GVM Variant Interface dependency"));
                    }
                }

                // If this is an interface gvm, look for types that implement the interface
                // and other instantantiations that have the same canonical form.
                // This ensure the various slot numbers remain equivalent across all types where there is an equivalence
                // relationship in the vtable.
                if (_method.OwningType.IsInterface)
                {
                    if (potentialOverrideType.IsInterface)
                    {
                        continue;
                    }

                    foreach (DefType interfaceImpl in potentialOverrideType.RuntimeInterfaces)
                    {
                        if (interfaceImpl.ConvertToCanonForm(CanonicalFormKind.Specific) == _method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific))
                        {
                            // Find if the type implements this method. (Note, do this comparision against the generic definition of the method, not the
                            // specific method instantiation that is "method"
                            MethodDesc genericDefinition = interfaceImpl.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
                            MethodDesc slotDecl          = potentialOverrideType.ResolveInterfaceMethodTarget(genericDefinition);
                            if (slotDecl != null)
                            {
                                CreateDependencyForMethodSlotAndInstantiation(slotDecl, dynamicDependencies, factory);
                            }
                        }
                    }
                }
                else
                {
                    // TODO: Ensure GVM Canon Target

                    TypeDesc overrideTypeCanonCur      = potentialOverrideType;
                    TypeDesc methodCanonContainingType = _method.OwningType;
                    while (overrideTypeCanonCur != null)
                    {
                        if (overrideTypeCanonCur.ConvertToCanonForm(CanonicalFormKind.Specific) == methodCanonContainingType.ConvertToCanonForm(CanonicalFormKind.Specific))
                        {
                            MethodDesc methodDefInDerivedType = potentialOverrideType.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
                            if (methodDefInDerivedType != null)
                            {
                                CreateDependencyForMethodSlotAndInstantiation(methodDefInDerivedType, dynamicDependencies, factory);
                            }

                            MethodDesc slotDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(_method);
                            if (slotDecl != null)
                            {
                                CreateDependencyForMethodSlotAndInstantiation(slotDecl.GetMethodDefinition(), dynamicDependencies, factory);
                            }
                        }

                        overrideTypeCanonCur = overrideTypeCanonCur.BaseType;
                    }
                }
            }
            return(dynamicDependencies);
        }
Beispiel #19
0
        public override IEnumerable <CombinedDependencyListEntry> SearchDynamicDependencies(List <DependencyNodeCore <NodeFactory> > markedNodes, int firstNode, NodeFactory factory)
        {
            List <CombinedDependencyListEntry> dynamicDependencies = new List <CombinedDependencyListEntry>();

            TypeDesc methodOwningType = _method.OwningType;
            bool     methodIsShared   = _method.IsSharedByGenericInstantiations;

            TypeSystemContext context = _method.Context;

            for (int i = firstNode; i < markedNodes.Count; i++)
            {
                DependencyNodeCore <NodeFactory> entry = markedNodes[i];
                EETypeNode entryAsEETypeNode           = entry as EETypeNode;

                if (entryAsEETypeNode == null)
                {
                    continue;
                }

                TypeDesc potentialOverrideType = entryAsEETypeNode.Type;
                if (!potentialOverrideType.IsDefType || potentialOverrideType.IsInterface)
                {
                    continue;
                }

                // If method is canonical, don't allow using it with non-canonical types - we can wait until
                // we see the __Canon instantiation. If there isn't one, the canonical method wouldn't be useful anyway.
                if (methodIsShared &&
                    potentialOverrideType.ConvertToCanonForm(CanonicalFormKind.Specific) != potentialOverrideType)
                {
                    continue;
                }

                // Similarly, if the type is canonical but this method instantiation isn't, don't mix them.
                if (!methodIsShared &&
                    potentialOverrideType.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    continue;
                }

                // If this is an interface gvm, look for types that implement the interface
                // and other instantantiations that have the same canonical form.
                // This ensure the various slot numbers remain equivalent across all types where there is an equivalence
                // relationship in the vtable.
                if (methodOwningType.IsInterface)
                {
                    // We go over definitions because a single canonical interface method could actually be implemented
                    // by multiple methods - consider:
                    //
                    // class Foo<T, U> : IFoo<T>, IFoo<U>, IFoo<string> { }
                    //
                    // If we ask what implements IFoo<__Canon>.Method, the answer could be "three methods"
                    // and that's expected. We therefore resolve IFoo<__Canon>.Method for each IFoo<!0>.Method,
                    // IFoo<!1>.Method, and IFoo<string>.Method, adding GVMDependencies for each.
                    TypeDesc  potentialOverrideDefinition   = potentialOverrideType.GetTypeDefinition();
                    DefType[] potentialInterfaces           = potentialOverrideType.RuntimeInterfaces;
                    DefType[] potentialDefinitionInterfaces = potentialOverrideDefinition.RuntimeInterfaces;
                    for (int interfaceIndex = 0; interfaceIndex < potentialInterfaces.Length; interfaceIndex++)
                    {
                        if (potentialInterfaces[interfaceIndex].ConvertToCanonForm(CanonicalFormKind.Specific) == methodOwningType)
                        {
                            MethodDesc interfaceMethod = _method.GetMethodDefinition();
                            if (methodOwningType.HasInstantiation)
                            {
                                interfaceMethod = context.GetMethodForInstantiatedType(
                                    _method.GetTypicalMethodDefinition(), (InstantiatedType)potentialDefinitionInterfaces[interfaceIndex]);
                            }

                            MethodDesc slotDecl = potentialOverrideDefinition.InstantiateAsOpen().ResolveInterfaceMethodTarget(interfaceMethod);
                            if (slotDecl == null)
                            {
                                // The method might be implemented through a default interface method
                                var result = potentialOverrideDefinition.InstantiateAsOpen().ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, out slotDecl);
                                if (result != DefaultInterfaceMethodResolution.DefaultImplementation)
                                {
                                    slotDecl = null;
                                }
                            }

                            if (slotDecl != null)
                            {
                                TypeDesc[] openInstantiation = new TypeDesc[_method.Instantiation.Length];
                                for (int instArg = 0; instArg < openInstantiation.Length; instArg++)
                                {
                                    openInstantiation[instArg] = context.GetSignatureVariable(instArg, method: true);
                                }
                                MethodDesc implementingMethodInstantiation = slotDecl.MakeInstantiatedMethod(openInstantiation).InstantiateSignature(potentialOverrideType.Instantiation, _method.Instantiation);
                                dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(implementingMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Specific)), null, "ImplementingMethodInstantiation"));
                            }
                        }
                    }
                }
                else
                {
                    // This is not an interface GVM. Check whether the current type overrides the virtual method.
                    // We might need to change what virtual method we ask about - consider:
                    //
                    // class Base<T> { virtual Method(); }
                    // class Derived : Base<string> { override Method(); }
                    //
                    // We need to resolve Base<__Canon>.Method on Derived, but if we were to ask the virtual
                    // method resolution algorithm, the answer would be "does not override" because Base<__Canon>
                    // is not even in the inheritance hierarchy.
                    //
                    // So we need to modify the question to resolve Base<string>.Method instead and then
                    // canonicalize the result.

                    TypeDesc overrideTypeCur = potentialOverrideType;
                    do
                    {
                        if (overrideTypeCur.ConvertToCanonForm(CanonicalFormKind.Specific) == methodOwningType)
                        {
                            break;
                        }

                        overrideTypeCur = overrideTypeCur.BaseType;
                    }while (overrideTypeCur != null);

                    if (overrideTypeCur == null)
                    {
                        continue;
                    }

                    MethodDesc methodToResolve;
                    if (methodOwningType == overrideTypeCur)
                    {
                        methodToResolve = _method;
                    }
                    else
                    {
                        methodToResolve = context
                                          .GetMethodForInstantiatedType(_method.GetTypicalMethodDefinition(), (InstantiatedType)overrideTypeCur)
                                          .MakeInstantiatedMethod(_method.Instantiation);
                    }

                    MethodDesc instantiatedTargetMethod = potentialOverrideType.FindVirtualFunctionTargetMethodOnObjectType(methodToResolve)
                                                          .GetCanonMethodTarget(CanonicalFormKind.Specific);
                    if (instantiatedTargetMethod != _method)
                    {
                        dynamicDependencies.Add(new CombinedDependencyListEntry(
                                                    factory.GVMDependencies(instantiatedTargetMethod), null, "DerivedMethodInstantiation"));
                    }
                }
            }

            return(dynamicDependencies);
        }
 public EETypeOptionalFieldsNode(EETypeNode owner)
 {
     _owner = owner;
 }
Beispiel #21
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:
                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, (MethodDesc)Target);
                    Debug.Assert(slot != -1);
                    AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.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
                // mov arg1, arg0
                encoder.Builder.EmitByte(0x48);
                encoder.Builder.EmitShort((short)((encoder.TargetRegister.Arg0 == Register.RCX) ? 0xD18B : 0xF78B));

                encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.NecessaryTypeSymbol(target));
                encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewArrayHelperForType(target)));
            }
            break;

            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                MetadataType target = (MetadataType)Target;
                if (!target.HasStaticConstructor)
                {
                    Debug.Assert(Id == ReadyToRunHelperId.GetNonGCStaticBase);
                    encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target));
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol(target));
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeNonGCStaticsSymbol(target));
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.GetThreadStaticBase:
                encoder.EmitINT3();
                break;

            case ReadyToRunHelperId.GetGCStaticBase:
            {
                MetadataType target = (MetadataType)Target;
                if (!target.HasStaticConstructor)
                {
                    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);
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol(target));
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeGCStaticsSymbol(target));
                    AddrMode loadFromRdx = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64);
                    encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx);
                    encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx);
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase));
                }
            }
            break;

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

                encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.MethodEntrypoint(target.Target));
                if (target.ShuffleThunk != null)
                {
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg3, factory.MethodEntrypoint(target.ShuffleThunk));
                }

                encoder.EmitJMP(factory.MethodEntrypoint(target.Ctor));
            }
            break;

            case ReadyToRunHelperId.InterfaceDispatch:
            {
                encoder.EmitLEAQ(Register.R10, factory.InterfaceDispatchCell((MethodDesc)Target));
                AddrMode jmpAddrMode = new AddrMode(Register.R10, null, 0, 0, AddrModeSize.Int64);
                encoder.EmitJmpToAddrMode(ref jmpAddrMode);
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
        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), hasLazyStaticConstructor ? NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target) : 0);

                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));

                    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:
                encoder.EmitINT3();
                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));

                    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;

                encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.Target);

                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;

            case ReadyToRunHelperId.GenericLookupFromThis:
            {
                int pointerSize = factory.Target.PointerSize;

                var lookupInfo = (GenericLookupDescriptor)Target;

                // Arg0 points to the EEType

                // Locate the VTable slot that points to the dictionary
                int vtableSlot = 0;
                if (!relocsOnly)
                {
                    vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)lookupInfo.CanonicalOwner);
                }

                int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize);

                // Load the dictionary pointer from the VTable
                AddrMode loadDictionary = new AddrMode(encoder.TargetRegister.Arg0, null, slotOffset, 0, AddrModeSize.Int64);
                encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadDictionary);

                // What's left now is the actual dictionary lookup
                goto case ReadyToRunHelperId.GenericLookupFromDictionary;
            }

            case ReadyToRunHelperId.GenericLookupFromDictionary:
            {
                var lookupInfo = (GenericLookupDescriptor)Target;

                // Find the generic dictionary slot
                int dictionarySlot = 0;
                if (!relocsOnly)
                {
                    // The concrete slot won't be known until we're emitting data.
                    dictionarySlot = factory.GenericDictionaryLayout(lookupInfo.CanonicalOwner).GetSlotForEntry(lookupInfo.Signature);
                }

                // Load the generic dictionary cell
                AddrMode loadEntry = new AddrMode(
                    encoder.TargetRegister.Arg0, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64);
                encoder.EmitMOV(encoder.TargetRegister.Result, ref loadEntry);
                encoder.EmitRET();
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
Beispiel #23
0
        protected override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly)
        {
            switch (Id)
            {
            case ReadyToRunHelperId.NewHelper:
            {
                TypeDesc target = (TypeDesc)Target;
                encoder.EmitMOV(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target));
                encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewObjectHelperForType(target)));
            }
            break;

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

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

                int pointerSize = factory.Target.PointerSize;

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

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

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

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

            case ReadyToRunHelperId.NewArr1:
            {
                TypeDesc target = (TypeDesc)Target;
                encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0);
                encoder.EmitMOV(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.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.EmitSUB(encoder.TargetRegister.Arg2, ((byte)NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)));

                    // cmp [r2 + ptrSize], 1
                    encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)factory.Target.PointerSize));
                    encoder.EmitCMP(encoder.TargetRegister.Arg3, ((byte)1));
                    // return if cmp
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    encoder.EmitMOV(encoder.TargetRegister.Arg0 /*Result*/, encoder.TargetRegister.Arg2);
                    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, ((short)factory.Target.PointerSize));

                if (!factory.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType));
                }
                else
                {
                    encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target));
                    encoder.EmitSUB(encoder.TargetRegister.Arg2, (byte)(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.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.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target));
                    // Get cctor pointer: offset is usually equal to the double size of the pointer, therefore we can use arm sub imm
                    encoder.EmitSUB(encoder.TargetRegister.Arg2, (byte)(NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)));
                    // cmp [r2 + ptrSize], 1
                    encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)factory.Target.PointerSize));
                    encoder.EmitCMP(encoder.TargetRegister.Arg3, (byte)1);
                    // return if cmp
                    encoder.EmitRETIfEqual();

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

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

                if (target.TargetNeedsVTableLookup)
                {
                    encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg1);

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

                    Debug.Assert(slot != -1);
                    encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2,
                                    ((short)(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);
                 ***
                 ***int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod);
                 ***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();
            }
        }
Beispiel #24
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), hasLazyStaticConstructor ? NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target) : 0);

                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));

                    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:
                encoder.EmitINT3();
                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));

                    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;

                encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.Target);

                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;

            case ReadyToRunHelperId.ResolveGenericVirtualMethod:
                encoder.EmitINT3();
                break;

            default:
                throw new NotImplementedException();
            }
        }
        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), hasLazyStaticConstructor ? NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target) : 0);

                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));

                    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));
                    // 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));

                    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
                {
                    int         delta            = 0;
                    ISymbolNode targetMethodNode = target.GetTargetNode(factory);
                    if (targetMethodNode is IFatFunctionPointerNode)
                    {
                        delta = FatFunctionPointerConstants.Offset;
                    }

                    encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.GetTargetNode(factory), delta);
                }

                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();
            }
        }
Beispiel #26
0
        public override IEnumerable <CombinedDependencyListEntry> SearchDynamicDependencies(List <DependencyNodeCore <NodeFactory> > markedNodes, int firstNode, NodeFactory factory)
        {
            Debug.Assert(_method.IsVirtual && _method.HasInstantiation);

            List <CombinedDependencyListEntry> dynamicDependencies = new List <CombinedDependencyListEntry>();

            for (int i = firstNode; i < markedNodes.Count; i++)
            {
                DependencyNodeCore <NodeFactory> entry = markedNodes[i];
                EETypeNode entryAsEETypeNode           = entry as EETypeNode;

                if (entryAsEETypeNode == null)
                {
                    continue;
                }

                TypeDesc potentialOverrideType = entryAsEETypeNode.Type;
                if (!potentialOverrideType.IsDefType)
                {
                    continue;
                }

                Debug.Assert(!potentialOverrideType.IsRuntimeDeterminedSubtype);

                if (potentialOverrideType.IsInterface)
                {
                    if (_method.OwningType.HasSameTypeDefinition(potentialOverrideType) && (potentialOverrideType != _method.OwningType))
                    {
                        if (potentialOverrideType.CanCastTo(_method.OwningType))
                        {
                            // Variance expansion
                            MethodDesc matchingMethodOnRelatedVariantMethod = potentialOverrideType.GetMethod(_method.Name, _method.GetTypicalMethodDefinition().Signature);
                            matchingMethodOnRelatedVariantMethod = _method.Context.GetInstantiatedMethod(matchingMethodOnRelatedVariantMethod, _method.Instantiation);
                            dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(matchingMethodOnRelatedVariantMethod), null, "GVM Variant Interface dependency"));
                        }
                    }

                    continue;
                }

                // If this is an interface gvm, look for types that implement the interface
                // and other instantantiations that have the same canonical form.
                // This ensure the various slot numbers remain equivalent across all types where there is an equivalence
                // relationship in the vtable.
                if (_method.OwningType.IsInterface)
                {
                    foreach (DefType interfaceImpl in potentialOverrideType.RuntimeInterfaces)
                    {
                        if (interfaceImpl == _method.OwningType)
                        {
                            MethodDesc slotDecl = potentialOverrideType.ResolveInterfaceMethodTarget(_method.GetMethodDefinition());
                            if (slotDecl != null)
                            {
                                MethodDesc implementingMethodInstantiation = _method.Context.GetInstantiatedMethod(slotDecl, _method.Instantiation);
                                dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(implementingMethodInstantiation), null, "ImplementingMethodInstantiation"));
                            }
                        }
                    }
                }
                else
                {
                    // Quickly check if the potential overriding type is at all related to the GVM's owning type (there is no need
                    // to do any processing for a type that is not at all related to the GVM's owning type. Resolving virtuals is expensive).
                    TypeDesc overrideTypeCur = potentialOverrideType;
                    {
                        do
                        {
                            if (overrideTypeCur == _method.OwningType)
                            {
                                break;
                            }

                            overrideTypeCur = overrideTypeCur.BaseType;
                        }while (overrideTypeCur != null);

                        if (overrideTypeCur == null)
                        {
                            continue;
                        }
                    }

                    overrideTypeCur = potentialOverrideType;
                    while (overrideTypeCur != null)
                    {
                        if (overrideTypeCur == _method.OwningType)
                        {
                            // The GVMDependencyNode already declares the entrypoint/dictionary dependencies of the current method
                            // as static dependencies, therefore we can break the loop as soon we hit the current method's owning type
                            // while we're traversing the hierarchy of the potential derived types.
                            break;
                        }

                        MethodDesc instantiatedTargetMethod = overrideTypeCur.FindVirtualFunctionTargetMethodOnObjectType(_method);
                        if (instantiatedTargetMethod != null)
                        {
                            dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(instantiatedTargetMethod), null, "DerivedMethodInstantiation"));
                        }

                        overrideTypeCur = overrideTypeCur.BaseType;
                    }
                }
            }

            return(dynamicDependencies);
        }
Beispiel #27
0
 public EETypeOptionalFieldsNode(EETypeNode owner)
 {
     _owner = owner;
 }
        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
            {
                //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 EETypeNode)
                    {
                        DefType t           = ((EETypeNode)node).Type.GetClosestDefType();
                        int     iSlot       = GetVTableSlotsCount(factory, t.BaseType);
                        var     pointerSize = factory.Target.PointerSize;
                        foreach (MethodDesc m in factory.VTable(t).Slots)
                        {
                            // set _getslot variable to sizeof(EEType) + iSlot * pointer size
                            string       realSymbolName = factory.NameMangler.GetMangledMethodName(m).ToString();
                            var          globalRefName  = "__getslot__" + realSymbolName;
                            LLVMValueRef slot           = LLVM.GetNamedGlobal(compilation.Module, globalRefName);
                            if (slot.Pointer == IntPtr.Zero)
                            {
                                slot = LLVM.AddGlobal(compilation.Module, LLVM.Int32Type(), globalRefName);
                            }
                            LLVM.SetInitializer(slot, LLVM.ConstInt(LLVM.Int32Type(), (ulong)((EETypeNode.GetVTableOffset(pointerSize) / pointerSize) + iSlot), LLVMMisc.False));
                            LLVM.SetGlobalConstant(slot, LLVMMisc.True);
                            iSlot++;
                        }
                    }

                    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);
                                }
                            }
                            int size = objectWriter.EmitSymbolReference(reloc.Target, (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
                    {
                    }
                }
            }
        }
        private void GetCodeForReadyToRunGenericHelper(WebAssemblyCodegenCompilation compilation, ReadyToRunGenericHelperNode node, NodeFactory factory)
        {
            LLVMBuilderRef builder      = compilation.Module.Context.CreateBuilder();
            var            args         = new List <LLVMTypeRef>();
            MethodDesc     delegateCtor = null;

            if (node.Id == ReadyToRunHelperId.DelegateCtor)
            {
                DelegateCreationInfo target = (DelegateCreationInfo)node.Target;
                delegateCtor = target.Constructor.Method;
                bool isStatic = delegateCtor.Signature.IsStatic;
                int  argCount = delegateCtor.Signature.Length;
                if (!isStatic)
                {
                    argCount++;
                }
                for (int i = 0; i < argCount; i++)
                {
                    TypeDesc argType;
                    if (i == 0 && !isStatic)
                    {
                        argType = delegateCtor.OwningType;
                    }
                    else
                    {
                        argType = delegateCtor.Signature[i - (isStatic ? 0 : 1)];
                    }
                    args.Add(ILImporter.GetLLVMTypeForTypeDesc(argType));
                }
            }

            LLVMValueRef helperFunc = Module.GetNamedFunction(node.GetMangledName(factory.NameMangler));

            if (helperFunc.Handle == IntPtr.Zero)
            {
                throw new Exception("if the function is requested here, it should have been created earlier");
            }
            var helperBlock = helperFunc.AppendBasicBlock("genericHelper");

            builder.PositionAtEnd(helperBlock);
            var          importer = new ILImporter(builder, compilation, Module, helperFunc, delegateCtor);
            LLVMValueRef ctx;
            string       gepName;

            if (node is ReadyToRunGenericLookupFromTypeNode)
            {
                // Locate the VTable slot that points to the dictionary
                int vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)node.DictionaryOwner);

                int pointerSize = factory.Target.PointerSize;
                // Load the dictionary pointer from the VTable
                int slotOffset    = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize);
                var slotGep       = builder.BuildGEP(helperFunc.GetParam(1), new[] { LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (ulong)slotOffset, false) }, "slotGep");
                var slotGepPtrPtr = builder.BuildPointerCast(slotGep,
                                                             LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), "slotGepPtrPtr");
                ctx     = builder.BuildLoad(slotGepPtrPtr, "dictGep");
                gepName = "typeNodeGep";
            }
            else
            {
                ctx     = helperFunc.GetParam(1);
                gepName = "paramGep";
            }

            LLVMValueRef resVar = OutputCodeForDictionaryLookup(builder, factory, node, node.LookupSignature, ctx, gepName);

            switch (node.Id)
            {
            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                MetadataType target = (MetadataType)node.Target;

                if (compilation.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    importer.OutputCodeForTriggerCctor(target, resVar);
                }
            }
            break;

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

                var ptrPtrPtr = builder.BuildBitCast(resVar, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), 0), "ptrPtrPtr");

                resVar = builder.BuildLoad(builder.BuildLoad(ptrPtrPtr, "ind1"), "ind2");

                if (compilation.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target);
                    var nonGcStaticsBase = OutputCodeForDictionaryLookup(builder, factory, node, nonGcRegionLookup, ctx, "lazyGep");
                    importer.OutputCodeForTriggerCctor(target, nonGcStaticsBase);
                }
            }
            break;

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

                if (compilation.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target);
                    var threadStaticBase = OutputCodeForDictionaryLookup(builder, factory, node, nonGcRegionLookup, ctx, "tsGep");
                    importer.OutputCodeForTriggerCctor(target, threadStaticBase);
                }
                resVar = importer.OutputCodeForGetThreadStaticBaseForType(resVar).ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), builder);
            }
            break;

            case ReadyToRunHelperId.DelegateCtor:
            {
                DelegateCreationInfo target      = (DelegateCreationInfo)node.Target;
                MethodDesc           constructor = target.Constructor.Method;
                var fatPtr = ILImporter.MakeFatPointer(builder, resVar, compilation);
                importer.OutputCodeForDelegateCtorInit(builder, helperFunc, constructor, fatPtr);
            }
            break;

            // These are all simple: just get the thing from the dictionary and we're done
            case ReadyToRunHelperId.TypeHandle:
            case ReadyToRunHelperId.MethodHandle:
            case ReadyToRunHelperId.FieldHandle:
            case ReadyToRunHelperId.MethodDictionary:
            case ReadyToRunHelperId.MethodEntry:
            case ReadyToRunHelperId.VirtualDispatchCell:
            case ReadyToRunHelperId.DefaultConstructor:
                break;

            default:
                throw new NotImplementedException();
            }

            if (node.Id != ReadyToRunHelperId.DelegateCtor)
            {
                builder.BuildRet(resVar);
            }
            else
            {
                builder.BuildRetVoid();
            }
        }
        protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly)
        {
            switch (Id)
            {
            case ReadyToRunHelperId.VirtualCall:
            {
                MethodDesc targetMethod = (MethodDesc)Target;

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

                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 = 0;
                if (!relocsOnly)
                {
                    slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType);
                    Debug.Assert(slot != -1);
                }
                Debug.Assert(((NativeSequencePoint[])((INodeWithDebugInfo)this).GetNativeSequencePoints())[1].NativeOffset == encoder.Builder.CountBytes);

                AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize), 0, AddrModeSize.Int64);
                encoder.EmitJmpToAddrMode(ref jmpAddrMode);
            }
            break;

            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                MetadataType target = (MetadataType)Target;
                bool         hasLazyStaticConstructor = factory.PreinitializationManager.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.GetClassConstructorContextSize(factory.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.Int32);
                encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromArg2AndDelta);

                if (!factory.PreinitializationManager.HasLazyStaticConstructor(target))
                {
                    encoder.EmitJMP(factory.ExternSymbol("RhpGetThreadStaticBaseForType"));
                }
                else
                {
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));

                    AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg2, null, factory.Target.PointerSize, 0, AddrModeSize.Int32);
                    encoder.EmitCMP(ref initialized, 1);
                    encoder.EmitJE(factory.ExternSymbol("RhpGetThreadStaticBaseForType"));

                    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);

                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.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextSize(factory.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)
                {
                    Debug.Assert(!target.TargetMethod.CanMethodBeInSealedVTable());

                    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, target.TargetMethod.OwningType);
                    }

                    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);

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

                    int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType);
                    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();
            }
        }
Beispiel #31
0
        protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly)
        {
            switch (Id)
            {
            case ReadyToRunHelperId.NewHelper:
                encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol((TypeDesc)Target));
                encoder.EmitJMP(factory.ExternSymbol("__allocate_object"));
                break;

            case ReadyToRunHelperId.VirtualCall:
                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, (MethodDesc)Target);
                    Debug.Assert(slot != -1);
                    AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64);
                    encoder.EmitJmpToAddrMode(ref jmpAddrMode);
                }
                break;

            case ReadyToRunHelperId.IsInstanceOf:
                encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target));
                encoder.EmitJMP(factory.ExternSymbol("__isinst_class"));
                break;

            case ReadyToRunHelperId.CastClass:
                encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target));
                encoder.EmitJMP(factory.ExternSymbol("__castclass_class"));
                break;

            case ReadyToRunHelperId.NewArr1:
                encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target));
                encoder.EmitJMP(factory.ExternSymbol("__allocate_array"));
                break;

            case ReadyToRunHelperId.GetNonGCStaticBase:
                if (!((MetadataType)Target).HasStaticConstructor)
                {
                    Debug.Assert(Id == ReadyToRunHelperId.GetNonGCStaticBase);
                    encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol((MetadataType)Target));
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol((MetadataType)Target));
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeNonGCStaticsSymbol((MetadataType)Target));
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
                }
                break;

            case ReadyToRunHelperId.GetThreadStaticBase:
                encoder.EmitINT3();
                break;

            case ReadyToRunHelperId.GetGCStaticBase:
                if (!((MetadataType)Target).HasStaticConstructor)
                {
                    encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol((MetadataType)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);
                    encoder.EmitRET();
                }
                else
                {
                    // We need to trigger the cctor before returning the base
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol((MetadataType)Target));
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeGCStaticsSymbol((MetadataType)Target));
                    AddrMode loadFromRdx = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64);
                    encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx);
                    encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx);
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase));
                }
                break;

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

                encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.MethodEntrypoint(target.Target));
                if (target.ShuffleThunk != null)
                {
                    encoder.EmitLEAQ(encoder.TargetRegister.Arg3, factory.MethodEntrypoint(target.ShuffleThunk));
                }

                encoder.EmitJMP(factory.MethodEntrypoint(target.Ctor));
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }