Exemple #1
0
        /// <summary>
        /// Initialize module info and construct per-module metadata reader.
        /// </summary>
        /// <param name="moduleHandle">Handle (address) of module to initialize</param>
        internal ModuleInfo(TypeManagerHandle moduleHandle, ModuleType moduleType)
        {
            Handle     = moduleHandle;
            ModuleType = moduleType;

            DynamicModule *dynamicModulePtr = (DynamicModule *)MemoryHelpers.AllocateMemory(sizeof(DynamicModule));

            dynamicModulePtr->CbSize = DynamicModule.DynamicModuleSize;
            Debug.Assert(sizeof(DynamicModule) >= dynamicModulePtr->CbSize);

            if ((moduleType == ModuleType.ReadyToRun) || (moduleType == ModuleType.Ecma))
            {
                // Dynamic type load modules utilize dynamic type resolution
                dynamicModulePtr->DynamicTypeSlotDispatchResolve = Intrinsics.AddrOf(
                    (Func <IntPtr, IntPtr, ushort, IntPtr>)ResolveTypeSlotDispatch);
            }
            else
            {
                Debug.Assert(moduleType == ModuleType.Eager);
                // Pre-generated modules do not
                dynamicModulePtr->DynamicTypeSlotDispatchResolve = IntPtr.Zero;
            }

            dynamicModulePtr->GetRuntimeException = Intrinsics.AddrOf(
                (Func <ExceptionIDs, Exception>)RuntimeExceptionHelpers.GetRuntimeException);

            DynamicModulePtr = dynamicModulePtr;
        }
Exemple #2
0
        private static IntPtr CreateStaticGCDesc(LowLevelList <bool> gcBitfield, out bool allocated, out int cbGCDesc)
        {
            if (gcBitfield != null)
            {
                int series = CreateGCDesc(gcBitfield, 0, false, true, null);
                if (series > 0)
                {
                    cbGCDesc = sizeof(int) + series * sizeof(int) * 2;
                    IntPtr result = MemoryHelpers.AllocateMemory(cbGCDesc);
                    CreateGCDesc(gcBitfield, 0, false, true, (void **)result.ToPointer());
                    allocated = true;
                    return(result);
                }
            }

            allocated = false;

            if (s_emptyGCDesc == IntPtr.Zero)
            {
                IntPtr ptr = MemoryHelpers.AllocateMemory(8);

                long *gcdesc = (long *)ptr.ToPointer();
                *     gcdesc = 0;

                if (Interlocked.CompareExchange(ref s_emptyGCDesc, ptr, IntPtr.Zero) != IntPtr.Zero)
                {
                    MemoryHelpers.FreeMemory(ptr);
                }
            }

            cbGCDesc = IntPtr.Size;
            return(s_emptyGCDesc);
        }
        public unsafe RuntimeFieldHandle GetRuntimeFieldHandleForComponents(RuntimeTypeHandle declaringTypeHandle, IntPtr fieldName)
        {
            string fieldNameStr = GetStringFromMemoryInNativeFormat(fieldName);

            RuntimeFieldHandleKey key = new RuntimeFieldHandleKey(declaringTypeHandle, fieldNameStr);
            RuntimeFieldHandle    runtimeFieldHandle = default(RuntimeFieldHandle);

            lock (_runtimeFieldHandles)
            {
                if (!_runtimeFieldHandles.TryGetValue(key, out runtimeFieldHandle))
                {
                    IntPtr runtimeFieldHandleValue = MemoryHelpers.AllocateMemory(sizeof(DynamicFieldHandleInfo));
                    if (runtimeFieldHandleValue == IntPtr.Zero)
                    {
                        throw new OutOfMemoryException();
                    }

                    DynamicFieldHandleInfo *fieldData = (DynamicFieldHandleInfo *)runtimeFieldHandleValue.ToPointer();
                    fieldData->DeclaringType = *(IntPtr *)&declaringTypeHandle;
                    fieldData->FieldName     = fieldName;

                    // Special flag (lowest bit set) in the handle value to indicate it was dynamically allocated
                    runtimeFieldHandleValue = runtimeFieldHandleValue + 1;
                    runtimeFieldHandle      = *(RuntimeFieldHandle *)&runtimeFieldHandleValue;

                    _runtimeFieldHandles.Add(key, runtimeFieldHandle);
                }

                return(runtimeFieldHandle);
            }
        }
Exemple #4
0
        /// <summary>
        /// Initialize module info and construct per-module metadata reader.
        /// </summary>
        /// <param name="moduleHandle">Handle (address) of module to initialize</param>
        /// <param name="moduleType">Module type</param>
        internal ModuleInfo(TypeManagerHandle moduleHandle, ModuleType moduleType)
        {
            Handle     = moduleHandle;
            ModuleType = moduleType;

            DynamicModule *dynamicModulePtr = (DynamicModule *)MemoryHelpers.AllocateMemory(sizeof(DynamicModule));

            dynamicModulePtr->CbSize = DynamicModule.DynamicModuleSize;
            Debug.Assert(sizeof(DynamicModule) >= dynamicModulePtr->CbSize);

            if ((moduleType == ModuleType.ReadyToRun) || (moduleType == ModuleType.Ecma))
            {
                // Dynamic type load modules utilize dynamic type resolution
                dynamicModulePtr->DynamicTypeSlotDispatchResolve = &ResolveTypeSlotDispatch;
            }
            else
            {
                Debug.Assert(moduleType == ModuleType.Eager);
                // Pre-generated modules do not
                dynamicModulePtr->DynamicTypeSlotDispatchResolve = null;
            }

            dynamicModulePtr->GetRuntimeException = &RuntimeExceptionHelpers.GetRuntimeException;

            DynamicModulePtr = dynamicModulePtr;
        }
Exemple #5
0
        /// <summary>
        /// Create a runtime method handle from name, signature and generic arguments. If the methodSignature
        /// is constructed from a metadata token, the methodName should be IntPtr.Zero, as it already encodes the method
        /// name.
        /// </summary>
        public unsafe RuntimeMethodHandle GetRuntimeMethodHandleForComponents(RuntimeTypeHandle declaringTypeHandle, IntPtr methodName, RuntimeSignature methodSignature, RuntimeTypeHandle[] genericMethodArgs)
        {
            // TODO! Consider interning these!, but if we do remember this function is called from code which isn't under the type builder lock
            int sizeToAllocate = sizeof(DynamicMethodHandleInfo);

            // Use checked arithmetics to ensure there aren't any overflows/truncations
            sizeToAllocate = checked (sizeToAllocate + (genericMethodArgs.Length > 0 ? sizeof(IntPtr) * (genericMethodArgs.Length - 1) : 0));
            IntPtr runtimeMethodHandleValue = MemoryHelpers.AllocateMemory(sizeToAllocate);

            if (runtimeMethodHandleValue == IntPtr.Zero)
            {
                throw new OutOfMemoryException();
            }

            DynamicMethodHandleInfo *methodData = (DynamicMethodHandleInfo *)runtimeMethodHandleValue.ToPointer();

            methodData->DeclaringType   = *(IntPtr *)&declaringTypeHandle;
            methodData->MethodName      = methodName;
            methodData->MethodSignature = methodSignature;
            methodData->NumGenericArgs  = genericMethodArgs.Length;
            IntPtr *genericArgPtr = &(methodData->GenericArgsArray);

            for (int i = 0; i < genericMethodArgs.Length; i++)
            {
                RuntimeTypeHandle currentArg = genericMethodArgs[i];
                genericArgPtr[i] = *(IntPtr *)&currentArg;
            }

            // Special flag in the handle value to indicate it was dynamically allocated, and doesn't point into the InvokeMap blob
            runtimeMethodHandleValue = runtimeMethodHandleValue + 1;
            return(*(RuntimeMethodHandle *)&runtimeMethodHandleValue);
        }
        /// <summary>
        /// Create a runtime method handle from name, signature and generic arguments. If the methodSignature
        /// is constructed from a metadata token, the methodName should be IntPtr.Zero, as it already encodes the method
        /// name.
        /// </summary>
        internal unsafe IntPtr TryGetRuntimeMethodHandleForComponents(RuntimeTypeHandle declaringTypeHandle, IntPtr methodName, RuntimeMethodSignature methodSignature, RuntimeTypeHandle[] genericMethodArgs)
        {
            int sizeToAllocate = sizeof(DynamicMethodHandleInfo);

            // Use checked arithmetics to ensure there aren't any overflows/truncations
            sizeToAllocate = checked (sizeToAllocate + (genericMethodArgs.Length > 0 ? sizeof(IntPtr) * (genericMethodArgs.Length - 1) : 0));
            IntPtr runtimeMethodHandleValue = MemoryHelpers.AllocateMemory(sizeToAllocate);

            DynamicMethodHandleInfo *methodData = (DynamicMethodHandleInfo *)runtimeMethodHandleValue.ToPointer();

            methodData->DeclaringType   = *(IntPtr *)&declaringTypeHandle;
            methodData->MethodName      = methodName;
            methodData->MethodSignature = methodSignature;
            methodData->NumGenericArgs  = genericMethodArgs.Length;
            IntPtr *genericArgPtr = &(methodData->GenericArgsArray);

            for (int i = 0; i < genericMethodArgs.Length; i++)
            {
                RuntimeTypeHandle currentArg = genericMethodArgs[i];
                genericArgPtr[i] = *(IntPtr *)&currentArg;
            }

            // Special flag in the handle value to indicate it was dynamically allocated, and doesn't point into the InvokeMap blob
            return(runtimeMethodHandleValue + 1);
        }
Exemple #7
0
        public unsafe IntPtr UpdateFloatingDictionary(IntPtr context, IntPtr dictionaryPtr)
        {
            IntPtr newFloatingDictionary;
            bool isNewlyAllocatedDictionary;
            bool isTypeContext = context != dictionaryPtr;

            if (isTypeContext)
            {
                // Look for the exact base type that owns the dictionary. We may be having
                // a virtual method run on a derived type and the generic lookup are performed
                // on the base type's dictionary.
                EEType* pEEType = (EEType*)context.ToPointer();
                context = (IntPtr)EETypeCreator.GetBaseEETypeForDictionaryPtr(pEEType, dictionaryPtr);
            }

            using (LockHolder.Hold(_typeLoaderLock))
            {
                // Check if some other thread already allocated a floating dictionary and updated the fixed portion
                if(*(IntPtr*)dictionaryPtr != IntPtr.Zero)
                    return *(IntPtr*)dictionaryPtr;

                try
                {
                    if (t_isReentrant)
                        Environment.FailFast("Reentrant update to floating dictionary");
                    t_isReentrant = true;

                    newFloatingDictionary = TypeBuilder.TryBuildFloatingDictionary(context, isTypeContext, dictionaryPtr, out isNewlyAllocatedDictionary);

                    t_isReentrant = false;
                }
                catch
                {
                    // Catch and rethrow any exceptions instead of using finally block. Otherwise, filters that are run during 
                    // the first pass of exception unwind may hit the re-entrancy fail fast above.

                    // TODO: Convert this to filter for better diagnostics once we switch to Roslyn

                    t_isReentrant = false;
                    throw;
                }
            }

            if (newFloatingDictionary == IntPtr.Zero)
            {
                Environment.FailFast("Unable to update floating dictionary");
                return IntPtr.Zero;
            }

            // The pointer to the floating dictionary is the first slot of the fixed dictionary.
            if (Interlocked.CompareExchange(ref *(IntPtr*)dictionaryPtr, newFloatingDictionary, IntPtr.Zero) != IntPtr.Zero)
            {
                // Some other thread beat us and updated the pointer to the floating dictionary.
                // Free the one allocated by the current thread
                if (isNewlyAllocatedDictionary)
                    MemoryHelpers.FreeMemory(newFloatingDictionary);
            }

            return *(IntPtr*)dictionaryPtr;
        }
        /// <summary>
        /// From a string, get a pointer to an allocated memory location that holds a NativeFormat encoded string.
        /// This is used for the creation of RuntimeFieldHandles from metadata.
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public IntPtr GetNativeFormatStringForString(string str)
        {
            using (LockHolder.Hold(_typeLoaderLock))
            {
                IntPtr result;
                if (_nativeFormatStrings.TryGetValue(str, out result))
                {
                    return(result);
                }

                NativePrimitiveEncoder stringEncoder = new NativePrimitiveEncoder();
                stringEncoder.Init();
                byte[] utf8Bytes = Encoding.UTF8.GetBytes(str);
                stringEncoder.WriteUnsigned(checked ((uint)utf8Bytes.Length));
                foreach (byte b in utf8Bytes)
                {
                    stringEncoder.WriteByte(b);
                }

                IntPtr allocatedNativeFormatString = MemoryHelpers.AllocateMemory(stringEncoder.Size);
                unsafe
                {
                    stringEncoder.Save((byte *)allocatedNativeFormatString.ToPointer(), stringEncoder.Size);
                }
                _nativeFormatStrings.Add(str, allocatedNativeFormatString);
                return(allocatedNativeFormatString);
            }
        }
Exemple #9
0
        public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind)
        {
            if (!type.IsTemplateUniversal() && (layoutKind == InstanceLayoutKind.TypeOnly))
            {
                // Non universal generics can just use the template's layout
                DefType template = (DefType)type.ComputeTemplate();
                return(_noMetadataFieldLayoutAlgorithm.ComputeInstanceLayout(template, InstanceLayoutKind.TypeOnly));
            }

            // Only needed for universal generics, or when looking up an offset for a field for a universal generic
            LowLevelList <int> fieldOffsets;

            int[] position = ComputeTypeSizeAndAlignment(type, FieldLoadState.Instance, out fieldOffsets);

            int numInstanceFields = 0;

            foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields)
            {
                if (!field.IsStatic)
                {
                    numInstanceFields++;
                }
            }

            int byteCountAlignment = position[InstanceAlignmentEntry];

            byteCountAlignment = type.Context.Target.GetObjectAlignment(byteCountAlignment);

            ComputedInstanceFieldLayout layout = new ComputedInstanceFieldLayout()
            {
                Offsets            = new FieldAndOffset[numInstanceFields],
                ByteCountAlignment = byteCountAlignment,
                ByteCountUnaligned = position[(int)NativeFormat.FieldStorage.Instance],
                PackValue          = 0 // TODO, as we add more metadata handling logic, find out if its necessary to use a meaningful value here
            };

            if (!type.IsValueType)
            {
                layout.FieldAlignment = type.Context.Target.PointerSize;
                layout.FieldSize      = type.Context.Target.PointerSize;
            }
            else
            {
                layout.FieldAlignment = position[InstanceAlignmentEntry];
                layout.FieldSize      = MemoryHelpers.AlignUp(position[(int)NativeFormat.FieldStorage.Instance], layout.FieldAlignment);
            }

            int curInstanceField = 0;

            foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields)
            {
                if (!field.IsStatic)
                {
                    layout.Offsets[curInstanceField] = new FieldAndOffset(field, fieldOffsets[curInstanceField]);
                    curInstanceField++;
                }
            }

            return(layout);
        }
        public override IntPtr Allocate()
        {
            Debug.Assert(_addressOfFirstCellSlot == IntPtr.Zero);

            if (_cells.Length > 0)
            {
                // Use checked typecast to int to ensure there aren't any overflows/truncations
                _addressOfFirstCellSlot = MemoryHelpers.AllocateMemory(checked ((int)(_cells.Length * IntPtr.Size)));
            }

            return(_addressOfFirstCellSlot);
        }
        public unsafe IntPtr TryGetRuntimeFieldHandleForComponents(RuntimeTypeHandle declaringTypeHandle, IntPtr fieldName)
        {
            IntPtr runtimeFieldHandleValue = MemoryHelpers.AllocateMemory(sizeof(DynamicFieldHandleInfo));

            DynamicFieldHandleInfo *fieldData = (DynamicFieldHandleInfo *)runtimeFieldHandleValue.ToPointer();

            fieldData->DeclaringType = *(IntPtr *)&declaringTypeHandle;
            fieldData->FieldName     = fieldName;

            // Special flag (lowest bit set) in the handle value to indicate it was dynamically allocated
            return(runtimeFieldHandleValue + 1);
        }
        //
        // Allocates a new physical buffer and returns the first offset where data can be written into buffer
        // First few bytes of the physical buffer are used to describe it.
        //
        // buffer[0-3] = Used buffer size
        //
        private unsafe int AllocatePhysicalBuffer(out IntPtr buffer)
        {
            // Allocate a new physical buffer.
            IntPtr newPhysicalBuffer = MemoryHelpers.AllocateMemory(PhysicalBufferSize);

            *(int *)newPhysicalBuffer = 0; // write the used buffer size, currently 0

            // Add the pointer to new physical buffer to DBGVISIBLE_serializedDataHeader
            AddAllocatedBufferToHeader(newPhysicalBuffer, ++_activePhysicalBufferIdx);

            buffer = newPhysicalBuffer;
            return(PhysicalBufferDataOffset);
        }
            public static unsafe IntPtr Get(RuntimeTypeHandle constraintType, RuntimeMethodHandle constrainedMethod)
            {
                lock (s_genericConstrainedCallDescs)
                {
                    // Get list of constrained call descs associated with a given type
                    LowLevelList <IntPtr> associatedCallDescs;
                    if (!s_genericConstrainedCallDescs.TryGetValue(constraintType, out associatedCallDescs))
                    {
                        associatedCallDescs = new LowLevelList <IntPtr>();
                        s_genericConstrainedCallDescs.Add(constraintType, associatedCallDescs);
                    }

                    // Perform linear scan of associated call descs to see if one matches
                    for (int i = 0; i < associatedCallDescs.Count; i++)
                    {
                        GenericConstrainedCallDesc *callDesc = (GenericConstrainedCallDesc *)associatedCallDescs[i];

                        Debug.Assert(constraintType.Equals(callDesc->_constraintType));

                        if (callDesc->_constrainedMethod != constrainedMethod)
                        {
                            continue;
                        }

                        // Found matching entry.
                        return(associatedCallDescs[i]);
                    }

                    // Did not find match, allocate a new one and add it to the lookup list
                    IntPtr newCallDescPtr = MemoryHelpers.AllocateMemory(sizeof(GenericConstrainedCallDesc));
                    GenericConstrainedCallDesc *newCallDesc = (GenericConstrainedCallDesc *)newCallDescPtr;
                    newCallDesc->_exactTarget = IntPtr.Zero;
                    if (RuntimeAugments.IsValueType(constraintType))
                    {
                        newCallDesc->_lookupFunc = s_resolveCallOnValueTypeFuncPtr;
                    }
                    else
                    {
                        newCallDesc->_lookupFunc = s_resolveCallOnReferenceTypeFuncPtr;
                    }

                    newCallDesc->_constraintType    = constraintType;
                    newCallDesc->_constrainedMethod = constrainedMethod;

                    associatedCallDescs.Add(newCallDescPtr);

                    return(newCallDescPtr);
                }
            }
 public unsafe IntPtr GetMemoryBlockForValue(IntPtr value)
 {
     using (LockHolder.Hold(_lock))
     {
         IntPtr result;
         if (_allocatedBlocks.TryGetValue(value, out result))
         {
             return(result);
         }
         result = MemoryHelpers.AllocateMemory(IntPtr.Size);
         *(IntPtr *)(result.ToPointer()) = value;
         _allocatedBlocks.Add(value, result);
         return(result);
     }
 }
 public unsafe IntPtr GetMemoryBlockForValue(ThreadStaticFieldOffsets value)
 {
     using (LockHolder.Hold(_lock))
     {
         IntPtr result;
         if (_allocatedBlocks.TryGetValue(value, out result))
         {
             return(result);
         }
         result = MemoryHelpers.AllocateMemory(sizeof(ThreadStaticFieldOffsets));
         *(ThreadStaticFieldOffsets *)(result.ToPointer()) = value;
         _allocatedBlocks.Add(value, result);
         return(result);
     }
 }
        public override unsafe IntPtr Allocate()
        {
            Debug.Assert(_addressOfFirstCellSlot == IntPtr.Zero);

            // Method dictionaries start with a header containing the hash code, which is not part of the native layout.
            // The real first slot is located after the header.
            // Use checked typecast to int to ensure there aren't any overflows/truncations
            IntPtr dictionaryWithHeader = MemoryHelpers.AllocateMemory(checked ((int)((_cells.Length + 1) * IntPtr.Size)));

            // Put a magic hash code to indicate dynamically allocated method dictionary for
            // debugging purposes.
            *(int *)dictionaryWithHeader = 0xD1CC0DE; // DICCODE

            _addressOfFirstCellSlot = IntPtr.Add(dictionaryWithHeader, IntPtr.Size);

            return(_addressOfFirstCellSlot);
        }
Exemple #17
0
        public unsafe RuntimeFieldHandle GetRuntimeFieldHandleForComponents(RuntimeTypeHandle declaringTypeHandle, IntPtr fieldName)
        {
            IntPtr runtimeFieldHandleValue = MemoryHelpers.AllocateMemory(sizeof(DynamicFieldHandleInfo));

            if (runtimeFieldHandleValue == IntPtr.Zero)
            {
                throw new OutOfMemoryException();
            }

            DynamicFieldHandleInfo *fieldData = (DynamicFieldHandleInfo *)runtimeFieldHandleValue.ToPointer();

            fieldData->DeclaringType = *(IntPtr *)&declaringTypeHandle;
            fieldData->FieldName     = fieldName;

            // Special flag (lowest bit set) in the handle value to indicate it was dynamically allocated
            runtimeFieldHandleValue = runtimeFieldHandleValue + 1;
            return(*(RuntimeFieldHandle *)&runtimeFieldHandleValue);
        }
Exemple #18
0
        /// <summary>
        /// Create a runtime method handle from name, signature and generic arguments. If the methodSignature
        /// is constructed from a metadata token, the methodName should be IntPtr.Zero, as it already encodes the method
        /// name.
        /// </summary>
        public unsafe RuntimeMethodHandle GetRuntimeMethodHandleForComponents(RuntimeTypeHandle declaringTypeHandle, IntPtr methodName, RuntimeSignature methodSignature, RuntimeTypeHandle[] genericMethodArgs)
        {
            string methodNameStr = methodName == IntPtr.Zero ? null : GetStringFromMemoryInNativeFormat(methodName);

            RuntimeMethodHandleKey key = new RuntimeMethodHandleKey(declaringTypeHandle, methodNameStr, methodSignature, genericMethodArgs);
            RuntimeMethodHandle    runtimeMethodHandle = default(RuntimeMethodHandle);

            lock (_runtimeMethodHandles)
            {
                if (!_runtimeMethodHandles.TryGetValue(key, out runtimeMethodHandle))
                {
                    int sizeToAllocate       = sizeof(DynamicMethodHandleInfo);
                    int numGenericMethodArgs = genericMethodArgs == null ? 0 : genericMethodArgs.Length;
                    // Use checked arithmetics to ensure there aren't any overflows/truncations
                    sizeToAllocate = checked (sizeToAllocate + (numGenericMethodArgs > 0 ? sizeof(IntPtr) * (numGenericMethodArgs - 1) : 0));
                    IntPtr runtimeMethodHandleValue = MemoryHelpers.AllocateMemory(sizeToAllocate);
                    if (runtimeMethodHandleValue == IntPtr.Zero)
                    {
                        throw new OutOfMemoryException();
                    }

                    DynamicMethodHandleInfo *methodData = (DynamicMethodHandleInfo *)runtimeMethodHandleValue.ToPointer();
                    methodData->DeclaringType   = *(IntPtr *)&declaringTypeHandle;
                    methodData->MethodName      = methodName;
                    methodData->MethodSignature = methodSignature;
                    methodData->NumGenericArgs  = numGenericMethodArgs;
                    IntPtr *genericArgPtr = &(methodData->GenericArgsArray);
                    for (int i = 0; i < numGenericMethodArgs; i++)
                    {
                        RuntimeTypeHandle currentArg = genericMethodArgs[i];
                        genericArgPtr[i] = *(IntPtr *)&currentArg;
                    }

                    // Special flag in the handle value to indicate it was dynamically allocated, and doesn't point into the InvokeMap blob
                    runtimeMethodHandleValue = runtimeMethodHandleValue + 1;
                    runtimeMethodHandle      = *(RuntimeMethodHandle *)&runtimeMethodHandleValue;

                    _runtimeMethodHandles.Add(key, runtimeMethodHandle);
                }

                return(runtimeMethodHandle);
            }
        }
Exemple #19
0
        /// <summary>
        /// Initialize module info and construct per-module metadata reader.
        /// </summary>
        /// <param name="moduleHandle">Handle (address) of module to initialize</param>
        internal ModuleInfo(IntPtr moduleHandle, ModuleType moduleType)
        {
            Handle     = moduleHandle;
            ModuleType = moduleType;

            byte *pBlob;
            uint  cbBlob;

            if (RuntimeAugments.FindBlob(moduleHandle, (int)ReflectionMapBlob.EmbeddedMetadata, new IntPtr(&pBlob), new IntPtr(&cbBlob)))
            {
                MetadataReader = new MetadataReader((IntPtr)pBlob, (int)cbBlob);
            }

            DynamicModule *dynamicModulePtr = (DynamicModule *)MemoryHelpers.AllocateMemory(sizeof(DynamicModule));

            dynamicModulePtr->CbSize = DynamicModule.DynamicModuleSize;
            Debug.Assert(sizeof(DynamicModule) >= dynamicModulePtr->CbSize);

#if SUPPORTS_R2R_LOADING
            if (moduleType == ModuleType.ReadyToRun)
            {
                // ReadyToRun modules utilize dynamic type resolution
                dynamicModulePtr->DynamicTypeSlotDispatchResolve = Intrinsics.AddrOf(
                    (Func <IntPtr, IntPtr, ushort, IntPtr>)ReadyToRunCallbacks.ResolveTypeSlotDispatch);
            }
            else
#endif
            {
                Debug.Assert(moduleType == ModuleType.Eager);
                // Pre-generated modules do not
                dynamicModulePtr->DynamicTypeSlotDispatchResolve = IntPtr.Zero;
            }

            dynamicModulePtr->GetRuntimeException = Intrinsics.AddrOf(
                (Func <ExceptionIDs, Exception>)RuntimeExceptionHelpers.GetRuntimeException);

            DynamicModulePtr = dynamicModulePtr;
        }
Exemple #20
0
        unsafe private static void TestGCDescsForEquality(IntPtr dynamicGCDesc, IntPtr templateGCDesc, int cbGCDesc, bool isInstanceGCDesc)
        {
            if (templateGCDesc == IntPtr.Zero)
            {
                return;
            }

            Debug.Assert(dynamicGCDesc != IntPtr.Zero);
            Debug.Assert(cbGCDesc == MemoryHelpers.AlignUp(cbGCDesc, 4));

            uint *pMem1            = (uint *)dynamicGCDesc.ToPointer();
            uint *pMem2            = (uint *)templateGCDesc.ToPointer();
            bool  foundDifferences = false;

            for (int i = 0; i < cbGCDesc; i += 4)
            {
                if (*pMem1 != *pMem2)
                {
                    // Log all the differences before the assert
                    Debug.WriteLine("ERROR: GCDesc comparison failed at byte #" + i.LowLevelToString() + " while comparing " +
                                    dynamicGCDesc.LowLevelToString() + " with " + templateGCDesc.LowLevelToString() +
                                    ": [" + (*pMem1).LowLevelToString() + "]/[" + (*pMem2).LowLevelToString() + "]");
                    foundDifferences = true;
                }
                if (isInstanceGCDesc)
                {
                    pMem1--;
                    pMem2--;
                }
                else
                {
                    pMem1++;
                    pMem2++;
                }
            }

            Debug.Assert(!foundDifferences);
        }
        private unsafe void InitializeHeader(int physicalBufferListSize)
        {
            int    headerSize = HeaderBufferListOffset + IntPtr.Size * physicalBufferListSize;
            IntPtr header     = MemoryHelpers.AllocateMemory(headerSize);
            IntPtr oldHeader  = IntPtr.Zero;

            MemoryHelpers.Memset(header, headerSize, 0);

            // check if an older header exists and copy all data from it to the newly
            // allocated header.
            if (_serializedDataHeaderSize > 0)
            {
                Debug.Assert(headerSize > _serializedDataHeaderSize);

                Buffer.MemoryCopy((byte *)DBGVISIBLE_serializedDataHeader, (byte *)header, headerSize, _serializedDataHeaderSize);

                // mark the older header for deletion
                oldHeader = DBGVISIBLE_serializedDataHeader;
            }
            else
            {
                // write the serialization format version
                *(int *)header = SerializationFormatVersion;
                // write the total allocated number of physical buffers (0)
                *(int *)(header + sizeof(int)) = 0;
                Debug.Assert(_activePhysicalBufferIdx == 0);
            }

            DBGVISIBLE_serializedDataHeader = header;
            _serializedDataHeaderSize       = headerSize;

            // delete the older header if a new one was allocated
            if (oldHeader != IntPtr.Zero)
            {
                MemoryHelpers.FreeMemory(oldHeader);
            }
        }
            /// <summary>
            /// Create a new value from a key. Must be threadsafe. Value may or may not be added
            /// to collection. Return value must not be null.
            /// </summary>
            protected override unsafe MethodEntrypointPtr CreateValueFromKey(MethodEntrypointLookup key)
            {
                lock (this)
                {
                    IntPtr thunk = IntPtr.Zero;
                    if (s_thunkPoolHeap == null)
                    {
                        s_thunkPoolHeap = RuntimeAugments.CreateThunksHeap(s_entryPointStub);
                        MethodEntrypointPtr.SetThunkPool(s_thunkPoolHeap);
                        Debug.Assert(s_thunkPoolHeap != null);
                    }

                    thunk = RuntimeAugments.AllocateThunk(s_thunkPoolHeap);
                    Debug.Assert(thunk != IntPtr.Zero);
                    MethodEntrypointData *methodEntrypointData = (MethodEntrypointData *)MemoryHelpers.AllocateMemory(sizeof(MethodEntrypointData));

                    *methodEntrypointData = new MethodEntrypointData(key.MethodHandle, thunk);

                    RuntimeAugments.SetThunkData(s_thunkPoolHeap, thunk, IntPtr.Zero, new IntPtr(methodEntrypointData));

                    SerializedDebugData.RegisterTailCallThunk(thunk);

                    return(new MethodEntrypointPtr(methodEntrypointData));
                }
            }
Exemple #23
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);
                    }
                }
            }
        }
Exemple #24
0
            public static unsafe IntPtr Get(RuntimeTypeHandle constraintType, RuntimeTypeHandle constrainedMethodType, int constrainedMethodSlot, bool directConstrainedCall = false)
            {
                LowLevelDictionary <RuntimeTypeHandle, LowLevelList <IntPtr> > nonGenericConstrainedCallDescsDirect = directConstrainedCall ? s_nonGenericConstrainedCallDescsDirect : s_nonGenericConstrainedCallDescs;

                lock (nonGenericConstrainedCallDescsDirect)
                {
                    // Get list of constrained call descs associated with a given type
                    LowLevelList <IntPtr> associatedCallDescs;
                    if (!nonGenericConstrainedCallDescsDirect.TryGetValue(constraintType, out associatedCallDescs))
                    {
                        associatedCallDescs = new LowLevelList <IntPtr>();
                        nonGenericConstrainedCallDescsDirect.Add(constraintType, associatedCallDescs);
                    }

                    // Perform linear scan of associated call descs to see if one matches
                    for (int i = 0; i < associatedCallDescs.Count; i++)
                    {
                        NonGenericConstrainedCallDesc *callDesc = (NonGenericConstrainedCallDesc *)associatedCallDescs[i];

                        Debug.Assert(constraintType.Equals(callDesc->_constraintType));

                        if (callDesc->_constrainedMethodSlot != constrainedMethodSlot)
                        {
                            continue;
                        }

                        if (!callDesc->_constrainedMethodType.Equals(constrainedMethodType))
                        {
                            continue;
                        }

                        // Found matching entry.
                        return(associatedCallDescs[i]);
                    }

                    // Did not find match, allocate a new one and add it to the lookup list
                    IntPtr newCallDescPtr = MemoryHelpers.AllocateMemory(sizeof(NonGenericConstrainedCallDesc));
                    NonGenericConstrainedCallDesc *newCallDesc = (NonGenericConstrainedCallDesc *)newCallDescPtr;
                    newCallDesc->_exactTarget = IntPtr.Zero;
                    if (directConstrainedCall)
                    {
                        newCallDesc->_lookupFunc = RuntimeAugments.GetUniversalTransitionThunk();
                    }
                    else
                    {
                        if (RuntimeAugments.IsValueType(constraintType))
                        {
                            newCallDesc->_lookupFunc = s_resolveCallOnValueTypeFuncPtr;
                        }
                        else
                        {
                            newCallDesc->_lookupFunc = s_resolveCallOnReferenceTypeFuncPtr;
                        }
                    }


                    newCallDesc->_constraintType        = constraintType;
                    newCallDesc->_constrainedMethodSlot = constrainedMethodSlot;
                    newCallDesc->_constrainedMethodType = constrainedMethodType;

                    associatedCallDescs.Add(newCallDescPtr);

                    return(newCallDescPtr);
                }
            }
        // The layout algorithm should probably compute results and let the caller set things
        internal unsafe int[] ComputeTypeSizeAndAlignment(TypeDesc type, FieldLoadState loadRequested, out LowLevelList <int> fieldOffsets)
        {
            fieldOffsets = null;
            TypeLoaderLogger.WriteLine("Laying out type " + type.ToString() + ". IsValueType: " + (type.IsValueType ? "true" : "false") + ". LoadRequested = " + ((int)loadRequested).LowLevelToString());

            Debug.Assert(loadRequested != FieldLoadState.None);
            Debug.Assert(type is ArrayType || (type is DefType && ((DefType)type).HasInstantiation));

            bool isArray = type is ArrayType;

            int[] position      = new int[5];
            int   alignRequired = 1;

            if ((loadRequested & FieldLoadState.Instance) == FieldLoadState.Instance)
            {
                ComputeTypeSizeBeforeFields(type, out position[(int)NativeFormat.FieldStorage.Instance], out alignRequired);
            }

            if (!isArray)
            {
                // Once this is done, the NativeLayoutFields on the type are initialized
                EnsureFieldLayoutLoadedForGenericType((DefType)type);
                Debug.Assert(type.NativeLayoutFields != null);
            }

            int instanceFields = 0;

            if (!isArray && type.NativeLayoutFields.Length > 0)
            {
                fieldOffsets = new LowLevelList <int>(type.NativeLayoutFields.Length);
                for (int i = 0; i < type.NativeLayoutFields.Length; i++)
                {
                    TypeDesc fieldType    = type.NativeLayoutFields[i].FieldType;
                    int      fieldStorage = (int)type.NativeLayoutFields[i].FieldStorage;

                    if (!ShouldProcessField((NativeFormat.FieldStorage)fieldStorage, loadRequested))
                    {
                        continue;
                    }

                    // For value types, we will attempt to get the size and alignment from
                    // the runtime if possible, otherwise GetFieldSizeAndAlignment will
                    // recurse to lay out nested struct fields.
                    int alignment;
                    int size;
                    GetFieldSizeAlignment(fieldType, out size, out alignment);

                    Debug.Assert(alignment > 0);

                    if (fieldStorage == (int)NativeFormat.FieldStorage.Instance)
                    {
                        instanceFields++;

                        // Ensure alignment of type is sufficient for this field
                        if (alignRequired < alignment)
                        {
                            alignRequired = alignment;
                        }
                    }

                    position[fieldStorage] = MemoryHelpers.AlignUp(position[fieldStorage], alignment);
                    TypeLoaderLogger.WriteLine(" --> Field type " + fieldType.ToString() +
                                               " storage " + ((uint)(type.NativeLayoutFields[i].FieldStorage)).LowLevelToString() +
                                               " offset " + position[fieldStorage].LowLevelToString() +
                                               " alignment " + alignment.LowLevelToString());

                    fieldOffsets.Add(position[fieldStorage]);
                    position[fieldStorage] += size;
                }
            }

            // Pad the length of structs to be 1 if they are empty so we have no zero-length structures
            if ((position[(int)NativeFormat.FieldStorage.Instance] == 0) && type.IsValueType)
            {
                position[(int)NativeFormat.FieldStorage.Instance] = 1;
            }

            Debug.Assert(alignRequired == 1 || alignRequired == 2 || alignRequired == 4 || alignRequired == 8);

            position[InstanceAlignmentEntry] = alignRequired;

            return(position);
        }