protected void EmitDictionaryLookup(NodeFactory factory, ref LoongArch64Emitter encoder, Register context, Register result, GenericLookupResult lookup, bool relocsOnly)
        {
            // INVARIANT: must not trash context register

            // Find the generic dictionary slot
            int dictionarySlot = 0;

            if (!relocsOnly)
            {
                // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly.
                dictionarySlot = factory.GenericDictionaryLayout(_dictionaryOwner).GetSlotForEntry(lookup);
            }

            // Load the generic dictionary cell
            encoder.EmitLD(result, context, dictionarySlot * factory.Target.PointerSize);

            switch (lookup.LookupResultReferenceType(factory))
            {
            case GenericLookupResultReferenceType.Indirect:
                // Do another indirection
                encoder.EmitLD(result, result, 0);
                break;

            case GenericLookupResultReferenceType.ConditionalIndirect:
                // andi temp, result, 0x1
                // BEQZ temp L1
                // addi.d result, result,-1
                // L1:
                throw new NotImplementedException();

            default:
                break;
            }
        }
Ejemplo n.º 2
0
        protected override void EmitCode(NodeFactory factory, ref LoongArch64Emitter instructionEncoder, bool relocsOnly)
        {
            switch (_thunkKind)
            {
            case Kind.Eager:
                break;

            case Kind.DelayLoadHelper:
            case Kind.VirtualStubDispatch:
                // T8 contains indirection cell
                // Do nothing T8=R20 contains our first param

                if (!relocsOnly)
                {
                    // movz T0=R12, #index
                    int index = _containingImportSection.IndexFromBeginningOfArray;
                    instructionEncoder.EmitMOV(Register.R12, checked ((ushort)index));
                }

                // get pc
                // pcaddi T1=R13, 0
                instructionEncoder.EmitPC(Register.R13);

                // load Module* -> T1
                instructionEncoder.EmitLD(Register.R13, Register.R13, 0x24);

                // ld_d R13, R13, 0
                instructionEncoder.EmitLD(Register.R13, Register.R13, 0);
                break;

            case Kind.Lazy:
                // get pc
                // pcaddi R5, 0
                instructionEncoder.EmitPC(Register.R5);

                // load Module* -> R5=A1
                instructionEncoder.EmitLD(Register.R5, Register.R5, 0x24);

                // ld_d R5, R5, 0
                instructionEncoder.EmitLD(Register.R5, Register.R5, 0);
                break;

            default:
                throw new NotImplementedException();
            }

            // branch to helper
            instructionEncoder.EmitJMP(_helperCell);

            // Emit relocation for the Module* load above
            if (_thunkKind != Kind.Eager)
            {
                instructionEncoder.Builder.EmitReloc(factory.ModuleImport, RelocType.IMAGE_REL_BASED_DIR64);
            }
        }
 protected Register GetContextRegister(ref /* readonly */ LoongArch64Emitter encoder)
 {
     if (_id == ReadyToRunHelperId.DelegateCtor)
     {
         return(encoder.TargetRegister.Arg2);
     }
     else
     {
         return(encoder.TargetRegister.Arg0);
     }
 }
        protected override void EmitLoadGenericContext(NodeFactory factory, ref LoongArch64Emitter 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.EmitLD(contextRegister, contextRegister, slotOffset);
        }
Ejemplo n.º 5
0
 protected override void EmitCode(NodeFactory factory, ref LoongArch64Emitter encoder, bool relocsOnly)
 {
     encoder.EmitJMP(GetTarget(factory));
 }
Ejemplo n.º 6
0
 protected override void EmitCode(NodeFactory factory, ref LoongArch64Emitter encoder, bool relocsOnly)
 {
     // addi.d a0, a0, sizeof(void*);
     encoder.EmitADD(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, factory.Target.PointerSize);
     encoder.EmitJMP(GetUnderlyingMethodEntrypoint(factory)); // b methodEntryPoint
 }
        protected sealed override void EmitCode(NodeFactory factory, ref LoongArch64Emitter encoder, bool relocsOnly)
        {
            // First load the generic context into the context register.
            EmitLoadGenericContext(factory, ref encoder, relocsOnly);

            Register contextRegister = GetContextRegister(ref encoder);

            switch (_id)
            {
            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                Debug.Assert(contextRegister == encoder.TargetRegister.Arg0);

                EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);

                MetadataType target = (MetadataType)_target;
                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.EmitADD(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg0, -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
                    encoder.EmitLD(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg3, factory.Target.PointerSize);
                    encoder.EmitXOR(encoder.TargetRegister.IntraProcedureCallScratch1, encoder.TargetRegister.Arg2, 1);
                    encoder.EmitRETIfEqual(Register.R21);

                    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.GetGCStaticBase:
            {
                Debug.Assert(contextRegister == encoder.TargetRegister.Arg0);

                encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0);
                EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                encoder.EmitLD(encoder.TargetRegister.Result, encoder.TargetRegister.Result, 0);

                MetadataType target = (MetadataType)_target;
                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.
                    GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target);
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly);

                    encoder.EmitADD(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
                    encoder.EmitLD(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, factory.Target.PointerSize);
                    encoder.EmitXOR(encoder.TargetRegister.IntraProcedureCallScratch1, encoder.TargetRegister.Arg3, 1);
                    encoder.EmitRETIfEqual(Register.R21);

                    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.GetThreadStaticBase:
            {
                Debug.Assert(contextRegister == encoder.TargetRegister.Arg0);

                MetadataType target = (MetadataType)_target;

                // Look up the index cell
                EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1, _lookupSignature, relocsOnly);

                ISymbolNode helperEntrypoint;
                if (factory.PreinitializationManager.HasLazyStaticConstructor(target))
                {
                    // There is a lazy class constructor. We need the non-GC static base because that's where the
                    // class constructor context lives.
                    GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target);
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly);
                    int cctorContextSize = -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target);
                    encoder.EmitADD(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, cctorContextSize);

                    helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase);
                }
                else
                {
                    helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType);
                }

                // 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.EmitLD(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1, 0);

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

                encoder.EmitJMP(helperEntrypoint);
            }
            break;

            case ReadyToRunHelperId.DelegateCtor:
            {
                // This is a weird helper. Codegen populated Arg0 and Arg1 with the values that the constructor
                // method expects. Codegen also passed us the generic context in Arg2.
                // We now need to load the delegate target method into Arg2 (using a dictionary lookup)
                // and the optional 4th parameter, and call the ctor.

                Debug.Assert(contextRegister == encoder.TargetRegister.Arg2);

                var target = (DelegateCreationInfo)_target;

                EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, _lookupSignature, relocsOnly);

                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;

            // 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:
            case ReadyToRunHelperId.ObjectAllocator:
            case ReadyToRunHelperId.TypeHandleForCasting:
            case ReadyToRunHelperId.ConstrainedDirectCall:
            {
                EmitDictionaryLookup(factory, ref encoder, contextRegister, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                encoder.EmitRET();
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
 protected virtual void EmitLoadGenericContext(NodeFactory factory, ref LoongArch64Emitter encoder, bool relocsOnly)
 {
     // Assume generic context is already loaded in the context register.
 }
Ejemplo n.º 9
0
        protected override void EmitCode(NodeFactory factory, ref LoongArch64Emitter 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.EmitLD(encoder.TargetRegister.IntraProcedureCallScratch1, encoder.TargetRegister.Arg0, 0);
                encoder.EmitLD(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.EmitADD(encoder.TargetRegister.Arg3, encoder.TargetRegister.Result, -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
                    encoder.EmitLD(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg3, factory.Target.PointerSize);
                    encoder.EmitXOR(encoder.TargetRegister.IntraProcedureCallScratch1, encoder.TargetRegister.Arg2, 1);
                    encoder.EmitRETIfEqual(encoder.TargetRegister.IntraProcedureCallScratch1);

                    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.EmitLD(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2, 0);

                // Second arg: index of the type in the ThreadStatic section of the modules
                encoder.EmitLD(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.EmitADD(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));

                    encoder.EmitLD(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, factory.Target.PointerSize);
                    encoder.EmitXOR(encoder.TargetRegister.IntraProcedureCallScratch1, encoder.TargetRegister.Arg3, 1);
                    encoder.EmitJE(encoder.TargetRegister.IntraProcedureCallScratch1, 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.EmitLD(encoder.TargetRegister.Result, encoder.TargetRegister.Result, 0);

                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.EmitADD(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, -NonGCStaticsNode.GetClassConstructorContextSize(factory.Target));
                    encoder.EmitLD(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, factory.Target.PointerSize);
                    encoder.EmitXOR(encoder.TargetRegister.IntraProcedureCallScratch1, encoder.TargetRegister.Arg3, 1);
                    encoder.EmitRETIfEqual(Register.R21);

                    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.EmitLD(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg1, 0);

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

                    Debug.Assert(slot != -1);
                    encoder.EmitLD(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:
            {
                // Not tested
                encoder.EmitBreak();

                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.EmitLD(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0, 0);

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

                    int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType);
                    Debug.Assert(slot != -1);
                    encoder.EmitLD(encoder.TargetRegister.Result, encoder.TargetRegister.Result,
                                   EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize));
                    encoder.EmitRET();
                }
            }
            break;


            default:
                throw new NotImplementedException();
            }
        }
Ejemplo n.º 10
0
 protected override void EmitCode(NodeFactory factory, ref LoongArch64Emitter instructionEncoder, bool relocsOnly)
 {
     throw new NotImplementedException();
 }