Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ForceInclude Attribute #225

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
1 change: 0 additions & 1 deletion source/Cosmos.IL2CPU/ExceptionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public static void ThrowNotFiniteNumberException(double offendingNumber)
public static void ThrowInvalidCastException() => throw new InvalidCastException();
}

[ForceInclude]
public static class ExceptionHelperRefs
{
public static readonly FieldInfo CurrentExceptionRef = typeof(ExceptionHelper).GetField("CurrentException");
Expand Down
70 changes: 43 additions & 27 deletions source/Cosmos.IL2CPU/ILScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,51 +229,67 @@ public void Execute(MethodBase aStartMethod, IEnumerable<Assembly> plugsAssembli

ILOp.PlugManager = mPlugManager;

// Pull in extra implementations, GC etc.
Queue(VTablesImplRefs.IsInstanceRef, null, "Explicit Entry");
Queue(VTablesImplRefs.SetTypeInfoRef, null, "Explicit Entry");
Queue(VTablesImplRefs.SetInterfaceInfoRef, null, "Explicit Entry");
Queue(VTablesImplRefs.SetMethodInfoRef, null, "Explicit Entry");
Queue(VTablesImplRefs.SetInterfaceMethodInfoRef, null, "Explicit Entry");
Queue(VTablesImplRefs.GetMethodAddressForTypeRef, null, "Explicit Entry");
Queue(VTablesImplRefs.GetMethodAddressForInterfaceTypeRef, null, "Explicit Entry");
Queue(VTablesImplRefs.GetDeclaringTypeOfMethodForTypeRef, null, "Explicit Entry");
Queue(GCImplementationRefs.InitRef, null, "Explicit Entry");
Queue(GCImplementationRefs.IncRootCountRef, null, "Explicit Entry");
Queue(GCImplementationRefs.IncRootCountsInStructRef, null, "Explicit Entry");
Queue(GCImplementationRefs.DecRootCountRef, null, "Explicit Entry");
Queue(GCImplementationRefs.DecRootCountsInStructRef, null, "Explicit Entry");
Queue(GCImplementationRefs.AllocNewObjectRef, null, "Explicit Entry");
// for now, to ease runtime exception throwing
Queue(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", new Type[] { typeof(string) }, null), null, "Explicit Entry");
Queue(typeof(ExceptionHelper).GetMethod("ThrowOverflow", Type.EmptyTypes, null), null, "Explicit Entry");
Queue(typeof(ExceptionHelper).GetMethod("ThrowInvalidOperation", new Type[] { typeof(string) }, null), null, "Explicit Entry");
Queue(typeof(ExceptionHelper).GetMethod("ThrowArgumentOutOfRange", new Type[] { typeof(string) }, null), null, "Explicit Entry");

// register system types:
Queue(typeof(Array), null, "Explicit Entry");
Queue(typeof(Array).Assembly.GetType("System.SZArrayHelper"), null, "Explicit Entry");
Queue(typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First(), null, "Explicit Entry");

Queue(typeof(MulticastDelegate).GetMethod("GetInvocationList"), null, "Explicit Entry");
Queue(ExceptionHelperRefs.CurrentExceptionRef, null, "Explicit Entry");
Queue(ExceptionHelperRefs.ThrowInvalidCastExceptionRef, null, "Explicit Entry");
Queue(ExceptionHelperRefs.ThrowNotFiniteNumberExceptionRef, null, "Explicit Entry");
Queue(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef, null, "Explicit Entry");
Queue(ExceptionHelperRefs.ThrowIndexOutOfRangeException, null, "Explicit Entry");


mAsmblr.ProcessField(typeof(string).GetField("Empty", BindingFlags.Static | BindingFlags.Public));

// Start from entry point of this program
Queue(aStartMethod, null, "Entry Point");

ScanQueue();
ScanForceInclude();
UpdateAssemblies();

Assemble();

mAsmblr.EmitEntrypoint(aStartMethod);
}

/// <summary>
/// Method used to scan the used assemblies for objets with <see cref="ForceIncludeAttribute"/>.
///
/// The used assemblies are a result of the <seealso cref="ScanQueue"/> method.
/// </summary>
private void ScanForceInclude()
{
foreach(var assembly in mUsedAssemblies)
{
foreach (Type type in assembly.GetTypes())
{
// Check if the type has the 'ForceIncludeAttribute' attribute
if (Attribute.IsDefined(type, typeof(ForceIncludeAttribute)))
{
ScanType(type);

// Ensure all public members are queued
foreach(var member in type.GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public))
{
Queue(member, type, "Force Included");
}
}
else
{
// Check each method of the type for the 'ForceIncludeAttribute' attribute
foreach (var method in type.GetRuntimeMethods())
{
if (Attribute.IsDefined(method, typeof(ForceIncludeAttribute)))
{
Queue(method, method.DeclaringType, "Force Included");
}
}
}
}
}

// Execute Scan
ScanQueue();
}

public void QueueMethod(MethodBase method)
{
Queue(method, null, "Explicit entry via QueueMethod");
Expand Down