-
Notifications
You must be signed in to change notification settings - Fork 515
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update to new linker custom steps API
- Loading branch information
Showing
13 changed files
with
463 additions
and
209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
tools/dotnet-linker/Steps/ConfigurationAwareMarkHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
using Xamarin.Bundler; | ||
|
||
namespace Xamarin.Linker { | ||
public abstract class ConfigurationAwareMarkHandler : ExceptionalMarkHandler { | ||
protected override void Report (Exception exception) | ||
{ | ||
LinkerConfiguration.Report (context, exception); | ||
} | ||
|
||
protected void Report (List<Exception> exceptions) | ||
{ | ||
LinkerConfiguration.Report (context, exceptions); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using Mono.Linker.Steps; | ||
|
||
namespace Xamarin.Linker.Steps { | ||
// MarkSubStepsDispatcher is abstract, so create a subclass we can instantiate. | ||
// Can be removed when we update to the preview4 linker, which makes MarkSubStepsDispatcher non-abstract. | ||
class DotNetMarkAssemblySubStepDispatcher : MarkSubStepsDispatcher { | ||
public DotNetMarkAssemblySubStepDispatcher (params BaseSubStep[] subSteps) : base (subSteps) | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright 2016 Xamarin Inc. | ||
|
||
using System; | ||
using Mono.Cecil; | ||
using Mono.Tuner; | ||
using Xamarin.Bundler; | ||
|
||
using Xamarin.Tuner; | ||
|
||
using Mono.Linker; | ||
using Mono.Linker.Steps; | ||
|
||
namespace Xamarin.Linker { | ||
|
||
// Similar to ExceptionalSubStep, but this only runs for marked members | ||
// that were registered for handling by the subclass. | ||
public abstract class ExceptionalMarkHandler : IMarkHandler | ||
{ | ||
public abstract void Initialize (LinkContext context, MarkContext markContext); | ||
|
||
protected DerivedLinkContext LinkContext => Configuration.DerivedLinkContext; | ||
|
||
protected LinkContext context { get; set; } | ||
|
||
protected AnnotationStore Annotations => context.Annotations; | ||
protected LinkerConfiguration Configuration => LinkerConfiguration.GetInstance (context); | ||
|
||
protected Profile Profile => Configuration.Profile; | ||
|
||
public void ProcessAssembly (AssemblyDefinition assembly) | ||
{ | ||
try { | ||
Process (assembly); | ||
} catch (Exception e) { | ||
Report (Fail (assembly, e)); | ||
} | ||
} | ||
|
||
public void ProcessType (TypeDefinition type) | ||
{ | ||
try { | ||
Process (type); | ||
} catch (Exception e) { | ||
Report (Fail (type, e)); | ||
} | ||
} | ||
|
||
public void ProcessField (FieldDefinition field) | ||
{ | ||
try { | ||
Process (field); | ||
} catch (Exception e) { | ||
Report (Fail (field, e)); | ||
} | ||
} | ||
|
||
public void ProcessMethod (MethodDefinition method) | ||
{ | ||
try { | ||
Process (method); | ||
} catch (Exception e) { | ||
Report (Fail (method, e)); | ||
} | ||
} | ||
|
||
// state-aware versions to be subclassed | ||
|
||
protected virtual void Process (AssemblyDefinition assembly) | ||
{ | ||
} | ||
|
||
protected virtual void Process (TypeDefinition type) | ||
{ | ||
} | ||
|
||
protected virtual void Process (FieldDefinition field) | ||
{ | ||
} | ||
|
||
protected virtual void Process (MethodDefinition method) | ||
{ | ||
} | ||
|
||
// failure overrides, with defaults | ||
|
||
protected virtual Exception Fail (AssemblyDefinition assembly, Exception e) | ||
{ | ||
return ErrorHelper.CreateError (ErrorCode, e, Errors.MX_ExceptionalSubSteps, Name, assembly?.FullName); | ||
} | ||
|
||
protected virtual Exception Fail (TypeDefinition type, Exception e) | ||
{ | ||
return ErrorHelper.CreateError (ErrorCode | 1, e, Errors.MX_ExceptionalSubSteps, Name, type?.FullName); | ||
} | ||
|
||
protected virtual Exception Fail (FieldDefinition field, Exception e) | ||
{ | ||
return ErrorHelper.CreateError (ErrorCode | 2, e, Errors.MX_ExceptionalSubSteps, Name, field?.FullName); | ||
} | ||
|
||
protected virtual Exception Fail (MethodDefinition method, Exception e) | ||
{ | ||
return ErrorHelper.CreateError (ErrorCode | 3, e, Errors.MX_ExceptionalSubSteps, Name, method?.FullName); | ||
} | ||
protected virtual void Report (Exception e) | ||
{ | ||
throw e; | ||
} | ||
|
||
// abstracts | ||
|
||
protected abstract string Name { get; } | ||
|
||
protected abstract int ErrorCode { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using System; | ||
using System.Linq; | ||
|
||
using Mono.Cecil; | ||
|
||
using Mono.Linker; | ||
using Mono.Linker.Steps; | ||
using Mono.Tuner; | ||
|
||
using Xamarin.Bundler; | ||
|
||
namespace Xamarin.Linker.Steps { | ||
|
||
public class PreserveBlockCodeHandler : ConfigurationAwareMarkHandler { | ||
|
||
protected override string Name { get; } = "Preserve Block Code"; | ||
protected override int ErrorCode { get; } = 2240; | ||
|
||
public override void Initialize (LinkContext context, MarkContext markContext) | ||
{ | ||
this.context = context; | ||
markContext.RegisterMarkTypeAction (ProcessType); | ||
} | ||
|
||
protected override void Process (TypeDefinition type) | ||
{ | ||
/* For the following class: | ||
static internal class SDInnerBlock { | ||
// this field is not preserved by other means, but it must not be linked away | ||
static internal readonly DInnerBlock Handler = Invoke; | ||
[MonoPInvokeCallback (typeof (DInnerBlock))] | ||
static internal void Invoke (IntPtr block, int magic_number) | ||
{ | ||
} | ||
} | ||
We need to make sure the linker doesn't remove the Handler field | ||
and the Invoke method. | ||
*/ | ||
|
||
// First make sure we got the right class | ||
// The type for the field we're looking for is abstract, sealed and nested and contains exactly 1 field. | ||
if (!type.IsAbstract || !type.IsSealed || !type.IsNested) | ||
return; | ||
if (type.Fields.Count != 1) | ||
return; | ||
|
||
// The type is also nested inside ObjCRuntime.Trampolines class) | ||
var nestingType = type.DeclaringType; | ||
if (!nestingType.Is ("ObjCRuntime", "Trampolines")) | ||
return; | ||
|
||
// The class has a readonly field named 'Handler' | ||
var field = type.Fields.Single (); | ||
if (!field.IsInitOnly) | ||
return; | ||
if (field.Name != "Handler") | ||
return; | ||
|
||
// The class has a parameterless 'Invoke' method with a 'MonoPInvokeCallback' attribute | ||
if (!type.HasMethods) | ||
return; | ||
var method = type.Methods.SingleOrDefault (v => { | ||
if (v.Name != "Invoke") | ||
return false; | ||
if (v.Parameters.Count == 0) | ||
return false; | ||
if (!v.HasCustomAttributes) | ||
return false; | ||
if (!v.CustomAttributes.Any (v => v.AttributeType.Name == "MonoPInvokeCallbackAttribute")) | ||
return false; | ||
return true; | ||
}); | ||
|
||
if (method == null) | ||
return; | ||
|
||
// The type was used, so preserve the method and field | ||
context.Annotations.Mark (method); | ||
context.Annotations.Mark (field); | ||
} | ||
} | ||
} |
Oops, something went wrong.