8313eeb9bcad3024db1a35508a2d903a76032ab1
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / XamlBuild / MethodBodyExtensions.cs
1 using Mono.Cecil.Cil;
2 using Mono.Cecil.Rocks;
3 using System;
4 using System.Linq;
5 using System.Collections.Generic;
6
7 namespace Tizen.NUI.Xaml.Build.Tasks
8 {
9     static class MethodBodyExtensions
10     {
11         public static void Optimize(this MethodBody self)
12         {
13             if (self == null)
14                 throw new ArgumentNullException(nameof(self));
15
16             self.OptimizeLongs();
17             self.OptimizeStLdLoc();
18             self.RemoveUnusedLocals();
19             self.OptimizeMacros();
20         }
21
22         static void ExpandMacro(Instruction instruction, OpCode opcode, object operand)
23         {
24             instruction.OpCode = opcode;
25             instruction.Operand = operand;
26         }
27
28         //this can be removed if/when https://github.com/jbevain/cecil/pull/307 is released in a nuget we consume
29         static void OptimizeLongs(this MethodBody self)
30         {
31             for (var i = 0; i < self.Instructions.Count; i++) {
32                 var instruction = self.Instructions[i];
33                 if (instruction.OpCode.Code != Code.Ldc_I8)
34                     continue;
35                 var l = (long)instruction.Operand;
36                 if (l < int.MinValue || l > int.MaxValue)
37                     continue;
38                 ExpandMacro(instruction, OpCodes.Ldc_I4, unchecked((int)l));
39                 self.Instructions.Insert(++i, Instruction.Create(OpCodes.Conv_I8));
40             }
41         }
42
43         static void OptimizeStLdLoc(this MethodBody self)
44         {
45             var method = self.Method;
46             for (var i = 0; i < self.Instructions.Count; i++) {
47                 var instruction = self.Instructions[i];
48                 if (instruction.OpCode.Code != Code.Stloc)
49                     continue;
50                 if (i + 1 >= self.Instructions.Count)
51                     continue;
52                 var next = self.Instructions[i + 1];
53                 int num = ((VariableDefinition)instruction.Operand).Index;
54                 var vardef = instruction.Operand;
55                 if (next.OpCode.Code != Code.Ldloc || num != ((VariableDefinition)next.Operand).Index)
56                     continue;
57                 ExpandMacro(instruction, OpCodes.Dup, null);
58                 ExpandMacro(next, OpCodes.Stloc, vardef);
59             }
60         }
61
62         static void RemoveUnusedLocals(this MethodBody self)
63         {
64             //Count ldloc for each variable
65             var ldlocUsed = new List<VariableDefinition>();
66             foreach (var instruction in self.Instructions) {
67                 if (instruction.OpCode.Code != Code.Ldloc)
68                     continue;
69                 var varDef = (VariableDefinition)instruction.Operand;
70                 if (!ldlocUsed.Contains(varDef))
71                     ldlocUsed.Add(varDef);
72             }
73
74             foreach (var varDef in self.Variables.ToArray()) {
75                 if (ldlocUsed.Contains(varDef))
76                     continue;
77
78                 //find the Stloc instruction
79                 var instruction = (from instr in self.Instructions where instr.OpCode.Code == Code.Stloc && instr.Operand == varDef select instr).First();
80
81                 //remove dup/stloc
82                 if (instruction.Previous.OpCode.Code != Code.Dup)
83                     break;
84
85                 self.Instructions.Remove(instruction.Previous);
86                 self.Instructions.Remove(instruction);
87
88                 //and remove the variable
89                 self.Variables.Remove(varDef);
90             }
91         }
92     }
93 }