Beispiel #1
0
        public Entry(EEType eet)
        {
            etype = new EType(eet);

            fields      = new List <Field>();
            changedFlag = false;
        }
        // cache must be a size which is a power of two.
        internal static unsafe object CastableTargetLookup(CastableObjectCacheEntry[] cache, EEType* interfaceType)
        {
            uint cacheMask = (uint)cache.Length - 1;
            uint bucket = interfaceType->HashCode & cacheMask;
            uint curbucket = bucket;

            // hash algorithm is open addressing with linear probing

            while (curbucket < cache.Length)
            {
                if (cache[curbucket].Type == interfaceType)
                    return cache[curbucket].InstanceObjectForType;
                if (cache[curbucket].Type == null)
                    return null;
                curbucket++;
            }

            // Handle wrap-around case
            curbucket = 0;
            while (curbucket < bucket)
            {
                if (cache[curbucket].Type == interfaceType)
                    return cache[curbucket].InstanceObjectForType;
                if (cache[curbucket].Type == null)
                    return null;
                curbucket++;
            }

            return null;
        }
        private static IntPtr RhResolveDispatchWorker(object pObject, EEType* pInterfaceType, ushort slot)
        {
            // Type of object we're dispatching on.
            EEType* pInstanceType = pObject.EEType;

            // Type whose DispatchMap is used. Usually the same as the above but for types which implement ICastable
            // we may repeat this process with an alternate type.
            EEType* pResolvingInstanceType = pInstanceType;

            IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                          pInterfaceType,
                                                                          slot);

            if (pTargetCode == IntPtr.Zero && pInstanceType->IsICastable)
            {
                // Dispatch not resolved through normal dispatch map, try using the ICastable
                IntPtr pfnGetImplTypeMethod = pInstanceType->ICastableGetImplTypeMethod;
                pResolvingInstanceType = (EEType*)CalliIntrinsics.Call<IntPtr>(pfnGetImplTypeMethod, pObject, new IntPtr(pInterfaceType));

                pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                         pInterfaceType,
                                                                         slot);
            }

            return pTargetCode;
        }
Beispiel #4
0
        private void button2_Click_1(object sender, EventArgs e)
        {
            resetPanels();
            EEType eet = (comboBoxEntrySelector.SelectedItem as EType).etype;

            project.entries[(int)eet] = new Entry(eet);
            //need to add the method to drop the flag "changed" in the corresponding entry
        }
Beispiel #5
0
#pragma warning restore

        public static IntPtr FindInterfaceMethodImplementationTarget(EEType* pTgtType,
                                                                 EEType* pItfType,
                                                                 ushort itfSlotNumber)
        {
            DynamicModule* dynamicModule = pTgtType->DynamicModule;

            // Use the dynamic module resolver if it's present
            if ((dynamicModule != null) && (dynamicModule->DynamicTypeSlotDispatchResolve != IntPtr.Zero))
            {
                return CalliIntrinsics.Call<IntPtr>(dynamicModule->DynamicTypeSlotDispatchResolve, 
                                                    (IntPtr)pTgtType, (IntPtr)pItfType, itfSlotNumber);
            }

            // Start at the current type and work up the inheritance chain
            EEType* pCur = pTgtType;
            UInt32 iCurInheritanceChainDelta = 0;

            if (pItfType->IsCloned)
                pItfType = pItfType->CanonicalEEType;

            while (pCur != null)
            {
                UInt16 implSlotNumber;
                if (FindImplSlotForCurrentType(
                        pCur, pItfType, itfSlotNumber, &implSlotNumber))
                {
                    IntPtr targetMethod;
                    if (implSlotNumber < pCur->NumVtableSlots)
                    {
                        // true virtual - need to get the slot from the target type in case it got overridden
                        targetMethod = pTgtType->GetVTableStartAddress()[implSlotNumber];
                    }
                    else
                    {
                        // sealed virtual - need to get the slot form the implementing type, because
                        // it's not present on the target type
                        targetMethod = pCur->GetSealedVirtualSlot((ushort)(implSlotNumber - pCur->NumVtableSlots));
                    }
                    return targetMethod;
                }
                if (pCur->IsArray)
                    pCur = pCur->GetArrayEEType();
                else
                    pCur = pCur->NonArrayBaseType;
                iCurInheritanceChainDelta++;
            }
            return IntPtr.Zero;
        }
Beispiel #6
0
        private static bool FindImplSlotForCurrentType(EEType* pTgtType,
                                        EEType* pItfType,
                                        UInt16 itfSlotNumber,
                                        UInt16* pImplSlotNumber)
        {
            bool fRes = false;

            // If making a call and doing virtual resolution don't look into the dispatch map,
            // take the slot number directly.
            if (!pItfType->IsInterface)
            {
                *pImplSlotNumber = itfSlotNumber;

                // Only notice matches if the target type and search types are the same
                // This will make dispatch to sealed slots work correctly
                return pTgtType == pItfType;
            }

            if (pTgtType->HasDispatchMap)
            {
                // For variant interface dispatch, the algorithm is to walk the parent hierarchy, and at each level
                // attempt to dispatch exactly first, and then if that fails attempt to dispatch variantly. This can
                // result in interesting behavior such as a derived type only overriding one particular instantiation
                // and funneling all the dispatches to it, but its the algorithm.

                bool fDoVariantLookup = false; // do not check variance for first scan of dispatch map 

                fRes = FindImplSlotInSimpleMap(
                    pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup);

                if (!fRes)
                {
                    fDoVariantLookup = true; // check variance for second scan of dispatch map
                    fRes = FindImplSlotInSimpleMap(
                     pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup);
                }
            }

            return fRes;
        }
Beispiel #7
0
 internal extern static unsafe IntPtr RhpGetICastableIsInstanceOfInterfaceMethod(EEType* pEEType);
Beispiel #8
0
 internal extern static unsafe byte RhpGetNullableEETypeValueOffset(EEType* pEEType);
Beispiel #9
0
 internal unsafe extern static IntPtr RhpUpdateDispatchCellCache(IntPtr pCell, IntPtr pTargetCode, EEType* pInstanceType, ref DispatchCellInfo newCellInfo);
Beispiel #10
0
 internal unsafe extern static IntPtr RhpGetSealedVirtualSlot(EEType* pEEType, ushort slot);
Beispiel #11
0
 internal unsafe extern static bool RhpHasDispatchMap(EEType* pEETypen);
Beispiel #12
0
 internal unsafe extern static void RhUnbox(object obj, ref byte data, EEType* pUnboxToEEType);
Beispiel #13
0
        private static bool ShouldTypedClauseCatchThisException(object exception, EEType* pClauseType)
        {
            if (TypeCast.IsInstanceOfClass(exception, pClauseType) != null)
                return true;

            if (s_pLowLevelObjectType == null)
            {
                // TODO: Avoid allocating here as that may fail
                s_pLowLevelObjectType = new System.Object().EEType;
            }

            // This allows the typical try { } catch { }--which expands to a typed catch of System.Object--to work on 
            // all objects when the clause is in the low level runtime code.  This special case is needed because 
            // objects from foreign type systems are sometimes throw back up at runtime code and this is the only way
            // to catch them outside of having a filter with no type check in it, which isn't currently possible to 
            // write in C#.  See https://github.com/dotnet/roslyn/issues/4388
            if (pClauseType->IsEquivalentTo(s_pLowLevelObjectType))
                return true;

            return false;
        }
Beispiel #14
0
        private static void CreateEETypeWorker(EEType *pTemplateEEType, UInt32 hashCodeOfNewType,
                                               int arity, bool requireVtableSlotMapping, TypeBuilderState state)
        {
            bool           successful            = false;
            IntPtr         eeTypePtrPlusGCDesc   = IntPtr.Zero;
            IntPtr         dynamicDispatchMapPtr = IntPtr.Zero;
            DynamicModule *dynamicModulePtr      = null;

            try
            {
                Debug.Assert((pTemplateEEType != null) || (state.TypeBeingBuilt as MetadataType != null));

                // In some situations involving arrays we can find as a template a dynamically generated type.
                // In that case, the correct template would be the template used to create the dynamic type in the first
                // place.
                if (pTemplateEEType != null && pTemplateEEType->IsDynamicType)
                {
                    pTemplateEEType = pTemplateEEType->DynamicTemplateType;
                }

                ModuleInfo moduleInfo = TypeLoaderEnvironment.GetModuleInfoForType(state.TypeBeingBuilt);
                dynamicModulePtr = moduleInfo.DynamicModulePtr;
                Debug.Assert(dynamicModulePtr != null);

                bool requiresDynamicDispatchMap = requireVtableSlotMapping && (pTemplateEEType != null) && pTemplateEEType->HasDispatchMap;

                uint valueTypeFieldPaddingEncoded = 0;
                int  baseSize = 0;

                bool   isValueType;
                bool   hasFinalizer;
                bool   isNullable;
                bool   isArray;
                bool   isGeneric;
                ushort componentSize = 0;
                ushort flags;
                ushort runtimeInterfacesLength = 0;
                bool   isGenericEETypeDef      = false;

                if (state.RuntimeInterfaces != null)
                {
                    runtimeInterfacesLength = checked ((ushort)state.RuntimeInterfaces.Length);
                }

                if (pTemplateEEType != null)
                {
                    valueTypeFieldPaddingEncoded = EEType.ComputeValueTypeFieldPaddingFieldValue(
                        pTemplateEEType->ValueTypeFieldPadding,
                        (uint)pTemplateEEType->FieldAlignmentRequirement);
                    baseSize      = (int)pTemplateEEType->BaseSize;
                    isValueType   = pTemplateEEType->IsValueType;
                    hasFinalizer  = pTemplateEEType->IsFinalizable;
                    isNullable    = pTemplateEEType->IsNullable;
                    componentSize = pTemplateEEType->ComponentSize;
                    flags         = pTemplateEEType->Flags;
                    isArray       = pTemplateEEType->IsArray;
                    isGeneric     = pTemplateEEType->IsGeneric;
                    Debug.Assert(pTemplateEEType->NumInterfaces == runtimeInterfacesLength);
                }
                else if (state.TypeBeingBuilt.IsGenericDefinition)
                {
                    flags       = (ushort)EETypeKind.GenericTypeDefEEType;
                    isValueType = state.TypeBeingBuilt.IsValueType;
                    if (isValueType)
                    {
                        flags |= (ushort)EETypeFlags.ValueTypeFlag;
                    }

                    if (state.TypeBeingBuilt.IsInterface)
                    {
                        flags |= (ushort)EETypeFlags.IsInterfaceFlag;
                    }
                    hasFinalizer       = false;
                    isArray            = false;
                    isNullable         = false;
                    isGeneric          = false;
                    isGenericEETypeDef = true;
                    componentSize      = checked ((ushort)state.TypeBeingBuilt.Instantiation.Length);
                    baseSize           = 0;
                }
                else
                {
                    isValueType  = state.TypeBeingBuilt.IsValueType;
                    hasFinalizer = state.TypeBeingBuilt.HasFinalizer;
                    isNullable   = state.TypeBeingBuilt.GetTypeDefinition().IsNullable;
                    flags        = EETypeBuilderHelpers.ComputeFlags(state.TypeBeingBuilt);
                    isArray      = false;
                    isGeneric    = state.TypeBeingBuilt.HasInstantiation;

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        state.GenericVarianceFlags = new int[state.TypeBeingBuilt.Instantiation.Length];
                        int i = 0;

                        foreach (GenericParameterDesc gpd in state.TypeBeingBuilt.GetTypeDefinition().Instantiation)
                        {
                            state.GenericVarianceFlags[i] = (int)gpd.Variance;
                            i++;
                        }
                        Debug.Assert(i == state.GenericVarianceFlags.Length);
                    }
                }

                // TODO! Change to if template is Universal or non-Existent
                if (state.TypeSize.HasValue)
                {
                    baseSize = state.TypeSize.Value;

                    int baseSizeBeforeAlignment = baseSize;

                    baseSize = MemoryHelpers.AlignUp(baseSize, IntPtr.Size);

                    if (isValueType)
                    {
                        // Compute the valuetype padding size based on size before adding the object type pointer field to the size
                        uint cbValueTypeFieldPadding = (uint)(baseSize - baseSizeBeforeAlignment);

                        // Add Object type pointer field to base size
                        baseSize += IntPtr.Size;

                        valueTypeFieldPaddingEncoded = (uint)EEType.ComputeValueTypeFieldPaddingFieldValue(cbValueTypeFieldPadding, (uint)state.FieldAlignment.Value);
                    }

                    // Minimum base size is 3 pointers, and requires us to bump the size of an empty class type
                    if (baseSize <= IntPtr.Size)
                    {
                        // ValueTypes should already have had their size bumped up by the normal type layout process
                        Debug.Assert(!isValueType);
                        baseSize += IntPtr.Size;
                    }

                    // Add sync block skew
                    baseSize += IntPtr.Size;

                    // Minimum basesize is 3 pointers
                    Debug.Assert(baseSize >= (IntPtr.Size * 3));
                }

                // Optional fields encoding
                int cbOptionalFieldsSize;
                OptionalFieldsRuntimeBuilder optionalFields;
                {
                    optionalFields = new OptionalFieldsRuntimeBuilder(pTemplateEEType != null ? pTemplateEEType->OptionalFieldsPtr : null);

                    UInt32 rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0);
                    rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeFlag;           // Set the IsDynamicTypeFlag
                    rareFlags &= ~(uint)EETypeRareFlags.NullableTypeViaIATFlag;     // Remove the NullableTypeViaIATFlag flag
                    rareFlags &= ~(uint)EETypeRareFlags.HasSealedVTableEntriesFlag; // Remove the HasSealedVTableEntriesFlag
                                                                                    // we'll set IsDynamicTypeWithSealedVTableEntriesFlag instead

                    // Set the IsDynamicTypeWithSealedVTableEntriesFlag if needed
                    if (state.NumSealedVTableEntries > 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithSealedVTableEntriesFlag;
                    }

                    if (requiresDynamicDispatchMap)
                    {
                        rareFlags |= (uint)EETypeRareFlags.HasDynamicallyAllocatedDispatchMapFlag;
                    }

                    if (state.NonGcDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics;
                    }

                    if (state.GcDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithGcStatics;
                    }

                    if (state.ThreadDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics;
                    }

#if ARM
                    if (state.FieldAlignment == 8)
                    {
                        rareFlags |= (uint)EETypeRareFlags.RequiresAlign8Flag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.RequiresAlign8Flag;
                    }

                    if (state.IsHFA)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsHFAFlag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.IsHFAFlag;
                    }
#endif
                    if (state.HasStaticConstructor)
                    {
                        rareFlags |= (uint)EETypeRareFlags.HasCctorFlag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag;
                    }

                    rareFlags |= (uint)EETypeRareFlags.HasDynamicModuleFlag;

                    optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags);

                    // Dispatch map is fetched either from template type, or from the dynamically allocated DispatchMap field
                    optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap);

                    optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding);

                    if (valueTypeFieldPaddingEncoded != 0)
                    {
                        optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded);
                    }

                    // Compute size of optional fields encoding
                    cbOptionalFieldsSize = optionalFields.Encode();
                    Debug.Assert(cbOptionalFieldsSize > 0);
                }

                // Note: The number of vtable slots on the EEType to create is not necessary equal to the number of
                // vtable slots on the template type for universal generics (see ComputeVTableLayout)
                ushort numVtableSlots = state.NumVTableSlots;

                // Compute the EEType size and allocate it
                EEType *pEEType;
                {
                    // In order to get the size of the EEType to allocate we need the following information
                    // 1) The number of VTable slots (from the TypeBuilderState)
                    // 2) The number of Interfaces (from the template)
                    // 3) Whether or not there is a finalizer (from the template)
                    // 4) Optional fields size
                    // 5) Whether or not the type is nullable (from the template)
                    // 6) Whether or not the type has sealed virtuals (from the TypeBuilderState)
                    int cbEEType = (int)EEType.GetSizeofEEType(
                        numVtableSlots,
                        runtimeInterfacesLength,
                        hasFinalizer,
                        true,
                        isNullable,
                        state.NumSealedVTableEntries > 0,
                        isGeneric,
                        state.NonGcDataSize != 0,
                        state.GcDataSize != 0,
                        state.ThreadDataSize != 0);

                    // Dynamic types have an extra pointer-sized field that contains a pointer to their template type
                    cbEEType += IntPtr.Size;

                    // Check if we need another pointer sized field for a dynamic DispatchMap
                    cbEEType += (requiresDynamicDispatchMap ? IntPtr.Size : 0);

                    // Add another pointer sized field for a DynamicModule
                    cbEEType += IntPtr.Size;

                    int cbGCDesc        = GetInstanceGCDescSize(state, pTemplateEEType, isValueType, isArray);
                    int cbGCDescAligned = MemoryHelpers.AlignUp(cbGCDesc, IntPtr.Size);

                    // Allocate enough space for the EEType + gcDescSize
                    eeTypePtrPlusGCDesc = MemoryHelpers.AllocateMemory(cbGCDescAligned + cbEEType + cbOptionalFieldsSize);

                    // Get the EEType pointer, and the template EEType pointer
                    pEEType = (EEType *)(eeTypePtrPlusGCDesc + cbGCDescAligned);
                    state.HalfBakedRuntimeTypeHandle = pEEType->ToRuntimeTypeHandle();

                    // Set basic EEType fields
                    pEEType->ComponentSize  = componentSize;
                    pEEType->Flags          = flags;
                    pEEType->BaseSize       = (uint)baseSize;
                    pEEType->NumVtableSlots = numVtableSlots;
                    pEEType->NumInterfaces  = runtimeInterfacesLength;
                    pEEType->HashCode       = hashCodeOfNewType;

                    // Write the GCDesc
                    bool isSzArray = isArray ? state.ArrayRank < 1 : false;
                    int  arrayRank = isArray ? state.ArrayRank.Value : 0;
                    CreateInstanceGCDesc(state, pTemplateEEType, pEEType, baseSize, cbGCDesc, isValueType, isArray, isSzArray, arrayRank);
                    Debug.Assert(pEEType->HasGCPointers == (cbGCDesc != 0));

#if GENERICS_FORCE_USG
                    if (state.NonUniversalTemplateType != null)
                    {
                        Debug.Assert(state.NonUniversalInstanceGCDescSize == cbGCDesc, "Non-universal instance GCDesc size not matching with universal GCDesc size!");
                        Debug.Assert(cbGCDesc == 0 || pEEType->HasGCPointers);

                        // The TestGCDescsForEquality helper will compare 2 GCDescs for equality, 4 bytes at a time (GCDesc contents treated as integers), and will read the
                        // GCDesc data in *reverse* order for instance GCDescs (subtracts 4 from the pointer values at each iteration).
                        //    - For the first GCDesc, we use (pEEType - 4) to point to the first 4-byte integer directly preceeding the EEType
                        //    - For the second GCDesc, given that the state.NonUniversalInstanceGCDesc already points to the first byte preceeding the template EEType, we
                        //      subtract 3 to point to the first 4-byte integer directly preceeding the template EEtype
                        TestGCDescsForEquality(new IntPtr((byte *)pEEType - 4), state.NonUniversalInstanceGCDesc - 3, cbGCDesc, true);
                    }
#endif

                    // Copy the encoded optional fields buffer to the newly allocated memory, and update the OptionalFields field on the EEType
                    // It is important to set the optional fields first on the newly created EEType, because all other 'setters'
                    // will assert that the type is dynamic, just to make sure we are not making any changes to statically compiled types
                    pEEType->OptionalFieldsPtr = (byte *)pEEType + cbEEType;
                    optionalFields.WriteToEEType(pEEType, cbOptionalFieldsSize);

#if CORERT
                    pEEType->PointerToTypeManager = PermanentAllocatedMemoryBlobs.GetPointerToIntPtr(moduleInfo.Handle);
#endif
                    pEEType->DynamicModule = dynamicModulePtr;

                    // Copy VTable entries from template type
                    int     numSlotsFilled = 0;
                    IntPtr *pVtable        = (IntPtr *)((byte *)pEEType + sizeof(EEType));
                    if (pTemplateEEType != null)
                    {
                        IntPtr *pTemplateVtable = (IntPtr *)((byte *)pTemplateEEType + sizeof(EEType));
                        for (int i = 0; i < pTemplateEEType->NumVtableSlots; i++)
                        {
                            int vtableSlotInDynamicType = requireVtableSlotMapping ? state.VTableSlotsMapping.GetVTableSlotInTargetType(i) : i;
                            if (vtableSlotInDynamicType != -1)
                            {
                                Debug.Assert(vtableSlotInDynamicType < numVtableSlots);

                                IntPtr dictionaryPtrValue;
                                if (requireVtableSlotMapping && state.VTableSlotsMapping.IsDictionarySlot(i, out dictionaryPtrValue))
                                {
                                    // This must be the dictionary pointer value of one of the base types of the
                                    // current universal generic type being constructed.
                                    pVtable[vtableSlotInDynamicType] = dictionaryPtrValue;

                                    // Assert that the current template vtable slot is also a NULL value since all
                                    // universal generic template types have NULL dictionary slot values in their vtables
                                    Debug.Assert(pTemplateVtable[i] == IntPtr.Zero);
                                }
                                else
                                {
                                    pVtable[vtableSlotInDynamicType] = pTemplateVtable[i];
                                }
                                numSlotsFilled++;
                            }
                        }
                    }
                    else if (isGenericEETypeDef)
                    {
                        // If creating a Generic Type Definition
                        Debug.Assert(pEEType->NumVtableSlots == 0);
                    }
                    else
                    {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                        // Dynamically loaded type

                        // Fill the vtable with vtable resolution thunks in all slots except for
                        // the dictionary slots, which should be filled with dictionary pointers if those
                        // dictionaries are already published.

                        TypeDesc nextTypeToExamineForDictionarySlot = state.TypeBeingBuilt;
                        TypeDesc typeWithDictionary;
                        int      nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);

                        for (int iSlot = pEEType->NumVtableSlots - 1; iSlot >= 0; iSlot--)
                        {
                            bool isDictionary = iSlot == nextDictionarySlot;
                            if (!isDictionary)
                            {
                                pVtable[iSlot] = LazyVTableResolver.GetThunkForSlot(iSlot);
                            }
                            else
                            {
                                if (typeWithDictionary.RetrieveRuntimeTypeHandleIfPossible())
                                {
                                    pVtable[iSlot] = typeWithDictionary.RuntimeTypeHandle.GetDictionary();
                                }
                                nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);
                            }
                            numSlotsFilled++;
                        }
#else
                        Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                    }

                    Debug.Assert(numSlotsFilled == numVtableSlots);

                    // Copy Pointer to finalizer method from the template type
                    if (hasFinalizer)
                    {
                        if (pTemplateEEType != null)
                        {
                            pEEType->FinalizerCode = pTemplateEEType->FinalizerCode;
                        }
                        else
                        {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                            pEEType->FinalizerCode = LazyVTableResolver.GetFinalizerThunk();
#else
                            Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                        }
                    }
                }

                // Copy the sealed vtable entries if they exist on the template type
                if (state.NumSealedVTableEntries > 0)
                {
                    state.HalfBakedSealedVTable = MemoryHelpers.AllocateMemory((int)state.NumSealedVTableEntries * IntPtr.Size);

                    UInt32 cbSealedVirtualSlotsTypeOffset = pEEType->GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
                    *((IntPtr *)((byte *)pEEType + cbSealedVirtualSlotsTypeOffset)) = state.HalfBakedSealedVTable;

                    for (UInt16 i = 0; i < state.NumSealedVTableEntries; i++)
                    {
                        IntPtr value = pTemplateEEType->GetSealedVirtualSlot(i);
                        pEEType->SetSealedVirtualSlot(value, i);
                    }
                }

                // Create a new DispatchMap for the type
                if (requiresDynamicDispatchMap)
                {
                    DispatchMap *pTemplateDispatchMap = (DispatchMap *)RuntimeAugments.GetDispatchMapForType(pTemplateEEType->ToRuntimeTypeHandle());

                    dynamicDispatchMapPtr = MemoryHelpers.AllocateMemory(pTemplateDispatchMap->Size);

                    UInt32 cbDynamicDispatchMapOffset = pEEType->GetFieldOffset(EETypeField.ETF_DynamicDispatchMap);
                    *((IntPtr *)((byte *)pEEType + cbDynamicDispatchMapOffset)) = dynamicDispatchMapPtr;

                    DispatchMap *pDynamicDispatchMap = (DispatchMap *)dynamicDispatchMapPtr;
                    pDynamicDispatchMap->NumEntries = pTemplateDispatchMap->NumEntries;

                    for (int i = 0; i < pTemplateDispatchMap->NumEntries; i++)
                    {
                        DispatchMap.DispatchMapEntry *pTemplateEntry = (*pTemplateDispatchMap)[i];
                        DispatchMap.DispatchMapEntry *pDynamicEntry  = (*pDynamicDispatchMap)[i];

                        pDynamicEntry->_usInterfaceIndex      = pTemplateEntry->_usInterfaceIndex;
                        pDynamicEntry->_usInterfaceMethodSlot = pTemplateEntry->_usInterfaceMethodSlot;
                        if (pTemplateEntry->_usImplMethodSlot < pTemplateEEType->NumVtableSlots)
                        {
                            pDynamicEntry->_usImplMethodSlot = (ushort)state.VTableSlotsMapping.GetVTableSlotInTargetType(pTemplateEntry->_usImplMethodSlot);
                            Debug.Assert(pDynamicEntry->_usImplMethodSlot < numVtableSlots);
                        }
                        else
                        {
                            // This is an entry in the sealed vtable. We need to adjust the slot number based on the number of vtable slots
                            // in the dynamic EEType
                            pDynamicEntry->_usImplMethodSlot = (ushort)(pTemplateEntry->_usImplMethodSlot - pTemplateEEType->NumVtableSlots + numVtableSlots);
                            Debug.Assert(state.NumSealedVTableEntries > 0 &&
                                         pDynamicEntry->_usImplMethodSlot >= numVtableSlots &&
                                         (pDynamicEntry->_usImplMethodSlot - numVtableSlots) < state.NumSealedVTableEntries);
                        }
                    }
                }

                if (pTemplateEEType != null)
                {
                    pEEType->DynamicTemplateType = pTemplateEEType;
                }
                else
                {
                    // Use object as the template type for non-template based EETypes. This will
                    // allow correct Module identification for types.

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        // TODO! We need to have a variant EEType here if the type has variance, as the
                        // CreateGenericInstanceDescForType requires it. However, this is a ridiculous api surface
                        // When we remove GenericInstanceDescs from the product, get rid of this weird special
                        // case
                        pEEType->DynamicTemplateType = typeof(IEnumerable <int>).TypeHandle.ToEETypePtr();
                    }
                    else
                    {
                        pEEType->DynamicTemplateType = typeof(object).TypeHandle.ToEETypePtr();
                    }
                }

                int nonGCStaticDataOffset = 0;

                if (!isArray && !isGenericEETypeDef)
                {
                    nonGCStaticDataOffset = state.HasStaticConstructor ? -TypeBuilder.ClassConstructorOffset : 0;

                    // create GC desc
                    if (state.GcDataSize != 0 && state.GcStaticDesc == IntPtr.Zero)
                    {
                        int cbStaticGCDesc;
                        state.GcStaticDesc = CreateStaticGCDesc(state.StaticGCLayout, out state.AllocatedStaticGCDesc, out cbStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.GcStaticDesc, state.NonUniversalStaticGCDesc, cbStaticGCDesc, false);
#endif
                    }

                    if (state.ThreadDataSize != 0 && state.ThreadStaticDesc == IntPtr.Zero)
                    {
                        int cbThreadStaticGCDesc;
                        state.ThreadStaticDesc = CreateStaticGCDesc(state.ThreadStaticGCLayout, out state.AllocatedThreadStaticGCDesc, out cbThreadStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.ThreadStaticDesc, state.NonUniversalThreadStaticGCDesc, cbThreadStaticGCDesc, false);
#endif
                    }

                    // If we have a class constructor, our NonGcDataSize MUST be non-zero
                    Debug.Assert(!state.HasStaticConstructor || (state.NonGcDataSize != 0));
                }

                if (isGeneric)
                {
                    if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, arity, state.NonGcDataSize, nonGCStaticDataOffset,
                                                                          state.GcDataSize, (int)state.ThreadStaticOffset, state.GcStaticDesc, state.ThreadStaticDesc, state.GenericVarianceFlags))
                    {
                        throw new OutOfMemoryException();
                    }
                }
                else
                {
                    Debug.Assert(arity == 0 || isGenericEETypeDef);
                    // We don't need to report the non-gc and gc static data regions and allocate them for non-generics,
                    // as we currently place these fields directly into the image
                    if (!isGenericEETypeDef && state.ThreadDataSize != 0)
                    {
                        // Types with thread static fields ALWAYS get a GID. The GID is used to perform GC
                        // and lifetime management of the thread static data. However, these GIDs are only used for that
                        // so the specified GcDataSize, etc are 0
                        if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, 0, 0, 0, 0, (int)state.ThreadStaticOffset, IntPtr.Zero, state.ThreadStaticDesc, null))
                        {
                            throw new OutOfMemoryException();
                        }
                    }
                }

                if (state.Dictionary != null)
                {
                    state.HalfBakedDictionary = state.Dictionary.Allocate();
                }

                Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());
                Debug.Assert((state.NumSealedVTableEntries == 0 && state.HalfBakedSealedVTable == IntPtr.Zero) || (state.NumSealedVTableEntries > 0 && state.HalfBakedSealedVTable != IntPtr.Zero));
                Debug.Assert((state.Dictionary == null && state.HalfBakedDictionary == IntPtr.Zero) || (state.Dictionary != null && state.HalfBakedDictionary != IntPtr.Zero));

                successful = true;
            }
            finally
            {
                if (!successful)
                {
                    if (eeTypePtrPlusGCDesc != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(eeTypePtrPlusGCDesc);
                    }
                    if (dynamicDispatchMapPtr != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(dynamicDispatchMapPtr);
                    }
                    if (state.HalfBakedSealedVTable != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(state.HalfBakedSealedVTable);
                    }
                    if (state.HalfBakedDictionary != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(state.HalfBakedDictionary);
                    }
                    if (state.AllocatedStaticGCDesc)
                    {
                        MemoryHelpers.FreeMemory(state.GcStaticDesc);
                    }
                    if (state.AllocatedThreadStaticGCDesc)
                    {
                        MemoryHelpers.FreeMemory(state.ThreadStaticDesc);
                    }
                }
            }
        }
Beispiel #15
0
 unsafe static bool IsInstanceOfInterfaceViaICastable(object obj, EEType* pTargetType)
 {
     // Call the ICastable.IsInstanceOfInterface method directly rather than via an interface
     // dispatch since we know the method address statically. We ignore any cast error exception
     // object passed back on failure (result == false) since IsInstanceOfInterface never throws.
     IntPtr pfnIsInstanceOfInterface = obj.EEType->ICastableIsInstanceOfInterfaceMethod;
     Exception castError = null;
     if (CalliIntrinsics.Call<bool>(pfnIsInstanceOfInterface, obj, pTargetType, out castError))
         return true;
     return false;
 }
Beispiel #16
0
        // Compare two types to see if they are compatible via generic variance.
        static private unsafe bool TypesAreCompatibleViaGenericVariance(EEType* pSourceType, EEType* pTargetType)
        {
            EEType* pTargetGenericType = pTargetType->GenericDefinition;
            EEType* pSourceGenericType = pSourceType->GenericDefinition;

            // If the generic types aren't the same then the types aren't compatible.
            if (pSourceGenericType == pTargetGenericType)
            {
                // Get generic instantiation metadata for both types.

                EETypeRef* pTargetInstantiation = pTargetType->GenericArguments;
                int targetArity = (int)pTargetType->GenericArity;
                GenericVariance* pTargetVarianceInfo = pTargetType->GenericVariance;

                Debug.Assert(pTargetVarianceInfo != null, "did not expect empty variance info");

                EETypeRef* pSourceInstantiation = pSourceType->GenericArguments;
                int sourceArity = (int)pSourceType->GenericArity;
                GenericVariance* pSourceVarianceInfo = pSourceType->GenericVariance;

                Debug.Assert(pSourceVarianceInfo != null, "did not expect empty variance info");

                // The types represent different instantiations of the same generic type. The
                // arity of both had better be the same.
                Debug.Assert(targetArity == sourceArity, "arity mismatch betweeen generic instantiations");

                // Compare the instantiations to see if they're compatible taking variance into account.
                if (TypeParametersAreCompatible(targetArity,
                                                pSourceInstantiation,
                                                pTargetInstantiation,
                                                pTargetVarianceInfo,
                                                false))
                {
                    return true;
                }
            }

            return false;
        }
Beispiel #17
0
 public EType()
 {
     etype = EEType.article;
 }
Beispiel #18
0
 internal unsafe extern static object RhpNewFastMisalign(EEType * pEEType);
Beispiel #19
0
 public EType(EEType et)
 {
     etype = et;
 }
Beispiel #20
0
 internal unsafe extern static EEType* RhpGetArrayBaseType(EEType* pEEType);
Beispiel #21
0
 /// <summary>
 /// Return true if both types are good for simple casting: canonical, no related type via IAT, no generic variance
 /// </summary>
 internal static bool BothSimpleCasting(EEType* pThis, EEType* pOther)
 {
     return ((pThis->_usFlags | pOther->_usFlags) & (ushort)EETypeFlags.ComplexCastingMask) == (ushort)EETypeKind.CanonicalEEType;
 }
Beispiel #22
0
 internal unsafe extern static DispatchResolve.DispatchMap* RhpGetDispatchMap(EEType* pEEType);
Beispiel #23
0
        internal bool IsEquivalentTo(EEType* pOtherEEType)
        {
            fixed (EEType* pThis = &this)
            {
                if (pThis == pOtherEEType)
                    return true;

                EEType* pThisEEType = pThis;

                if (pThisEEType->IsCloned)
                    pThisEEType = pThisEEType->CanonicalEEType;

                if (pOtherEEType->IsCloned)
                    pOtherEEType = pOtherEEType->CanonicalEEType;

                if (pThisEEType == pOtherEEType)
                    return true;

                if (pThisEEType->IsParameterizedType && pOtherEEType->IsParameterizedType)
                {
                    return pThisEEType->RelatedParameterType->IsEquivalentTo(pOtherEEType->RelatedParameterType) &&
                        pThisEEType->ParameterizedTypeShape == pOtherEEType->ParameterizedTypeShape;
                }
            }

            return false;
        }
Beispiel #24
0
 internal unsafe extern static IntPtr RhpSearchDispatchCellCache(IntPtr pCell, EEType* pInstanceType);
Beispiel #25
0
 // Returns true if the passed in EEType is the EEType for System.Object
 // This is recognized by the fact that System.Object and interfaces are the only ones without a base type
 internal static unsafe bool IsSystemObject(EEType* pEEType)
 {
     if (pEEType->IsArray)
         return false;
     return (pEEType->NonArrayBaseType == null) && !pEEType->IsInterface;
 }
Beispiel #26
0
 internal extern static unsafe UInt32 RhpGetEETypeRareFlags(EEType* pEEType);
Beispiel #27
0
 // Returns true if the passed in EEType is the EEType for System.Array.
 // The binder sets a special CorElementType for this well known type
 internal static unsafe bool IsSystemArray(EEType* pEEType)
 {
     return (pEEType->CorElementType == CorElementType.ELEMENT_TYPE_ARRAY);
 }
Beispiel #28
0
 internal extern static unsafe EEType* RhpGetNullableEEType(EEType* pEEType);
Beispiel #29
0
 internal void SetToCloneOf(EEType *pOrigType)
 {
     Debug.Assert((_usFlags & (ushort)EETypeFlags.EETypeKindMask) == 0, "should be a canonical type");
     this._usFlags |= (ushort)EETypeKind.ClonedEEType;
     this._relatedType._pCanonicalType = pOrigType;
 }
Beispiel #30
0
 internal extern static unsafe IntPtr RhpGetICastableGetImplTypeMethod(EEType* pEEType);
Beispiel #31
0
 internal unsafe extern static object RhpNewFastAlign8(EEType * pEEType);  // BEWARE: not for finalizable objects!
Beispiel #32
0
        static internal unsafe bool ImplementsInterface(EEType* pObjType, EEType* pTargetType)
        {
            Debug.Assert(!pTargetType->IsParameterizedType, "did not expect paramterized type");
            Debug.Assert(pTargetType->IsInterface, "IsInstanceOfInterface called with non-interface EEType");

            // This can happen with generic interface types
            // Debug.Assert(!pTargetType->IsCloned, "cloned interface types are disallowed");

            // canonicalize target type
            if (pTargetType->IsCloned)
                pTargetType = pTargetType->CanonicalEEType;

            int numInterfaces = pObjType->NumInterfaces;
            EEInterfaceInfo* interfaceMap = pObjType->InterfaceMap;
            for (int i = 0; i < numInterfaces; i++)
            {
                EEType* pInterfaceType = interfaceMap[i].InterfaceType;

                // canonicalize the interface type
                if (pInterfaceType->IsCloned)
                    pInterfaceType = pInterfaceType->CanonicalEEType;

                if (pInterfaceType == pTargetType)
                {
                    return true;
                }
            }

            // We did not find the interface type in the list of supported interfaces. There's still one
            // chance left: if the target interface is generic and one or more of its type parameters is co or
            // contra variant then the object can still match if it implements a different instantiation of
            // the interface with type compatible generic arguments.
            //
            // Interfaces which are only variant for arrays have the HasGenericVariance flag set even if they
            // are not variant.
            bool fArrayCovariance = pObjType->IsArray;
            if (pTargetType->HasGenericVariance)
            {
                // Grab details about the instantiation of the target generic interface.
                EEType* pTargetGenericType = pTargetType->GenericDefinition;
                EETypeRef* pTargetInstantiation = pTargetType->GenericArguments;
                int targetArity = (int)pTargetType->GenericArity;
                GenericVariance* pTargetVarianceInfo = pTargetType->GenericVariance;

                Debug.Assert(pTargetVarianceInfo != null, "did not expect empty variance info");


                for (int i = 0; i < numInterfaces; i++)
                {
                    EEType* pInterfaceType = interfaceMap[i].InterfaceType;

                    // We can ignore interfaces which are not also marked as having generic variance
                    // unless we're dealing with array covariance. 
                    //
                    // Interfaces which are only variant for arrays have the HasGenericVariance flag set even if they
                    // are not variant.
                    if (pInterfaceType->HasGenericVariance)
                    {
                        EEType* pInterfaceGenericType = pInterfaceType->GenericDefinition;

                        // If the generic types aren't the same then the types aren't compatible.
                        if (pInterfaceGenericType != pTargetGenericType)
                            continue;

                        // Grab instantiation details for the candidate interface.
                        EETypeRef* pInterfaceInstantiation = pInterfaceType->GenericArguments;
                        int interfaceArity = (int)pInterfaceType->GenericArity;
                        GenericVariance* pInterfaceVarianceInfo = pInterfaceType->GenericVariance;

                        Debug.Assert(pInterfaceVarianceInfo != null, "did not expect empty variance info");

                        // The types represent different instantiations of the same generic type. The
                        // arity of both had better be the same.
                        Debug.Assert(targetArity == interfaceArity, "arity mismatch betweeen generic instantiations");

                        // Compare the instantiations to see if they're compatible taking variance into account.
                        if (TypeParametersAreCompatible(targetArity,
                                                        pInterfaceInstantiation,
                                                        pTargetInstantiation,
                                                        pTargetVarianceInfo,
                                                        fArrayCovariance))
                            return true;
                    }
                }
            }

            return false;
        }
Beispiel #33
0
 internal unsafe extern static object RhpNewFinalizableAlign8(EEType* pEEType);
Beispiel #34
0
        // Internally callable version of the export method above. Has two additional flags:
        //  fBoxedSource            : assume the source type is boxed so that value types and enums are
        //                            compatible with Object, ValueType and Enum (if applicable)
        //  fAllowSizeEquivalence   : allow identically sized integral types and enums to be considered
        //                            equivalent (currently used only for array element types)
        static internal unsafe bool AreTypesAssignableInternal(EEType* pSourceType, EEType* pTargetType, AssignmentVariation variation)
        {
            bool fBoxedSource = ((variation & AssignmentVariation.BoxedSource) == AssignmentVariation.BoxedSource);
            bool fAllowSizeEquivalence = ((variation & AssignmentVariation.AllowSizeEquivalence ) == AssignmentVariation.AllowSizeEquivalence);

            //
            // Are the types identical?
            //
            if (AreTypesEquivalentInternal(pSourceType, pTargetType))
                return true;

            //
            // Handle cast to interface cases.
            //
            if (pTargetType->IsInterface)
            {
                // Value types can only be cast to interfaces if they're boxed.
                if (!fBoxedSource && pSourceType->IsValueType)
                    return false;

                if (ImplementsInterface(pSourceType, pTargetType))
                    return true;

                // Are the types compatible due to generic variance?
                if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance)
                    return TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType);

                return false;
            }
            if (pSourceType->IsInterface)
            {
                // The only non-interface type an interface can be cast to is Object.
                return WellKnownEETypes.IsSystemObject(pTargetType);
            }

            //
            // Handle cast to array or pointer cases.
            //
            if (pTargetType->IsParameterizedType)
            {
                if (pSourceType->IsParameterizedType 
                    && (pTargetType->ParameterizedTypeShape == pSourceType->ParameterizedTypeShape))
                {
                    // Source type is also a parameterized type. Are the parameter types compatible? 
                    if (pSourceType->RelatedParameterType->IsPointerType)
                    {
                        // If the parameter types are pointers, then only exact matches are correct.
                        // As we've already called AreTypesEquivalent at the start of this function,
                        // return false as the exact match case has already been handled.
                        // int** is not compatible with uint**, nor is int*[] oompatible with uint*[].
                        return false;
                    }
                    else
                    {
                        // Note that using AreTypesAssignableInternal with AssignmentVariation.AllowSizeEquivalence 
                        // here handles array covariance as well as IFoo[] -> Foo[] etc.  We are not using 
                        // AssignmentVariation.BoxedSource because int[] is not assignable to object[].
                        return CastCache.AreTypesAssignableInternal(pSourceType->RelatedParameterType, 
                            pTargetType->RelatedParameterType, AssignmentVariation.AllowSizeEquivalence);
                    }
                }

                // Can't cast a non-parameter type to a parameter type or a parameter type of different shape to a parameter type
                return false;
            }
            if (pSourceType->IsArray)
            {
                // Target type is not an array. But we can still cast arrays to Object or System.Array.
                return WellKnownEETypes.IsSystemObject(pTargetType) || WellKnownEETypes.IsSystemArray(pTargetType);
            }
            else if (pSourceType->IsParameterizedType)
            {
                return false;
            }

            //
            // Handle cast to other (non-interface, non-array) cases.
            //

            if (pSourceType->IsValueType)
            {
                // Certain value types of the same size are treated as equivalent when the comparison is
                // between array element types (indicated by fAllowSizeEquivalence). These are integer types
                // of the same size (e.g. int and uint) and the base type of enums vs all integer types of the
                // same size.
                if (fAllowSizeEquivalence && pTargetType->IsValueType)
                {
                    if (ArePrimitveTypesEquivalentSize(pSourceType, pTargetType))
                        return true;

                    // Non-identical value types aren't equivalent in any other case (since value types are
                    // sealed).
                    return false;
                }

                // If the source type is a value type but it's not boxed then we've run out of options: the types
                // are not identical, the target type isn't an interface and we're not allowed to check whether
                // the target type is a parent of this one since value types are sealed and thus the only matches
                // would be against Object, ValueType or Enum, all of which are reference types and not compatible
                // with non-boxed value types.
                if (!fBoxedSource)
                    return false;
            }

            // Sub case of casting between two instantiations of the same delegate type where one or more of
            // the type parameters have variance. Only interfaces and delegate types can have variance over
            // their type parameters and we know that neither type is an interface due to checks above.
            if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance)
            {
                // We've dealt with the identical case at the start of this method. And the regular path below
                // will handle casting to Object, Delegate and MulticastDelegate. Since we don't support
                // deriving from user delegate classes any further all we have to check here is that the
                // uninstantiated generic delegate definitions are the same and the type parameters are
                // compatible.
                return TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType);
            }

            // Is the source type derived from the target type?
            if (IsDerived(pSourceType, pTargetType))
                return true;

            return false;
        }
Beispiel #35
0
 internal unsafe extern static object RhpNewArrayAlign8(EEType* pEEType, int length);