Example #1
0
        public override int GetSlotForEntry(GenericLookupResult entry)
        {
            int index = Array.IndexOf(_layout, entry);

            Debug.Assert(index >= 0);
            return(index);
        }
            public int Compare(GenericLookupResult x, GenericLookupResult y)
            {
                if (x == y)
                {
                    return(0);
                }

                int codeX = x.ClassCode;
                int codeY = y.ClassCode;

                if (codeX == codeY)
                {
                    Debug.Assert(x.GetType() == y.GetType());

                    int result = x.CompareToImpl(y, _comparer);

                    // We did a reference equality check above so an "Equal" result is not expected
                    Debug.Assert(result != 0);

                    return(result);
                }
                else
                {
                    Debug.Assert(x.GetType() != y.GetType());
                    return(codeX > codeY ? -1 : 1);
                }
            }
        public ReadyToRunGenericHelperNode(NodeFactory factory, ReadyToRunHelperId helperId, object target, TypeSystemEntity dictionaryOwner)
        {
            _id = helperId;
            _dictionaryOwner = dictionaryOwner;
            _target = target;

            _lookupSignature = GetLookupSignature(factory, helperId, target);
        }
 public void DeferFloatingGenericLookup(GenericLookupResult lookupResult)
 {
     if (_floatingGenericLookupResults == null)
     {
         _floatingGenericLookupResults = new HashSet <GenericLookupResult>();
     }
     _floatingGenericLookupResults.Add(lookupResult);
 }
        public ReadyToRunGenericHelperNode(NodeFactory factory, ReadyToRunHelperId helperId, object target, TypeSystemEntity dictionaryOwner)
        {
            _id = helperId;
            _dictionaryOwner = dictionaryOwner;
            _target          = target;

            _lookupSignature = GetLookupSignature(factory, helperId, target);
        }
Example #6
0
        public override void EnsureEntry(GenericLookupResult entry)
        {
            int index = Array.IndexOf(_layout, entry);

            if (index == -1)
            {
                // Using EnsureEntry to add a slot to a PrecomputedDictionaryLayoutNode is not supported
                throw new NotSupportedException();
            }
        }
        protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
        {
            var otherEntry = (MethodEntryGenericLookupResult)other;
            int result     = (_isUnboxingThunk ? 1 : 0) - (otherEntry._isUnboxingThunk ? 1 : 0);

            if (result != 0)
            {
                return(result);
            }

            return(comparer.Compare(_method, otherEntry._method));
        }
        protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
        {
            var otherEntry = (CallingConventionConverterLookupResult)other;
            int result     = (int)(_callingConventionConverter.ConverterKind - otherEntry._callingConventionConverter.ConverterKind);

            if (result != 0)
            {
                return(result);
            }

            return(comparer.Compare(_callingConventionConverter.Signature, otherEntry._callingConventionConverter.Signature));
        }
Example #9
0
        public virtual int GetSlotForEntry(GenericLookupResult entry)
        {
            if (_layout == null)
            {
                ComputeLayout();
            }

            int index = Array.IndexOf(_layout, entry);

            Debug.Assert(index >= 0);
            return(index);
        }
        public GenericLookupDescriptor(TypeSystemEntity canonicalOwner, GenericLookupResult signature)
        {
            // Owner should be a canonical type or canonical method
            Debug.Assert((
                             canonicalOwner is TypeDesc &&
                             ((TypeDesc)canonicalOwner).IsCanonicalSubtype(CanonicalFormKind.Any)) ||
                         (canonicalOwner is MethodDesc &&
                          ((MethodDesc)canonicalOwner).HasInstantiation && ((MethodDesc)canonicalOwner).IsSharedByGenericInstantiations));

            CanonicalOwner = canonicalOwner;
            Signature      = signature;
        }
Example #11
0
        private void ComputeLayout()
        {
            // TODO: deterministic ordering
            GenericLookupResult[] layout = new GenericLookupResult[_entries.Count];
            int index = 0;

            foreach (GenericLookupResult entry in EntryHashTable.Enumerator.Get(_entries))
            {
                layout[index++] = entry;
            }

            // Only publish after the full layout is computed. Races are fine.
            _layout = layout;
        }
        public override int GetSlotForEntry(GenericLookupResult entry)
        {
            int index = Array.IndexOf(_layout, entry);

            // This entry wasn't precomputed. If this is an optimized build with scanner, it might suggest
            // the scanner didn't see the need for this. There is a discrepancy between scanning and compiling.
            // This is a fatal error to prevent bad codegen.
            if (index < 0)
            {
                throw new InvalidOperationException($"{OwningMethodOrType}: {entry}");
            }

            return(index);
        }
Example #13
0
        private void ComputeLayout()
        {
            GenericLookupResult[] layout = new GenericLookupResult[_entries.Count];
            int index = 0;

            foreach (GenericLookupResult entry in EntryHashTable.Enumerator.Get(_entries))
            {
                layout[index++] = entry;
            }

            var comparer = new GenericLookupResult.Comparer(new TypeSystemComparer());

            Array.Sort(layout, comparer.Compare);

            // Only publish after the full layout is computed. Races are fine.
            _layout = layout;
        }
        protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter 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
            AddrMode loadEntry = new AddrMode(
                context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64);
            encoder.EmitMOV(result, ref loadEntry);
        }
        public override int GetSlotForEntry(GenericLookupResult entry)
        {
            int index;

            lock (thisLock)
            {
                if (!_entryslots.TryGetValue(entry, out index))
                {
                    _layout.Add(entry);
                    index = _layout.Count - 1;
                    _entryslots.Add(entry, index);
                }
            }

            Debug.Assert(index >= 0);
            return(index);
        }
Example #16
0
        protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
        {
            var otherResult = (ConstrainedMethodUseLookupResult)other;
            int result      = (_directCall ? 1 : 0) - (otherResult._directCall ? 1 : 0);

            if (result != 0)
            {
                return(result);
            }

            result = comparer.Compare(_constraintType, otherResult._constraintType);
            if (result != 0)
            {
                return(result);
            }

            return(comparer.Compare(_constrainedMethod, otherResult._constrainedMethod));
        }
        public override int GetSlotForEntry(GenericLookupResult entry)
        {
            if (_layout == null)
            {
                ComputeLayout();
            }

            int index = Array.IndexOf(_layout, entry);

            // We never called EnsureEntry on this during compilation?
            // This is a fatal error to prevent bad codegen.
            if (index < 0)
            {
                throw new InvalidOperationException($"{OwningMethodOrType}: {entry}");
            }

            return(index);
        }
        public override IEnumerable <CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
        {
            if (!factory.MetadataManager.SupportsReflection)
            {
                return(Array.Empty <CombinedDependencyListEntry>());
            }

            List <CombinedDependencyListEntry> conditionalDependencies = new List <CombinedDependencyListEntry>();
            NativeLayoutSavedVertexNode        templateLayout;

            if (_dictionaryOwner is MethodDesc)
            {
                templateLayout = factory.NativeLayout.TemplateMethodLayout((MethodDesc)_dictionaryOwner);
                conditionalDependencies.Add(new CombinedDependencyListEntry(_lookupSignature.TemplateDictionaryNode(factory),
                                                                            templateLayout,
                                                                            "Type loader template"));
            }
            else
            {
                templateLayout = factory.NativeLayout.TemplateTypeLayout((TypeDesc)_dictionaryOwner);
                conditionalDependencies.Add(new CombinedDependencyListEntry(_lookupSignature.TemplateDictionaryNode(factory),
                                                                            templateLayout,
                                                                            "Type loader template"));
            }

            if (_id == ReadyToRunHelperId.GetGCStaticBase || _id == ReadyToRunHelperId.GetThreadStaticBase)
            {
                // If the type has a lazy static constructor, we also need the non-GC static base to be available as
                // a template dictionary node.
                TypeDesc type = (TypeDesc)_target;
                Debug.Assert(templateLayout != null);
                if (factory.TypeSystemContext.HasLazyStaticConstructor(type))
                {
                    GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(type);
                    conditionalDependencies.Add(new CombinedDependencyListEntry(nonGcRegionLookup.TemplateDictionaryNode(factory),
                                                                                templateLayout,
                                                                                "Type loader template"));
                }
            }

            return(conditionalDependencies);
        }
Example #19
0
 public override void EnsureEntry(GenericLookupResult lookupResult) => throw new NotImplementedException();
Example #20
0
        protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter 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
            AddrMode loadEntry = new AddrMode(
                context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64);

            encoder.EmitMOV(result, ref loadEntry);

            // If there's any invalid entries, we need to test for them
            //
            // Only do this in relocsOnly to make it easier to weed out bugs - the _hasInvalidEntries
            // flag can change over the course of compilation and the bad slot helper dependency
            // should be reported by someone else - the system should not rely on it coming from here.
            if (!relocsOnly && _hasInvalidEntries)
            {
                encoder.EmitCompareToZero(result);
                encoder.EmitJE(GetBadSlotHelper(factory));
            }

            switch (lookup.LookupResultReferenceType(factory))
            {
            case GenericLookupResultReferenceType.Indirect:
                // Do another indirection
                loadEntry = new AddrMode(result, null, 0, 0, AddrModeSize.Int64);
                encoder.EmitMOV(result, ref loadEntry);
                break;

            case GenericLookupResultReferenceType.ConditionalIndirect:
                // Test result, 0x1
                // JEQ L1
                // mov result, [result-1]
                // L1:
                throw new NotImplementedException();

            default:
                break;
            }
        }
        protected sealed override void EmitCode(NodeFactory factory, ref X64Emitter 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);

                MetadataType target = (MetadataType)_target;

                if (!factory.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                    encoder.EmitRET();
                }
                else
                {
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly);
                    encoder.EmitMOV(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0);

                    // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region.
                    int      cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target);
                    AddrMode initialized      = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32);
                    encoder.EmitCMP(ref initialized, 1);
                    encoder.EmitRETIfEqual();

                    AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64);
                    encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor);
                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
                }
            }
            break;

            case ReadyToRunHelperId.GetGCStaticBase:
            {
                Debug.Assert(contextRegister == encoder.TargetRegister.Arg0);

                MetadataType target = (MetadataType)_target;

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

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

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

                    int      cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target);
                    AddrMode initialized      = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32);
                    encoder.EmitCMP(ref initialized, 1);
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64);
                    encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor);

                    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.TypeSystemContext.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.GetClassConstructorContextStorageSize(factory.Target, target);
                    AddrMode loadCctor        = new AddrMode(encoder.TargetRegister.Arg2, null, -cctorContextSize, 0, AddrModeSize.Int64);
                    encoder.EmitLEA(encoder.TargetRegister.Arg2, ref loadCctor);

                    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).
                AddrMode loadFromArg1 = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64);
                encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadFromArg1);

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

                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.EmitLEAQ(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:
            {
                EmitDictionaryLookup(factory, ref encoder, contextRegister, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                encoder.EmitRET();
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
        protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter 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
            AddrMode loadEntry = new AddrMode(
                context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64);

            encoder.EmitMOV(result, ref loadEntry);

            switch (lookup.LookupResultReferenceType(factory))
            {
            case GenericLookupResultReferenceType.Indirect:
                // Do another indirection
                loadEntry = new AddrMode(result, null, 0, 0, AddrModeSize.Int64);
                encoder.EmitMOV(result, ref loadEntry);
                break;

            case GenericLookupResultReferenceType.ConditionalIndirect:
                // Test result, 0x1
                // JEQ L1
                // mov result, [result-1]
                // L1:
                throw new NotImplementedException();

            default:
                break;
            }
        }
Example #23
0
 public abstract int GetSlotForEntry(GenericLookupResult entry);
Example #24
0
        protected sealed override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly)
        {
            // First load the generic context into Arg0.
            EmitLoadGenericContext(factory, ref encoder, relocsOnly);

            switch (_id)
            {
            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                MetadataType target = (MetadataType)_target;

                if (!factory.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                    encoder.EmitRET();
                }
                else
                {
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly);
                    encoder.EmitMOV(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0);

                    // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region.
                    int      cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target);
                    AddrMode initialized      = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32);
                    encoder.EmitCMP(ref initialized, 1);
                    encoder.EmitRETIfEqual();

                    AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64);
                    encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor);
                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
                }
            }
            break;

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

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

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

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

                    int      cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target);
                    AddrMode initialized      = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32);
                    encoder.EmitCMP(ref initialized, 1);
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64);
                    encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor);

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

            case ReadyToRunHelperId.GetThreadStaticBase:
            {
                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.TypeSystemContext.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.GetClassConstructorContextStorageSize(factory.Target, target);
                    AddrMode loadCctor        = new AddrMode(encoder.TargetRegister.Arg2, null, -cctorContextSize, 0, AddrModeSize.Int64);
                    encoder.EmitLEA(encoder.TargetRegister.Arg2, ref loadCctor);

                    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).
                AddrMode loadFromArg1 = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64);
                encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadFromArg1);

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

                encoder.EmitJMP(helperEntrypoint);
            }
            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.VirtualCall:
            case ReadyToRunHelperId.ResolveVirtualFunction:
            case ReadyToRunHelperId.MethodEntry:
            {
                EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                encoder.EmitRET();
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
        protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter 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
            AddrMode loadEntry = new AddrMode(
                context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64);

            encoder.EmitMOV(result, ref loadEntry);
        }
Example #26
0
 public override int GetSlotForEntry(GenericLookupResult entry) => throw new NotImplementedException();
        protected sealed override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly)
        {
            // First load the generic context into Arg0.
            EmitLoadGenericContext(factory, ref encoder, relocsOnly);

            switch (_id)
            {
            case ReadyToRunHelperId.GetNonGCStaticBase:
            {
                MetadataType target = (MetadataType)_target;

                if (!factory.TypeSystemContext.HasLazyStaticConstructor(target))
                {
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                    encoder.EmitRET();
                }
                else
                {
                    EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly);

                    // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region.
                    int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target);

                    AddrMode loadBase = new AddrMode(encoder.TargetRegister.Arg0, null, cctorContextSize, 0, AddrModeSize.Int64);
                    encoder.EmitLEA(encoder.TargetRegister.Result, ref loadBase);

                    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.GetGCStaticBase:
            {
                MetadataType target = (MetadataType)_target;

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

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

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

                    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;

            // These are all simple: just get the thing from the dictionary and we're done
            case ReadyToRunHelperId.TypeHandle:
            case ReadyToRunHelperId.MethodDictionary:
            case ReadyToRunHelperId.VirtualCall:
            case ReadyToRunHelperId.ResolveVirtualFunction:
            case ReadyToRunHelperId.MethodEntry:
            {
                EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly);
                encoder.EmitRET();
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }
Example #28
0
        private LLVMValueRef OutputCodeForDictionaryLookup(LLVMBuilderRef builder, NodeFactory factory,
                                                           ReadyToRunGenericHelperNode node, GenericLookupResult lookup, LLVMValueRef ctx, string gepName)
        {
            // Find the generic dictionary slot
            int dictionarySlot = factory.GenericDictionaryLayout(node.DictionaryOwner).GetSlotForEntry(lookup);
            int offset         = dictionarySlot * factory.Target.PointerSize;

            // Load the generic dictionary cell
            LLVMValueRef retGep  = builder.BuildGEP(ctx, new[] { LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (ulong)offset, false) }, "retGep");
            LLVMValueRef castGep = builder.BuildBitCast(retGep, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), "ptrPtr");
            LLVMValueRef retRef  = builder.BuildLoad(castGep, gepName);

            switch (lookup.LookupResultReferenceType(factory))
            {
            case GenericLookupResultReferenceType.Indirect:
                var ptrPtr = builder.BuildBitCast(retRef, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), "ptrPtr");
                retRef = builder.BuildLoad(ptrPtr, "indLoad");
                break;

            case GenericLookupResultReferenceType.ConditionalIndirect:
                throw new NotImplementedException();

            default:
                break;
            }

            return(retRef);
        }
Example #29
0
 public void EnsureEntry(GenericLookupResult entry)
 {
     Debug.Assert(_layout == null, "Trying to add entry but layout already computed");
     _entries.AddOrGetExisting(entry);
 }
Example #30
0
 protected void EmitDictionaryLookup(NodeFactory factory, ref ARM64Emitter encoder, Register context, Register result, GenericLookupResult lookup, bool relocsOnly)
 {
     throw new NotImplementedException();
 }
Example #31
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();
            }
        }
Example #32
0
        protected sealed override void EmitCode(NodeFactory factory, ref ARMEmitter 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.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.
                    int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target);
                    encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0, ((short)(factory.Target.PointerSize - cctorContextSize)));
                    encoder.EmitCMP(encoder.TargetRegister.Arg1, ((byte)1));
                    encoder.EmitRETIfEqual();

                    encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result);
                    encoder.EmitSUB(encoder.TargetRegister.Arg0, ((byte)(cctorContextSize)));
                    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.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result);
                encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result);

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

                    int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target);
                    encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)(factory.Target.PointerSize - cctorContextSize)));
                    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.EmitSUB(encoder.TargetRegister.Arg0, cctorContextSize);
                    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.TypeSystemContext.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.GetClassConstructorContextStorageSize(factory.Target, target);
                    encoder.EmitSUB(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.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1);

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

                encoder.EmitJMP(helperEntrypoint);
            }
            break;

            case ReadyToRunHelperId.DelegateCtor:
            {
                ARMDebug.EmitNYIAssert(factory, ref encoder, "DelegateCtor EmitCode is not implemented");

                /*
                 ***
                 ***NOT TESTED!!!
                 ***
                 ***// 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);
                 */
            }