public static void RegisterDebugDataForType(TypeBuilder typeBuilder, DefType defType, TypeBuilderState state) { if (!defType.IsGeneric()) { RegisterDebugDataForNativeFormatType(typeBuilder, defType, state); return; } if (defType.IsGenericDefinition) { // We don't yet have an encoding for open generic types // TODO! fill this in return; } NativePrimitiveEncoder encoder = new NativePrimitiveEncoder(); encoder.Init(); IntPtr gcStaticFieldData = TypeLoaderEnvironment.Instance.TryGetGcStaticFieldData(typeBuilder.GetRuntimeTypeHandle(defType)); IntPtr nonGcStaticFieldData = TypeLoaderEnvironment.Instance.TryGetNonGcStaticFieldData(typeBuilder.GetRuntimeTypeHandle(defType)); bool isUniversalGenericType = state.TemplateType != null && state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.Universal); bool embeddedTypeSizeAndFieldOffsets = isUniversalGenericType || (state.TemplateType == null); uint instanceFieldCount = 0; uint staticFieldCount = 0; // GetDiagnosticFields only returns the fields that are of interest for diagnostic reporting. So it doesn't // return a meaningful list for non-universal canonical templates IEnumerable<FieldDesc> diagnosticFields = defType.GetDiagnosticFields(); foreach (var f in diagnosticFields) { if (f.IsLiteral) continue; if (f.IsStatic) { ++staticFieldCount; } else { ++instanceFieldCount; } } SharedTypeFlags sharedTypeFlags = 0; if (gcStaticFieldData != IntPtr.Zero) sharedTypeFlags |= SharedTypeFlags.HasGCStaticFieldRegion; if (nonGcStaticFieldData != IntPtr.Zero) sharedTypeFlags |= SharedTypeFlags.HasNonGCStaticFieldRegion; if (state.ThreadDataSize != 0) sharedTypeFlags |= SharedTypeFlags.HasThreadStaticFieldRegion; if (embeddedTypeSizeAndFieldOffsets) { sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasTypeSize; if (instanceFieldCount > 0) sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasInstanceFields; if (staticFieldCount > 0) sharedTypeFlags |= SerializedDebugData.SharedTypeFlags.HasStaticFields; } Instance.SerializeDataBlobTypeAndFlags(ref encoder, SerializedDataBlobKind.SharedType, (byte)sharedTypeFlags); // // The order of these writes is a contract shared between the runtime and debugger engine. // Changes here must also be updated in the debugger reader code // encoder.WriteUnsignedLong((ulong)typeBuilder.GetRuntimeTypeHandle(defType).ToIntPtr().ToInt64()); encoder.WriteUnsigned((uint)defType.Instantiation.Length); foreach (var instParam in defType.Instantiation) { encoder.WriteUnsignedLong((ulong)typeBuilder.GetRuntimeTypeHandle(instParam).ToIntPtr().ToInt64()); } if (gcStaticFieldData != IntPtr.Zero) { encoder.WriteUnsignedLong((ulong)gcStaticFieldData.ToInt64()); } if (nonGcStaticFieldData != IntPtr.Zero) { encoder.WriteUnsignedLong((ulong)nonGcStaticFieldData.ToInt64()); } // Write the TLS offset into the native thread's TLS buffer. That index de-referenced is the thread static // data region for this type if (state.ThreadDataSize != 0) { encoder.WriteUnsigned(state.ThreadStaticOffset); } // Collect information debugger only requires for universal generics and dynamically loaded types if (embeddedTypeSizeAndFieldOffsets) { Debug.Assert(state.TypeSize != null); encoder.WriteUnsigned((uint)state.TypeSize); if (instanceFieldCount > 0) { encoder.WriteUnsigned(instanceFieldCount); uint i = 0; foreach (FieldDesc f in diagnosticFields) { if (f.IsLiteral) continue; if (f.IsStatic) continue; encoder.WriteUnsigned(i); encoder.WriteUnsigned((uint)f.Offset); i++; } } if (staticFieldCount > 0) { encoder.WriteUnsigned(staticFieldCount); uint i = 0; foreach (FieldDesc f in diagnosticFields) { if (f.IsLiteral) continue; if (!f.IsStatic) continue; NativeLayoutFieldDesc nlfd = f as NativeLayoutFieldDesc; FieldStorage fieldStorage; if (nlfd != null) { // NativeLayoutFieldDesc's have the field storage information directly embedded in them fieldStorage = nlfd.FieldStorage; } else { // Metadata based types do not, but the api's to get the info are available if (f.IsThreadStatic) { fieldStorage = FieldStorage.TLSStatic; } else if (f.HasGCStaticBase) { fieldStorage = FieldStorage.GCStatic; } else { fieldStorage = FieldStorage.NonGCStatic; } } encoder.WriteUnsigned(i); encoder.WriteUnsigned((uint)fieldStorage); encoder.WriteUnsigned((uint)f.Offset); i++; } } } Instance.ThreadSafeWriteBytes(encoder.GetBytes()); }