Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
{
if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor)
{
_dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference");
// Mark the GC static base - it contains a pointer to the class constructor, but also info
// about whether the class constructor already executed and it's what is looked at at runtime.
_dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference");
}
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
{
if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field)
{
// This is an instance field. We don't track them right now.
if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name))
return false;
}
else
{
Expand All@@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend
return true;
}

private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName)
{
FieldDesc field = attributeType.GetField(fieldName);
if (field is not null)
{
if (factory.MetadataManager.IsReflectionBlocked(field))
return false;

dependencies.Add(factory.ReflectableField(field), "Custom attribute blob");

return true;
}

// Haven't found it in current type. Check the base type.
TypeDesc baseType = attributeType.BaseType;

if (baseType != null)
return AddDependenciesFromField(dependencies, factory, baseType, fieldName);

// Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
return true;
}

private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
{
EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
return "Field metadata: " + _field.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;

if (preinitManager.IsPreinitialized(type))
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,7 +49,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable method: " + _method.ToString();
return "Method metadata: " + _method.ToString();
}

protected override void OnMarked(NodeFactory factory)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -294,6 +294,11 @@ private void CreateNodeCaches()
return new ReflectableMethodNode(method);
});

_reflectableFields = new NodeCache<FieldDesc, ReflectableFieldNode>(field =>
{
return new ReflectableFieldNode(field);
});

_objectGetTypeFlowDependencies = new NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode>(type =>
{
return new ObjectGetTypeFlowDependenciesNode(type);
Expand DownExpand Up@@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method)
return _reflectableMethods.GetOrAdd(method);
}

private NodeCache<FieldDesc, ReflectableFieldNode> _reflectableFields;
public ReflectableFieldNode ReflectableField(FieldDesc field)
{
return _reflectableFields.GetOrAdd(field);
}

private NodeCache<MetadataType, ObjectGetTypeFlowDependenciesNode> _objectGetTypeFlowDependencies;
internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type)
{
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb
public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager)
{
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
_preinitializationManager = preinitializationManager;
}
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a field that is gettable/settable from reflection.
/// </summary>
public class ReflectableFieldNode : DependencyNodeCore<NodeFactory>
{
private readonly FieldDesc _field;

public ReflectableFieldNode(FieldDesc field)
{
Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)
|| field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType);
_field = field;
}

public FieldDesc Field => _field;

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition()));

DependencyList dependencies = new DependencyList();
factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field);

// No runtime artifacts needed if this is a generic definition or literal field
if (_field.OwningType.IsGenericDefinition || _field.IsLiteral)
{
return dependencies;
}

FieldDesc typicalField = _field.GetTypicalFieldDefinition();
if (typicalField != _field)
{
// Ensure we consistently apply reflectability to all fields sharing the same definition.
// Bases for different instantiations of the field have a conditional dependency on the definition node that
// brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable.
dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field");
}

// Runtime reflection stack needs to see the type handle of the owning type
dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field");

// Root the static base of the type
if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// Infrastructure around static constructors is stashed in the NonGC static base
bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType);

if (_field.HasRva)
{
// No reflection access right now
}
else if (_field.IsThreadStatic)
{
dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field");
}
else if (_field.HasGCStaticBase)
{
dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field");
}
else
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field");
needsNonGcStaticBase = false;
}
Comment on lines +74 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just remove this branch and let the if immediately below do this? It seems to be doing the same thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of a if/else cascade - we only need to add the TypeNonGCStaticsSymbol if there's a class constructor, or the field is non-GC static. There's no quick way to check if a field is non-GC static - one has to ask the "is it RVA/ThreadStatic/GCStatic" questions first.

The best we could do here is change this else block to needsNonGcStaticBase = true; and delete the dependencies.Add line but then the reason string will be wrong.


if (needsNonGcStaticBase)
{
dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context");
}
}

// Runtime reflection stack needs to obtain the type handle of the field
// (but there's no type handles for function pointers)
if (!_field.FieldType.IsFunctionPointer)
dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field");

return dependencies;
}
protected override string GetName(NodeFactory factory)
{
return "Reflectable field: " + _field.ToString();
}

public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool HasDynamicDependencies => false;
public override bool HasConditionalStaticDependencies => false;
public override bool StaticDependenciesAreComputed => true;
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) => null;
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode

public ThreadStaticsNode(MetadataType type, NodeFactory factory)
{
Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen);
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific));
Debug.Assert(!type.IsGenericDefinition);
_type = type;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
// A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type),
// so for enums also include their MethodTable.
dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum");

// Enums are not useful without their literal fields. The literal fields are not referenced
// from anywhere (source code reference to enums compiles to the underlying numerical constants in IL).
foreach (FieldDesc enumField in _type.GetFields())
{
if (enumField.IsLiteral)
{
dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum");
}
}
}

// If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that.
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ public interface IRootingServiceProvider
void AddCompilationRoot(MethodDesc method, string reason, string exportName = null);
void AddCompilationRoot(TypeDesc type, string reason);
void AddReflectionRoot(MethodDesc method, string reason);
void AddReflectionRoot(FieldDesc field, string reason);
void RootThreadStaticBaseForType(TypeDesc type, string reason);
void RootGCStaticBaseForType(TypeDesc type, string reason);
void RootNonGCStaticBaseForType(TypeDesc type, string reason);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -345,6 +345,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated fields.
/// </summary>
public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
MetadataCategory category = GetMetadataCategory(field);

if ((category & MetadataCategory.Description) != 0)
{
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field);
}
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies on a virtual method.
/// </summary>
Expand All@@ -359,6 +372,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of metadata
// (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor
// and property setters)
}

/// <summary>
/// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes.
/// </summary>
Expand All@@ -371,15 +391,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies,
GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type);
}

if ((category & MetadataCategory.RuntimeMapping) != 0)
{
// We're going to generate a mapping table entry for this. Collect dependencies.

// Nothing special is needed for the mapping table (we only emit the MethodTable and we already
// have one, since we got this callback). But check if a child wants to do something extra.
GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type);
}

GetDependenciesDueToEETypePresence(ref dependencies, factory, type);
}

Expand All@@ -390,12 +401,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency
// and property setters)
}

protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime
// mapping for a type.
}

protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)
{
// MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable.
Expand Down
Loading