From d50bdf1f75a3be86dacccdb82936e9f74f21a290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 1 Oct 2015 13:20:39 -0700 Subject: [PATCH 1/3] Add support for non-GC static fields This change includes: 1. Static field layout computation (general purpose enough to cover GC statics and thread statics) 2. Associated codegen support to generate helpers and calls to helpers (non-GC, non-thread, non-RVA fields only, with no support for class constructors and associated semantics) 3. Emission of the non-GC static section into the assembly file --- src/ILToNative/src/Compiler/AsmWriter.cs | 35 ++++ .../src/Compiler/ReadyToRunHelper.cs | 3 + src/JitInterface/src/CorInfoImpl.cs | 31 +++- src/TypeSystem/src/Common/FieldDesc.cs | 30 ++++ .../src/Common/FieldForInstantiatedType.cs | 16 ++ src/TypeSystem/src/Common/FieldLayout.cs | 149 +++++++++++++++++- .../src/Common/TypeSystemHelpers.cs | 17 ++ src/TypeSystem/src/Ecma/EcmaField.cs | 25 +++ 8 files changed, 296 insertions(+), 10 deletions(-) diff --git a/src/ILToNative/src/Compiler/AsmWriter.cs b/src/ILToNative/src/Compiler/AsmWriter.cs index 773b8ea0a5e..9e9bd30f3cf 100644 --- a/src/ILToNative/src/Compiler/AsmWriter.cs +++ b/src/ILToNative/src/Compiler/AsmWriter.cs @@ -32,6 +32,11 @@ void OutputCode() OutputEETypes(); + Out.WriteLine(); + Out.WriteLine(".data"); + + OutputStatics(); + Out.Dispose(); } @@ -222,6 +227,13 @@ void OutputReadyToHelpers() Out.WriteLine("jmp __castclass_class"); break; + case ReadyToRunHelperId.GetNonGCStaticBase: + Out.Write("leaq __NonGCStaticBase_"); + Out.Write(GetMangledTypeName((TypeDesc)helper.Target)); + Out.WriteLine("(%rip), %rax"); + Out.WriteLine("ret"); + break; + default: throw new NotImplementedException(); } @@ -260,6 +272,29 @@ void OutputEETypes() } } + void OutputStatics() + { + foreach (var t in _registeredTypes.Values) + { + if (!t.IncludedInCompilation) + continue; + + if (t.Type.NonGCStaticFieldSize > 0) + { + Out.Write(".align "); + Out.WriteLine(t.Type.NonGCStaticFieldAlignment); + Out.Write("__NonGCStaticBase_"); + Out.Write(GetMangledTypeName(t.Type)); + Out.WriteLine(":"); + Out.Write(".rept "); + Out.WriteLine(t.Type.NonGCStaticFieldSize); + Out.WriteLine(".byte 0"); + Out.WriteLine(".endr"); + Out.WriteLine(); + } + } + } + void OutputVirtualSlots(TypeDesc implType, TypeDesc declType) { var baseType = declType.BaseType; diff --git a/src/ILToNative/src/Compiler/ReadyToRunHelper.cs b/src/ILToNative/src/Compiler/ReadyToRunHelper.cs index 797c995899e..57362b293a3 100644 --- a/src/ILToNative/src/Compiler/ReadyToRunHelper.cs +++ b/src/ILToNative/src/Compiler/ReadyToRunHelper.cs @@ -17,6 +17,7 @@ public enum ReadyToRunHelperId VirtualCall, IsInstanceOf, CastClass, + GetNonGCStaticBase, } class ReadyToRunHelper @@ -48,6 +49,8 @@ public string MangledName return "__IsInstanceOf_" + _compilation.GetMangledTypeName((TypeDesc)this.Target); case ReadyToRunHelperId.CastClass: return "__CastClass_" + _compilation.GetMangledTypeName((TypeDesc)this.Target); + case ReadyToRunHelperId.GetNonGCStaticBase: + return "__GetNonGCStaticBase_" + _compilation.GetMangledTypeName((TypeDesc)this.Target); default: throw new NotImplementedException(); } diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index 6a99659b57b..53947bd89f0 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -782,7 +782,10 @@ CorInfoIsAccessAllowedResult canAccessClass(IntPtr _this, ref CORINFO_RESOLVED_T } CORINFO_CLASS_STRUCT_* getFieldClass(IntPtr _this, CORINFO_FIELD_STRUCT_* field) - { throw new NotImplementedException(); } + { + var fieldDesc = HandleToObject(field); + return ObjectToHandle(fieldDesc.OwningType); + } CorInfoType getFieldType(IntPtr _this, CORINFO_FIELD_STRUCT_* field, ref CORINFO_CLASS_STRUCT_* structType, CORINFO_CLASS_STRUCT_* memberParent) { @@ -825,10 +828,30 @@ void getFieldInfo(IntPtr _this, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORIN if (field.IsStatic) { fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC; - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_ADDRESS; - // TODO: Shared statics/HasFieldRVA - throw new NotImplementedException(); + if (field.HasRva) + { + throw new NotSupportedException(); + } + + // Make sure to include the type in the compilation + _compilation.AddType(field.OwningType); + + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; + pResult.helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE; + + ReadyToRunHelperId helperId; + if (field.IsThreadStatic || field.HasGCStaticBase) + { + throw new NotImplementedException(); + } + else + { + helperId = ReadyToRunHelperId.GetNonGCStaticBase; + } + + pResult.fieldLookup.addr = (void*)ObjectToHandle(_compilation.GetReadyToRunHelper(helperId, field.OwningType)); + pResult.fieldLookup.accessType = InfoAccessType.IAT_VALUE; } else { diff --git a/src/TypeSystem/src/Common/FieldDesc.cs b/src/TypeSystem/src/Common/FieldDesc.cs index 49abcd383b7..59505796212 100644 --- a/src/TypeSystem/src/Common/FieldDesc.cs +++ b/src/TypeSystem/src/Common/FieldDesc.cs @@ -4,6 +4,8 @@ using System; using System.Runtime.CompilerServices; +using Debug = System.Diagnostics.Debug; + namespace Internal.TypeSystem { public abstract partial class FieldDesc @@ -54,6 +56,34 @@ public abstract bool IsInitOnly get; } + public abstract bool IsThreadStatic + { + get; + } + + public abstract bool HasRva + { + get; + } + + public bool HasGCStaticBase + { + get + { + Debug.Assert(IsStatic); + TypeFlags category = FieldType.UnderlyingCategory(); + switch (category) + { + case TypeFlags.ValueType: + case TypeFlags.Class: + case TypeFlags.Array: + return true; + default: + return false; + } + } + } + public virtual FieldDesc GetTypicalFieldDefinition() { return this; diff --git a/src/TypeSystem/src/Common/FieldForInstantiatedType.cs b/src/TypeSystem/src/Common/FieldForInstantiatedType.cs index dde3df0bccb..e48f66377fa 100644 --- a/src/TypeSystem/src/Common/FieldForInstantiatedType.cs +++ b/src/TypeSystem/src/Common/FieldForInstantiatedType.cs @@ -64,6 +64,22 @@ public override bool IsInitOnly } } + public override bool IsThreadStatic + { + get + { + return _fieldDef.IsThreadStatic; + } + } + + public override bool HasRva + { + get + { + return _fieldDef.HasRva; + } + } + public override FieldDesc GetTypicalFieldDefinition() { return _fieldDef; diff --git a/src/TypeSystem/src/Common/FieldLayout.cs b/src/TypeSystem/src/Common/FieldLayout.cs index 9d87f6b681a..4e3bff6732c 100644 --- a/src/TypeSystem/src/Common/FieldLayout.cs +++ b/src/TypeSystem/src/Common/FieldLayout.cs @@ -8,21 +8,21 @@ namespace Internal.TypeSystem { - public struct InstanceFieldMason + public struct FieldMason { private MetadataType _type; private int _numInstanceFields; private ComputedInstanceFieldLayout _computedLayout; - private InstanceFieldMason(MetadataType type, int numInstanceFields) + private FieldMason(MetadataType type, int numInstanceFields) { _type = type; _computedLayout = new ComputedInstanceFieldLayout(); _numInstanceFields = numInstanceFields; } - public static ComputedInstanceFieldLayout ComputeFieldLayout(MetadataType type) + public static ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type) { // CLI - Partition 1, section 9.5 - Generic types shall not be marked explicitlayout. if (type.HasInstantiation && type.IsExplicitLayout) @@ -139,7 +139,7 @@ out byteCount // At this point all special cases are handled and all inputs validated - InstanceFieldMason mason = new InstanceFieldMason(type, numInstanceFields); + FieldMason mason = new FieldMason(type, numInstanceFields); if (type.IsExplicitLayout) { @@ -154,6 +154,63 @@ out byteCount return mason._computedLayout; } + public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(MetadataType type) + { + int numStaticFields = 0; + + foreach (var field in type.GetFields()) + { + if (!field.IsStatic) + continue; + + numStaticFields++; + } + + FieldAndOffset[] computedOffsets = new FieldAndOffset[numStaticFields]; + + int* cumulativeFieldPos = stackalloc int[3]; + int* largestAlignmentRequired = stackalloc int[3]; + int index = 0; + + foreach (var field in type.GetFields()) + { + if (!field.IsStatic) + continue; + + int offsetType = field.IsThreadStatic ? 2 : + field.HasGCStaticBase ? 1 : + 0; + + if (field.HasRva) + { + throw new NotImplementedException(); + } + + SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, type.Context.Target.DefaultPackingSize); + + cumulativeFieldPos[offsetType] = AlignmentHelper.AlignUp(cumulativeFieldPos[offsetType], sizeAndAlignment.Alignment); + computedOffsets[index] = new FieldAndOffset(field, cumulativeFieldPos[offsetType]); + cumulativeFieldPos[offsetType] = checked(cumulativeFieldPos[offsetType] + sizeAndAlignment.Size); + + largestAlignmentRequired[offsetType] = Math.Max(largestAlignmentRequired[offsetType], sizeAndAlignment.Alignment); + + index++; + } + + ComputedStaticFieldLayout result; + + result.NonGCStaticFieldSize = cumulativeFieldPos[0]; + result.NonGCStaticFieldAlignment = largestAlignmentRequired[0]; + result.GCStaticFieldSize = cumulativeFieldPos[1]; + result.GCStaticFieldAlignment = largestAlignmentRequired[1]; + result.ThreadStaticFieldSize = cumulativeFieldPos[2]; + result.ThreadStaticFieldAlignment = largestAlignmentRequired[2]; + + result.Offsets = computedOffsets; + + return result; + } + private void ComputeExplicitFieldLayout() { // Instance slice size is the total size of instance not including the base type. @@ -385,6 +442,25 @@ private struct SizeAndAlignment } } + public partial class TypeDesc + { + public virtual int NonGCStaticFieldSize + { + get + { + return 0; + } + } + + public virtual int NonGCStaticFieldAlignment + { + get + { + return 0; + } + } + } + public partial class MetadataType { private class FieldLayoutFlags @@ -392,6 +468,7 @@ private class FieldLayoutFlags public const int HasContainsPointers = 1; public const int ContainsPointers = 2; public const int HasInstanceFieldLayout = 4; + public const int HasStaticFieldLayout = 8; } volatile int _fieldLayoutFlags; @@ -400,6 +477,9 @@ private class FieldLayoutFlags int _instanceByteCount; int _instanceFieldAlignment; + int _nonGCStaticFieldSize; + int _nonGCStaticFieldAlignment; + public bool ContainsPointers { get @@ -453,9 +533,33 @@ public int InstanceByteCount } } + public override int NonGCStaticFieldSize + { + get + { + if ((_fieldLayoutFlags & FieldLayoutFlags.HasStaticFieldLayout) == 0) + { + ComputeStaticFieldLayout(); + } + return _nonGCStaticFieldSize; + } + } + + public override int NonGCStaticFieldAlignment + { + get + { + if ((_fieldLayoutFlags & FieldLayoutFlags.HasStaticFieldLayout) == 0) + { + ComputeStaticFieldLayout(); + } + return _nonGCStaticFieldAlignment; + } + } + internal void ComputeInstanceFieldLayout() { - var computedLayout = InstanceFieldMason.ComputeFieldLayout(this); + var computedLayout = FieldMason.ComputeInstanceFieldLayout(this); _instanceFieldSize = computedLayout.FieldSize; _instanceFieldAlignment = computedLayout.FieldAlignment; @@ -470,6 +574,21 @@ internal void ComputeInstanceFieldLayout() EnableFieldLayoutFlags(FieldLayoutFlags.HasInstanceFieldLayout); } + internal void ComputeStaticFieldLayout() + { + var computedStaticLayout = FieldMason.ComputeStaticFieldLayout(this); + + _nonGCStaticFieldSize = computedStaticLayout.NonGCStaticFieldSize; + _nonGCStaticFieldAlignment = computedStaticLayout.NonGCStaticFieldAlignment; + + foreach (var fieldAndOffset in computedStaticLayout.Offsets) + { + Debug.Assert(fieldAndOffset.Field.OwningType == this); + fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); + } + EnableFieldLayoutFlags(FieldLayoutFlags.HasStaticFieldLayout); + } + private bool ComputeTypeContainsPointers() { if (!IsValueType && HasBaseType && BaseType.ContainsPointers) @@ -546,7 +665,11 @@ public int Offset { if (_offset == FieldAndOffset.InvalidOffset) { - OwningType.ComputeInstanceFieldLayout(); + if (IsStatic) + OwningType.ComputeStaticFieldLayout(); + else + OwningType.ComputeInstanceFieldLayout(); + Debug.Assert(_offset != FieldAndOffset.InvalidOffset); } return _offset; } @@ -567,4 +690,18 @@ public struct ComputedInstanceFieldLayout public int ByteCount; public FieldAndOffset[] Offsets; } + + public struct ComputedStaticFieldLayout + { + public int NonGCStaticFieldSize; + public int NonGCStaticFieldAlignment; + + public int GCStaticFieldSize; + public int GCStaticFieldAlignment; + + public int ThreadStaticFieldSize; + public int ThreadStaticFieldAlignment; + + public FieldAndOffset[] Offsets; + } } diff --git a/src/TypeSystem/src/Common/TypeSystemHelpers.cs b/src/TypeSystem/src/Common/TypeSystemHelpers.cs index 9d9770fabc4..638a6f86976 100644 --- a/src/TypeSystem/src/Common/TypeSystemHelpers.cs +++ b/src/TypeSystem/src/Common/TypeSystemHelpers.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; + namespace Internal.TypeSystem { static public class TypeSystemHelpers @@ -19,5 +21,20 @@ static public TypeDesc MakeByRefType(this TypeDesc type) { return type.Context.GetByRefType(type); } + + static public TypeFlags UnderlyingCategory(this TypeDesc type) + { + TypeFlags category = type.Category; + if (type.IsEnum) + { + foreach (var field in type.GetFields()) + { + if (!field.IsStatic) + return field.FieldType.Category; + } + throw new TypeLoadException(); + } + return category; + } } } diff --git a/src/TypeSystem/src/Ecma/EcmaField.cs b/src/TypeSystem/src/Ecma/EcmaField.cs index 8e4eab0dbc4..e25990a6735 100644 --- a/src/TypeSystem/src/Ecma/EcmaField.cs +++ b/src/TypeSystem/src/Ecma/EcmaField.cs @@ -19,6 +19,7 @@ enum FieldFlags BasicMetadataCache = 0x01, Static = 0x02, InitOnly = 0x04, + ThreadStatic = 0x08, }; EcmaType _type; @@ -116,6 +117,9 @@ private FieldFlags InitializeFieldFlags(FieldFlags mask) if ((fieldAttributes & FieldAttributes.InitOnly) != 0) flags |= FieldFlags.InitOnly; + if (HasCustomAttribute("System.ThreadStaticAttribute")) + flags |= FieldFlags.ThreadStatic; + flags |= FieldFlags.BasicMetadataCache; } @@ -142,6 +146,14 @@ public override bool IsStatic } } + public override bool IsThreadStatic + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.ThreadStatic) & FieldFlags.ThreadStatic) != 0; + } + } + public override bool IsInitOnly { get @@ -169,6 +181,19 @@ public override string Name } } + public override bool HasRva + { + get + { + return (FieldDefinition.Attributes & FieldAttributes.HasFieldRVA) != 0; + } + } + + public bool HasCustomAttribute(string customAttributeName) + { + return this.Module.HasCustomAttribute(FieldDefinition.GetCustomAttributes(), customAttributeName); + } + public override string ToString() { return _type.ToString() + "." + this.Name; From 9d171129e112e2d931f1171f7ad32dd4c732d52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 1 Oct 2015 17:03:50 -0700 Subject: [PATCH 2/3] Implement code review feedback --- src/ILToNative/src/Compiler/AsmWriter.cs | 12 +- src/TypeSystem/src/Common/FieldDesc.cs | 18 -- src/TypeSystem/src/Common/FieldLayout.cs | 154 ++++++++++-------- .../src/Common/TypeSystemHelpers.cs | 15 -- src/TypeSystem/src/Ecma/EcmaField.cs | 74 +++++++-- src/TypeSystem/src/Ecma/EcmaType.cs | 14 +- 6 files changed, 165 insertions(+), 122 deletions(-) diff --git a/src/ILToNative/src/Compiler/AsmWriter.cs b/src/ILToNative/src/Compiler/AsmWriter.cs index 9e9bd30f3cf..ae84f56ea54 100644 --- a/src/ILToNative/src/Compiler/AsmWriter.cs +++ b/src/ILToNative/src/Compiler/AsmWriter.cs @@ -279,15 +279,19 @@ void OutputStatics() if (!t.IncludedInCompilation) continue; - if (t.Type.NonGCStaticFieldSize > 0) + var type = t.Type as MetadataType; + if (type == null) + continue; + + if (type.NonGCStaticFieldSize > 0) { Out.Write(".align "); - Out.WriteLine(t.Type.NonGCStaticFieldAlignment); + Out.WriteLine(type.NonGCStaticFieldAlignment); Out.Write("__NonGCStaticBase_"); - Out.Write(GetMangledTypeName(t.Type)); + Out.Write(GetMangledTypeName(type)); Out.WriteLine(":"); Out.Write(".rept "); - Out.WriteLine(t.Type.NonGCStaticFieldSize); + Out.WriteLine(type.NonGCStaticFieldSize); Out.WriteLine(".byte 0"); Out.WriteLine(".endr"); Out.WriteLine(); diff --git a/src/TypeSystem/src/Common/FieldDesc.cs b/src/TypeSystem/src/Common/FieldDesc.cs index 59505796212..1130230c876 100644 --- a/src/TypeSystem/src/Common/FieldDesc.cs +++ b/src/TypeSystem/src/Common/FieldDesc.cs @@ -66,24 +66,6 @@ public abstract bool HasRva get; } - public bool HasGCStaticBase - { - get - { - Debug.Assert(IsStatic); - TypeFlags category = FieldType.UnderlyingCategory(); - switch (category) - { - case TypeFlags.ValueType: - case TypeFlags.Class: - case TypeFlags.Array: - return true; - default: - return false; - } - } - } - public virtual FieldDesc GetTypicalFieldDefinition() { return this; diff --git a/src/TypeSystem/src/Common/FieldLayout.cs b/src/TypeSystem/src/Common/FieldLayout.cs index 4e3bff6732c..93da4f4c387 100644 --- a/src/TypeSystem/src/Common/FieldLayout.cs +++ b/src/TypeSystem/src/Common/FieldLayout.cs @@ -8,14 +8,14 @@ namespace Internal.TypeSystem { - public struct FieldMason + public struct FieldLayoutAlgorithm { private MetadataType _type; private int _numInstanceFields; private ComputedInstanceFieldLayout _computedLayout; - private FieldMason(MetadataType type, int numInstanceFields) + private FieldLayoutAlgorithm(MetadataType type, int numInstanceFields) { _type = type; _computedLayout = new ComputedInstanceFieldLayout(); @@ -139,19 +139,19 @@ out byteCount // At this point all special cases are handled and all inputs validated - FieldMason mason = new FieldMason(type, numInstanceFields); + FieldLayoutAlgorithm algorithm = new FieldLayoutAlgorithm(type, numInstanceFields); if (type.IsExplicitLayout) { - mason.ComputeExplicitFieldLayout(); + algorithm.ComputeExplicitFieldLayout(); } else { // Treat auto layout as sequential for now - mason.ComputeSequentialFieldLayout(); + algorithm.ComputeSequentialFieldLayout(); } - return mason._computedLayout; + return algorithm._computedLayout; } public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(MetadataType type) @@ -166,10 +166,19 @@ public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(Metadata numStaticFields++; } - FieldAndOffset[] computedOffsets = new FieldAndOffset[numStaticFields]; + ComputedStaticFieldLayout result; + result.GcStatics = new StaticsBlock(); + result.NonGcStatics = new StaticsBlock(); + result.ThreadStatics = new StaticsBlock(); + + if (numStaticFields == 0) + { + result.Offsets = null; + return result; + } + + result.Offsets = new FieldAndOffset[numStaticFields]; - int* cumulativeFieldPos = stackalloc int[3]; - int* largestAlignmentRequired = stackalloc int[3]; int index = 0; foreach (var field in type.GetFields()) @@ -177,9 +186,10 @@ public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(Metadata if (!field.IsStatic) continue; - int offsetType = field.IsThreadStatic ? 2 : - field.HasGCStaticBase ? 1 : - 0; + StaticsBlock* block = + field.IsThreadStatic ? &result.ThreadStatics : + field.HasGCStaticBase ? &result.GcStatics : + &result.NonGcStatics; if (field.HasRva) { @@ -188,26 +198,15 @@ public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(Metadata SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, type.Context.Target.DefaultPackingSize); - cumulativeFieldPos[offsetType] = AlignmentHelper.AlignUp(cumulativeFieldPos[offsetType], sizeAndAlignment.Alignment); - computedOffsets[index] = new FieldAndOffset(field, cumulativeFieldPos[offsetType]); - cumulativeFieldPos[offsetType] = checked(cumulativeFieldPos[offsetType] + sizeAndAlignment.Size); + block->Size = AlignmentHelper.AlignUp(block->Size, sizeAndAlignment.Alignment); + result.Offsets[index] = new FieldAndOffset(field, block->Size); + block->Size = checked(block->Size + sizeAndAlignment.Size); - largestAlignmentRequired[offsetType] = Math.Max(largestAlignmentRequired[offsetType], sizeAndAlignment.Alignment); + block->LargestAlignment = Math.Max(block->LargestAlignment, sizeAndAlignment.Alignment); index++; } - ComputedStaticFieldLayout result; - - result.NonGCStaticFieldSize = cumulativeFieldPos[0]; - result.NonGCStaticFieldAlignment = largestAlignmentRequired[0]; - result.GCStaticFieldSize = cumulativeFieldPos[1]; - result.GCStaticFieldAlignment = largestAlignmentRequired[1]; - result.ThreadStaticFieldSize = cumulativeFieldPos[2]; - result.ThreadStaticFieldAlignment = largestAlignmentRequired[2]; - - result.Offsets = computedOffsets; - return result; } @@ -442,25 +441,6 @@ private struct SizeAndAlignment } } - public partial class TypeDesc - { - public virtual int NonGCStaticFieldSize - { - get - { - return 0; - } - } - - public virtual int NonGCStaticFieldAlignment - { - get - { - return 0; - } - } - } - public partial class MetadataType { private class FieldLayoutFlags @@ -471,14 +451,21 @@ private class FieldLayoutFlags public const int HasStaticFieldLayout = 8; } + private class StaticBlockInfo + { + public StaticsBlock NonGcStatics; + public StaticsBlock GcStatics; + public StaticsBlock ThreadStatics; + } + volatile int _fieldLayoutFlags; int _instanceFieldSize; int _instanceByteCount; int _instanceFieldAlignment; - int _nonGCStaticFieldSize; - int _nonGCStaticFieldAlignment; + // Information about various static blocks is rare, so we keep it out of line. + StaticBlockInfo _staticBlockInfo; public bool ContainsPointers { @@ -533,7 +520,7 @@ public int InstanceByteCount } } - public override int NonGCStaticFieldSize + public int NonGCStaticFieldSize { get { @@ -541,11 +528,11 @@ public override int NonGCStaticFieldSize { ComputeStaticFieldLayout(); } - return _nonGCStaticFieldSize; + return _staticBlockInfo == null ? 0 : _staticBlockInfo.NonGcStatics.Size; } } - public override int NonGCStaticFieldAlignment + public int NonGCStaticFieldAlignment { get { @@ -553,13 +540,13 @@ public override int NonGCStaticFieldAlignment { ComputeStaticFieldLayout(); } - return _nonGCStaticFieldAlignment; + return _staticBlockInfo == null ? 0 : _staticBlockInfo.NonGcStatics.LargestAlignment; } } internal void ComputeInstanceFieldLayout() { - var computedLayout = FieldMason.ComputeInstanceFieldLayout(this); + var computedLayout = FieldLayoutAlgorithm.ComputeInstanceFieldLayout(this); _instanceFieldSize = computedLayout.FieldSize; _instanceFieldAlignment = computedLayout.FieldAlignment; @@ -576,16 +563,27 @@ internal void ComputeInstanceFieldLayout() internal void ComputeStaticFieldLayout() { - var computedStaticLayout = FieldMason.ComputeStaticFieldLayout(this); + var computedStaticLayout = FieldLayoutAlgorithm.ComputeStaticFieldLayout(this); - _nonGCStaticFieldSize = computedStaticLayout.NonGCStaticFieldSize; - _nonGCStaticFieldAlignment = computedStaticLayout.NonGCStaticFieldAlignment; - - foreach (var fieldAndOffset in computedStaticLayout.Offsets) + if (computedStaticLayout.Offsets != null) { - Debug.Assert(fieldAndOffset.Field.OwningType == this); - fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); + Debug.Assert(computedStaticLayout.Offsets.Length > 0); + + var staticBlockInfo = new StaticBlockInfo + { + NonGcStatics = computedStaticLayout.NonGcStatics, + GcStatics = computedStaticLayout.GcStatics, + ThreadStatics = computedStaticLayout.ThreadStatics + }; + _staticBlockInfo = staticBlockInfo; + + foreach (var fieldAndOffset in computedStaticLayout.Offsets) + { + Debug.Assert(fieldAndOffset.Field.OwningType == this); + fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); + } } + EnableFieldLayoutFlags(FieldLayoutFlags.HasStaticFieldLayout); } @@ -669,12 +667,29 @@ public int Offset OwningType.ComputeStaticFieldLayout(); else OwningType.ComputeInstanceFieldLayout(); - Debug.Assert(_offset != FieldAndOffset.InvalidOffset); + + if (_offset == FieldAndOffset.InvalidOffset) + { + // Must be a field that doesn't participate in layout (literal?) + throw new BadImageFormatException(); + } } return _offset; } } + public bool HasGCStaticBase + { + get + { + if (!FieldType.IsValueType) + return true; + + MetadataType fieldType = FieldType as MetadataType; + return fieldType != null && fieldType.ContainsPointers; + } + } + internal void InitializeOffset(int offset) { Debug.Assert(_offset == FieldAndOffset.InvalidOffset || _offset == offset); @@ -691,16 +706,17 @@ public struct ComputedInstanceFieldLayout public FieldAndOffset[] Offsets; } - public struct ComputedStaticFieldLayout + public struct StaticsBlock { - public int NonGCStaticFieldSize; - public int NonGCStaticFieldAlignment; - - public int GCStaticFieldSize; - public int GCStaticFieldAlignment; + public int Size; + public int LargestAlignment; + } - public int ThreadStaticFieldSize; - public int ThreadStaticFieldAlignment; + public struct ComputedStaticFieldLayout + { + public StaticsBlock NonGcStatics; + public StaticsBlock GcStatics; + public StaticsBlock ThreadStatics; public FieldAndOffset[] Offsets; } diff --git a/src/TypeSystem/src/Common/TypeSystemHelpers.cs b/src/TypeSystem/src/Common/TypeSystemHelpers.cs index 638a6f86976..bfbea6f1ab4 100644 --- a/src/TypeSystem/src/Common/TypeSystemHelpers.cs +++ b/src/TypeSystem/src/Common/TypeSystemHelpers.cs @@ -21,20 +21,5 @@ static public TypeDesc MakeByRefType(this TypeDesc type) { return type.Context.GetByRefType(type); } - - static public TypeFlags UnderlyingCategory(this TypeDesc type) - { - TypeFlags category = type.Category; - if (type.IsEnum) - { - foreach (var field in type.GetFields()) - { - if (!field.IsStatic) - return field.FieldType.Category; - } - throw new TypeLoadException(); - } - return category; - } } } diff --git a/src/TypeSystem/src/Ecma/EcmaField.cs b/src/TypeSystem/src/Ecma/EcmaField.cs index e25990a6735..cb5ee3ef4c5 100644 --- a/src/TypeSystem/src/Ecma/EcmaField.cs +++ b/src/TypeSystem/src/Ecma/EcmaField.cs @@ -9,24 +9,28 @@ using Internal.TypeSystem; +using Interlocked = System.Threading.Interlocked; + namespace Internal.TypeSystem.Ecma { public sealed class EcmaField : FieldDesc { - [Flags] - enum FieldFlags + static class FieldFlags { - BasicMetadataCache = 0x01, - Static = 0x02, - InitOnly = 0x04, - ThreadStatic = 0x08, + public const int BasicMetadataCache = 0x0001; + public const int Static = 0x0002; + public const int InitOnly = 0x0004; + public const int Literal = 0x0008; + + public const int AttributeMetadataCache = 0x0100; + public const int ThreadStatic = 0x0200; }; EcmaType _type; FieldDefinitionHandle _handle; TypeDesc _fieldType; - FieldFlags _fieldFlags; + volatile int _fieldFlags; internal EcmaField(EcmaType type, FieldDefinitionHandle handle) { @@ -102,9 +106,9 @@ public override TypeDesc FieldType } [MethodImpl(MethodImplOptions.NoInlining)] - private FieldFlags InitializeFieldFlags(FieldFlags mask) + private int InitializeFieldFlags(int mask) { - FieldFlags flags = 0; + int flags = 0; if ((mask & FieldFlags.BasicMetadataCache) != 0) { @@ -117,22 +121,55 @@ private FieldFlags InitializeFieldFlags(FieldFlags mask) if ((fieldAttributes & FieldAttributes.InitOnly) != 0) flags |= FieldFlags.InitOnly; - if (HasCustomAttribute("System.ThreadStaticAttribute")) - flags |= FieldFlags.ThreadStatic; + if ((fieldAttributes & FieldAttributes.Literal) != 0) + flags |= FieldFlags.Literal; flags |= FieldFlags.BasicMetadataCache; } + // Fetching custom attribute based properties is more expensive, so keep that under + // a separate cache that might not be accessed very frequently. + if ((mask & FieldFlags.AttributeMetadataCache) != 0) + { + var fieldDefinition = this.MetadataReader.GetFieldDefinition(_handle); + + foreach (var customAttributeHandle in fieldDefinition.GetCustomAttributes()) + { + var customAttribute = this.MetadataReader.GetCustomAttribute(customAttributeHandle); + var constructorHandle = customAttribute.Constructor; + + var constructor = Module.GetMethod(constructorHandle); + var type = constructor.OwningType; + + switch (type.Name) + { + case "System.ThreadStaticAttribute": + flags |= FieldFlags.ThreadStatic; + break; + } + } + + flags |= FieldFlags.AttributeMetadataCache; + } + Debug.Assert((flags & mask) != 0); + + // Atomically update flags + var originalFlags = _fieldFlags; + while (Interlocked.CompareExchange(ref _fieldFlags, (int)(originalFlags | flags), originalFlags) != originalFlags) + { + originalFlags = _fieldFlags; + } + _fieldFlags |= flags; return flags & mask; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private FieldFlags GetFieldFlags(FieldFlags mask) + private int GetFieldFlags(int mask) { - FieldFlags flags = _fieldFlags & mask; + int flags = _fieldFlags & mask; if (flags != 0) return flags; return InitializeFieldFlags(mask); @@ -150,7 +187,8 @@ public override bool IsThreadStatic { get { - return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.ThreadStatic) & FieldFlags.ThreadStatic) != 0; + return IsStatic && + (GetFieldFlags(FieldFlags.AttributeMetadataCache | FieldFlags.ThreadStatic) & FieldFlags.ThreadStatic) != 0; } } @@ -162,6 +200,14 @@ public override bool IsInitOnly } } + public bool IsLiteral + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.Literal) & FieldFlags.Literal) != 0; + } + } + public FieldAttributes Attributes { get diff --git a/src/TypeSystem/src/Ecma/EcmaType.cs b/src/TypeSystem/src/Ecma/EcmaType.cs index dc8a7988bd8..e8874834d0b 100644 --- a/src/TypeSystem/src/Ecma/EcmaType.cs +++ b/src/TypeSystem/src/Ecma/EcmaType.cs @@ -257,7 +257,11 @@ public override IEnumerable GetFields() { foreach (var handle in _typeDefinition.GetFields()) { - yield return (FieldDesc)this.Module.GetObject(handle); + var field = (EcmaField)this.Module.GetObject(handle); + + // Literal fields are not interesting for codegen purposes + if (!field.IsLiteral) + yield return field; } } @@ -269,7 +273,13 @@ public override FieldDesc GetField(string name) foreach (var handle in _typeDefinition.GetFields()) { if (stringComparer.Equals(metadataReader.GetFieldDefinition(handle).Name, name)) - return (FieldDesc)this.Module.GetObject(handle); + { + var field = (EcmaField)this.Module.GetObject(handle); + + // Literal fields are not interesting for codegen purposes + if (!field.IsLiteral) + return field; + } } return null; From 3981fbb5d5071b1ebd0771065cbc8bd88a9fed49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 1 Oct 2015 17:17:55 -0700 Subject: [PATCH 3/3] Remove leftover unused code --- src/TypeSystem/src/Common/TypeSystemHelpers.cs | 2 -- src/TypeSystem/src/Ecma/EcmaField.cs | 5 ----- 2 files changed, 7 deletions(-) diff --git a/src/TypeSystem/src/Common/TypeSystemHelpers.cs b/src/TypeSystem/src/Common/TypeSystemHelpers.cs index bfbea6f1ab4..9d9770fabc4 100644 --- a/src/TypeSystem/src/Common/TypeSystemHelpers.cs +++ b/src/TypeSystem/src/Common/TypeSystemHelpers.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; - namespace Internal.TypeSystem { static public class TypeSystemHelpers diff --git a/src/TypeSystem/src/Ecma/EcmaField.cs b/src/TypeSystem/src/Ecma/EcmaField.cs index cb5ee3ef4c5..4c88b4f5efa 100644 --- a/src/TypeSystem/src/Ecma/EcmaField.cs +++ b/src/TypeSystem/src/Ecma/EcmaField.cs @@ -235,11 +235,6 @@ public override bool HasRva } } - public bool HasCustomAttribute(string customAttributeName) - { - return this.Module.HasCustomAttribute(FieldDefinition.GetCustomAttributes(), customAttributeName); - } - public override string ToString() { return _type.ToString() + "." + this.Name;