зеркало из https://github.com/DeGsoft/maui-linux.git
93 строки
2.7 KiB
C#
93 строки
2.7 KiB
C#
using Mono.Cecil.Cil;
|
|
using Mono.Cecil.Rocks;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Xamarin.Forms.Build.Tasks
|
|
{
|
|
static class MethodBodyExtensions
|
|
{
|
|
public static void Optimize(this MethodBody self)
|
|
{
|
|
if (self == null)
|
|
throw new ArgumentNullException(nameof(self));
|
|
|
|
self.OptimizeLongs();
|
|
self.OptimizeStLdLoc();
|
|
self.RemoveUnusedLocals();
|
|
self.OptimizeMacros();
|
|
}
|
|
|
|
static void ExpandMacro(Instruction instruction, OpCode opcode, object operand)
|
|
{
|
|
instruction.OpCode = opcode;
|
|
instruction.Operand = operand;
|
|
}
|
|
|
|
//this can be removed if/when https://github.com/jbevain/cecil/pull/307 is released in a nuget we consume
|
|
static void OptimizeLongs(this MethodBody self)
|
|
{
|
|
for (var i = 0; i < self.Instructions.Count; i++) {
|
|
var instruction = self.Instructions[i];
|
|
if (instruction.OpCode.Code != Code.Ldc_I8)
|
|
continue;
|
|
var l = (long)instruction.Operand;
|
|
if (l < int.MinValue || l > int.MaxValue)
|
|
continue;
|
|
ExpandMacro(instruction, OpCodes.Ldc_I4, unchecked((int)l));
|
|
self.Instructions.Insert(++i, Instruction.Create(OpCodes.Conv_I8));
|
|
}
|
|
}
|
|
|
|
static void OptimizeStLdLoc(this MethodBody self)
|
|
{
|
|
var method = self.Method;
|
|
for (var i = 0; i < self.Instructions.Count; i++) {
|
|
var instruction = self.Instructions[i];
|
|
if (instruction.OpCode.Code != Code.Stloc)
|
|
continue;
|
|
if (i + 1 >= self.Instructions.Count)
|
|
continue;
|
|
var next = self.Instructions[i + 1];
|
|
int num = ((VariableDefinition)instruction.Operand).Index;
|
|
var vardef = instruction.Operand;
|
|
if (next.OpCode.Code != Code.Ldloc || num != ((VariableDefinition)next.Operand).Index)
|
|
continue;
|
|
ExpandMacro(instruction, OpCodes.Dup, null);
|
|
ExpandMacro(next, OpCodes.Stloc, vardef);
|
|
}
|
|
}
|
|
|
|
static void RemoveUnusedLocals(this MethodBody self)
|
|
{
|
|
//Count ldloc for each variable
|
|
var ldlocUsed = new List<VariableDefinition>();
|
|
foreach (var instruction in self.Instructions) {
|
|
if (instruction.OpCode.Code != Code.Ldloc)
|
|
continue;
|
|
var varDef = (VariableDefinition)instruction.Operand;
|
|
if (!ldlocUsed.Contains(varDef))
|
|
ldlocUsed.Add(varDef);
|
|
}
|
|
|
|
foreach (var varDef in self.Variables.ToArray()) {
|
|
if (ldlocUsed.Contains(varDef))
|
|
continue;
|
|
|
|
//find the Stloc instruction
|
|
var instruction = (from instr in self.Instructions where instr.OpCode.Code == Code.Stloc && instr.Operand == varDef select instr).First();
|
|
|
|
//remove dup/stloc
|
|
if (instruction.Previous.OpCode.Code != Code.Dup)
|
|
break;
|
|
|
|
self.Instructions.Remove(instruction.Previous);
|
|
self.Instructions.Remove(instruction);
|
|
|
|
//and remove the variable
|
|
self.Variables.Remove(varDef);
|
|
}
|
|
}
|
|
}
|
|
} |