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);
        }
        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);
        }
示例#3
0
        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.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();
            }
        }