5 // Jb Evain (jbevain@gmail.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 namespace Mono.Cecil.Cil {
33 public sealed class MethodBody : IVariableDefinitionProvider, IScopeProvider, ICodeVisitable {
35 MethodDefinition m_method;
41 InstructionCollection m_instructions;
42 ExceptionHandlerCollection m_exceptions;
43 VariableDefinitionCollection m_variables;
44 ScopeCollection m_scopes;
46 private CilWorker m_cilWorker;
48 public MethodDefinition Method {
49 get { return m_method; }
53 get { return m_maxStack; }
54 set { m_maxStack = value; }
58 get { return m_codeSize; }
59 set { m_codeSize = value; }
62 public bool InitLocals {
63 get { return m_initLocals; }
64 set { m_initLocals = value; }
67 internal int LocalVarToken {
68 get { return m_localVarToken; }
69 set { m_localVarToken = value; }
72 public CilWorker CilWorker {
74 if (m_cilWorker == null)
75 m_cilWorker = new CilWorker (this);
78 set { m_cilWorker = value; }
81 public InstructionCollection Instructions {
82 get { return m_instructions; }
85 public ExceptionHandlerCollection ExceptionHandlers {
86 get { return m_exceptions; }
89 public VariableDefinitionCollection Variables {
90 get { return m_variables; }
93 public ScopeCollection Scopes {
94 get { return m_scopes; }
97 public MethodBody (MethodDefinition meth)
100 m_instructions = new InstructionCollection (this);
101 m_exceptions = new ExceptionHandlerCollection (this);
102 m_variables = new VariableDefinitionCollection (this);
103 m_scopes = new ScopeCollection (this);
106 internal static Instruction GetInstruction (MethodBody oldBody, MethodBody newBody, Instruction i)
108 int pos = oldBody.Instructions.IndexOf (i);
109 if (pos > -1 && pos < newBody.Instructions.Count)
110 return newBody.Instructions [pos];
112 return newBody.Instructions.Outside;
115 internal static MethodBody Clone (MethodBody body, MethodDefinition parent, ImportContext context)
117 MethodBody nb = new MethodBody (parent);
118 nb.MaxStack = body.MaxStack;
119 nb.InitLocals = body.InitLocals;
120 nb.CodeSize = body.CodeSize;
122 foreach (VariableDefinition var in body.Variables)
123 nb.Variables.Add (new VariableDefinition (
124 context.Import (var.VariableType)));
126 foreach (Instruction instr in body.Instructions) {
127 Instruction ni = new Instruction (instr.OpCode);
129 switch (instr.OpCode.OperandType) {
130 case OperandType.InlineParam :
131 case OperandType.ShortInlineParam :
132 int param = body.Method.Parameters.IndexOf ((ParameterDefinition) instr.Operand);
133 ni.Operand = parent.Parameters [param];
135 case OperandType.InlineVar :
136 case OperandType.ShortInlineVar :
137 int var = body.Variables.IndexOf ((VariableDefinition) instr.Operand);
138 ni.Operand = nb.Variables [var];
140 case OperandType.InlineField :
141 ni.Operand = context.Import ((FieldReference) instr.Operand);
143 case OperandType.InlineMethod :
144 ni.Operand = context.Import ((MethodReference) instr.Operand);
146 case OperandType.InlineType :
147 ni.Operand = context.Import ((TypeReference) instr.Operand);
149 case OperandType.InlineTok :
150 if (instr.Operand is TypeReference)
151 ni.Operand = context.Import ((TypeReference) instr.Operand);
152 else if (instr.Operand is FieldReference)
153 ni.Operand = context.Import ((FieldReference) instr.Operand);
154 else if (instr.Operand is MethodReference)
155 ni.Operand = context.Import ((MethodReference) instr.Operand);
157 case OperandType.ShortInlineBrTarget :
158 case OperandType.InlineBrTarget :
161 ni.Operand = instr.Operand;
165 nb.Instructions.Add (ni);
168 for (int i = 0; i < body.Instructions.Count; i++) {
169 Instruction instr = nb.Instructions [i];
170 if (instr.OpCode.OperandType != OperandType.ShortInlineBrTarget &&
171 instr.OpCode.OperandType != OperandType.InlineBrTarget)
174 instr.Operand = GetInstruction (body, nb, (Instruction) body.Instructions [i].Operand);
177 foreach (ExceptionHandler eh in body.ExceptionHandlers) {
178 ExceptionHandler neh = new ExceptionHandler (eh.Type);
179 neh.TryStart = GetInstruction (body, nb, eh.TryStart);
180 neh.TryEnd = GetInstruction (body, nb, eh.TryEnd);
181 neh.HandlerStart = GetInstruction (body, nb, eh.HandlerStart);
182 neh.HandlerEnd = GetInstruction (body, nb, eh.HandlerEnd);
185 case ExceptionHandlerType.Catch :
186 neh.CatchType = context.Import (eh.CatchType);
188 case ExceptionHandlerType.Filter :
189 neh.FilterStart = GetInstruction (body, nb, eh.FilterStart);
190 neh.FilterEnd = GetInstruction (body, nb, eh.FilterEnd);
194 nb.ExceptionHandlers.Add (neh);
200 public void Simplify ()
202 foreach (Instruction i in this.Instructions) {
203 if (i.OpCode.OpCodeType != OpCodeType.Macro)
206 switch (i.OpCode.Code) {
208 Simplify (i, OpCodes.Ldarg,
209 CodeReader.GetParameter (this, 0));
212 Simplify (i, OpCodes.Ldarg,
213 CodeReader.GetParameter (this, 1));
216 Simplify (i, OpCodes.Ldarg,
217 CodeReader.GetParameter (this, 2));
220 Simplify (i, OpCodes.Ldarg,
221 CodeReader.GetParameter (this, 3));
224 Simplify (i, OpCodes.Ldloc,
225 CodeReader.GetVariable (this, 0));
228 Simplify (i, OpCodes.Ldloc,
229 CodeReader.GetVariable (this, 1));
232 Simplify (i, OpCodes.Ldloc,
233 CodeReader.GetVariable (this, 2));
236 Simplify (i, OpCodes.Ldloc,
237 CodeReader.GetVariable (this, 3));
240 Simplify (i, OpCodes.Stloc,
241 CodeReader.GetVariable (this, 0));
244 Simplify (i, OpCodes.Stloc,
245 CodeReader.GetVariable (this, 1));
248 Simplify (i, OpCodes.Stloc,
249 CodeReader.GetVariable (this, 2));
252 Simplify (i, OpCodes.Stloc,
253 CodeReader.GetVariable (this, 3));
256 i.OpCode = OpCodes.Ldarg;
259 i.OpCode = OpCodes.Ldarga;
262 i.OpCode = OpCodes.Starg;
265 i.OpCode = OpCodes.Ldloc;
268 i.OpCode = OpCodes.Ldloca;
271 i.OpCode = OpCodes.Stloc;
273 case Code.Ldc_I4_M1 :
274 Simplify (i, OpCodes.Ldc_I4, -1);
277 Simplify (i, OpCodes.Ldc_I4, 0);
280 Simplify (i, OpCodes.Ldc_I4, 1);
283 Simplify (i, OpCodes.Ldc_I4, 2);
286 Simplify (i, OpCodes.Ldc_I4, 3);
289 Simplify (i, OpCodes.Ldc_I4, 4);
292 Simplify (i, OpCodes.Ldc_I4, 5);
295 Simplify (i, OpCodes.Ldc_I4, 6);
298 Simplify (i, OpCodes.Ldc_I4, 7);
301 Simplify (i, OpCodes.Ldc_I4, 8);
304 i.OpCode = OpCodes.Ldc_I4;
305 i.Operand = (int) (sbyte) i.Operand;
308 i.OpCode = OpCodes.Br;
310 case Code.Brfalse_S :
311 i.OpCode = OpCodes.Brfalse;
314 i.OpCode = OpCodes.Brtrue;
317 i.OpCode = OpCodes.Beq;
320 i.OpCode = OpCodes.Bge;
323 i.OpCode = OpCodes.Bgt;
326 i.OpCode = OpCodes.Ble;
329 i.OpCode = OpCodes.Blt;
332 i.OpCode = OpCodes.Bne_Un;
335 i.OpCode = OpCodes.Bge_Un;
338 i.OpCode = OpCodes.Bgt_Un;
341 i.OpCode = OpCodes.Ble_Un;
344 i.OpCode = OpCodes.Blt_Un;
347 i.OpCode = OpCodes.Leave;
353 static void Simplify (Instruction i, OpCode op, object operand)
359 public void Accept (ICodeVisitor visitor)
361 visitor.VisitMethodBody (this);
362 m_variables.Accept (visitor);
363 m_instructions.Accept (visitor);
364 m_exceptions.Accept (visitor);
365 m_scopes.Accept (visitor);
367 visitor.TerminateMethodBody (this);