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 number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using Internal.ReadyToRunConstants;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

namespace ILCompiler
{
/// <summary>
/// A compilation group that only contains no methods. Used for creating an R2R image without
/// any method compiled into it. Needed for handling inputbubble scenarios where a dependent
/// assembly should not be R2R'd.
/// </summary>
public class NoMethodsCompilationModuleGroup : ReadyToRunCompilationModuleGroupBase
{
public NoMethodsCompilationModuleGroup(
TypeSystemContext context,
bool isCompositeBuildMode,
bool isInputBubble,
IEnumerable<EcmaModule> compilationModuleSet,
IEnumerable<ModuleDesc> versionBubbleModuleSet,
bool compileGenericDependenciesFromVersionBubbleModuleSet) :
base(context,
isCompositeBuildMode,
isInputBubble,
compilationModuleSet,
versionBubbleModuleSet,
compileGenericDependenciesFromVersionBubbleModuleSet)
{
}

public override bool ContainsMethodBody(MethodDesc method, bool unboxingStub)
{
return false;
}

public override void ApplyProfilerGuidedCompilationRestriction(ProfileDataManager profileGuidedCompileRestriction)
{
return;
}

public override ReadyToRunFlags GetReadyToRunFlags()
{
// Partial by definition.
return ReadyToRunFlags.READYTORUN_FLAG_Partial;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -227,6 +228,7 @@ public sealed class ReadyToRunCodegenCompilation : Compilation
private bool _generateMapFile;

public ReadyToRunSymbolNodeFactory SymbolNodeFactory { get; }
public ReadyToRunCompilationModuleGroupBase CompilationModuleGroup { get; }

internal ReadyToRunCodegenCompilation(
DependencyAnalyzerBase<NodeFactory> dependencyGraph,
Expand Down Expand Up @@ -256,6 +258,7 @@ internal ReadyToRunCodegenCompilation(
SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory);
_corInfoImpls = new ConditionalWeakTable<Thread, CorInfoImpl>();
_inputFiles = inputFiles;
CompilationModuleGroup = (ReadyToRunCompilationModuleGroupBase)nodeFactory.CompilationModuleGroup;

// Generate baseline support specification for InstructionSetSupport. This will prevent usage of the generated
// code if the runtime environment doesn't support the specified instruction set
Expand Down Expand Up @@ -333,9 +336,86 @@ public override void WriteDependencyLog(string outputFileName)
}
}

internal bool IsInheritanceChainLayoutFixedInCurrentVersionBubble(TypeDesc type)
public bool IsLayoutFixedInCurrentVersionBubble(TypeDesc type)
{
// TODO: implement
// Primitive types and enums have fixed layout
if (type.IsPrimitive || type.IsEnum)
{
return true;
}

if (!(type is MetadataType defType))
{
// Non metadata backed types have layout defined in all version bubbles
return true;
}

if (!NodeFactory.CompilationModuleGroup.VersionsWithModule(defType.Module))
{
if (!type.IsValueType)
{
// Eventually, we may respect the non-versionable attribute for reference types too. For now, we are going
// to play it safe and ignore it.
return false;
}

// Valuetypes with non-versionable attribute are candidates for fixed layout. Reject the rest.
return type is MetadataType metadataType && metadataType.IsNonVersionable();
}

// If the above condition passed, check that all instance fields have fixed layout as well. In particular,
// it is important for generic types with non-versionable layout (e.g. Nullable<T>)
foreach (var field in type.GetFields())
{
// Only instance fields matter here
if (field.IsStatic)
continue;

var fieldType = field.FieldType;
if (!fieldType.IsValueType)
continue;

if (!IsLayoutFixedInCurrentVersionBubble(fieldType))
Comment thread
trylek marked this conversation as resolved.
{
return false;
}
}

return true;
}

public bool IsInheritanceChainLayoutFixedInCurrentVersionBubble(TypeDesc type)
{
// This method is not expected to be called for value types
Debug.Assert(!type.IsValueType);

if (type.IsObject)
return true;

if (!IsLayoutFixedInCurrentVersionBubble(type))
{
return false;
}

type = type.BaseType;

if (type != null)
{
// If there are multiple inexact compilation units in the layout of the type, then the exact offset
// of a derived given field is unknown as there may or may not be alignment inserted between a type and its base
if (CompilationModuleGroup.TypeLayoutCompilationUnits(type).HasMultipleInexactCompilationUnits)
return false;

while (!type.IsObject && type != null)
{
if (!IsLayoutFixedInCurrentVersionBubble(type))
{
return false;
}
type = type.BaseType;
}
}

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public sealed class ReadyToRunCodegenCompilationBuilder : CompilationBuilder
private KeyValuePair<string, string>[] _ryujitOptions = Array.Empty<KeyValuePair<string, string>>();
private ILProvider _ilProvider = new ReadyToRunILProvider();

public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group, IEnumerable<string> inputFiles)
public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, ReadyToRunCompilationModuleGroupBase group, IEnumerable<string> inputFiles)
: base(context, group, new CoreRTNameMangler())
{
_inputFiles = inputFiles;
Expand Down
Loading