/// <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; }
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); } }
/// <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; }
/// <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 *)¤tArg; } // 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 *)¤tArg; } // Special flag in the handle value to indicate it was dynamically allocated, and doesn't point into the InvokeMap blob return(runtimeMethodHandleValue + 1); }
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); } }
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); }
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); }
/// <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 *)¤tArg; } // 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); } }
/// <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; }
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)); } }
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); } } } }
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); }