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 if (instr.Operand == body.Method.This)
133 ni.Operand = nb.Method.This;
135 int param = body.Method.Parameters.IndexOf ((ParameterDefinition) instr.Operand);
136 ni.Operand = parent.Parameters [param];
139 case OperandType.InlineVar :
140 case OperandType.ShortInlineVar :
141 int var = body.Variables.IndexOf ((VariableDefinition) instr.Operand);
142 ni.Operand = nb.Variables [var];
144 case OperandType.InlineField :
145 ni.Operand = context.Import ((FieldReference) instr.Operand);
147 case OperandType.InlineMethod :
148 ni.Operand = context.Import ((MethodReference) instr.Operand);
150 case OperandType.InlineType :
151 ni.Operand = context.Import ((TypeReference) instr.Operand);
153 case OperandType.InlineTok :
154 if (instr.Operand is TypeReference)
155 ni.Operand = context.Import ((TypeReference) instr.Operand);
156 else if (instr.Operand is FieldReference)
157 ni.Operand = context.Import ((FieldReference) instr.Operand);
158 else if (instr.Operand is MethodReference)
159 ni.Operand = context.Import ((MethodReference) instr.Operand);
161 case OperandType.ShortInlineBrTarget :
162 case OperandType.InlineBrTarget :
165 ni.Operand = instr.Operand;
169 nb.Instructions.Add (ni);
172 for (int i = 0; i < body.Instructions.Count; i++) {
173 Instruction instr = nb.Instructions [i];
174 if (instr.OpCode.OperandType != OperandType.ShortInlineBrTarget &&
175 instr.OpCode.OperandType != OperandType.InlineBrTarget)
178 instr.Operand = GetInstruction (body, nb, (Instruction) body.Instructions [i].Operand);
181 foreach (ExceptionHandler eh in body.ExceptionHandlers) {
182 ExceptionHandler neh = new ExceptionHandler (eh.Type);
183 neh.TryStart = GetInstruction (body, nb, eh.TryStart);
184 neh.TryEnd = GetInstruction (body, nb, eh.TryEnd);
185 neh.HandlerStart = GetInstruction (body, nb, eh.HandlerStart);
186 neh.HandlerEnd = GetInstruction (body, nb, eh.HandlerEnd);
189 case ExceptionHandlerType.Catch :
190 neh.CatchType = context.Import (eh.CatchType);
192 case ExceptionHandlerType.Filter :
193 neh.FilterStart = GetInstruction (body, nb, eh.FilterStart);
194 neh.FilterEnd = GetInstruction (body, nb, eh.FilterEnd);
198 nb.ExceptionHandlers.Add (neh);
204 public void Simplify ()
206 foreach (Instruction i in this.Instructions) {
207 if (i.OpCode.OpCodeType != OpCodeType.Macro)
210 switch (i.OpCode.Code) {
212 Simplify (i, OpCodes.Ldarg,
213 CodeReader.GetParameter (this, 0));
216 Simplify (i, OpCodes.Ldarg,
217 CodeReader.GetParameter (this, 1));
220 Simplify (i, OpCodes.Ldarg,
221 CodeReader.GetParameter (this, 2));
224 Simplify (i, OpCodes.Ldarg,
225 CodeReader.GetParameter (this, 3));
228 Simplify (i, OpCodes.Ldloc,
229 CodeReader.GetVariable (this, 0));
232 Simplify (i, OpCodes.Ldloc,
233 CodeReader.GetVariable (this, 1));
236 Simplify (i, OpCodes.Ldloc,
237 CodeReader.GetVariable (this, 2));
240 Simplify (i, OpCodes.Ldloc,
241 CodeReader.GetVariable (this, 3));
244 Simplify (i, OpCodes.Stloc,
245 CodeReader.GetVariable (this, 0));
248 Simplify (i, OpCodes.Stloc,
249 CodeReader.GetVariable (this, 1));
252 Simplify (i, OpCodes.Stloc,
253 CodeReader.GetVariable (this, 2));
256 Simplify (i, OpCodes.Stloc,
257 CodeReader.GetVariable (this, 3));
260 i.OpCode = OpCodes.Ldarg;
263 i.OpCode = OpCodes.Ldarga;
266 i.OpCode = OpCodes.Starg;
269 i.OpCode = OpCodes.Ldloc;
272 i.OpCode = OpCodes.Ldloca;
275 i.OpCode = OpCodes.Stloc;
277 case Code.Ldc_I4_M1 :
278 Simplify (i, OpCodes.Ldc_I4, -1);
281 Simplify (i, OpCodes.Ldc_I4, 0);
284 Simplify (i, OpCodes.Ldc_I4, 1);
287 Simplify (i, OpCodes.Ldc_I4, 2);
290 Simplify (i, OpCodes.Ldc_I4, 3);
293 Simplify (i, OpCodes.Ldc_I4, 4);
296 Simplify (i, OpCodes.Ldc_I4, 5);
299 Simplify (i, OpCodes.Ldc_I4, 6);
302 Simplify (i, OpCodes.Ldc_I4, 7);
305 Simplify (i, OpCodes.Ldc_I4, 8);
308 i.OpCode = OpCodes.Ldc_I4;
309 i.Operand = (int) (sbyte) i.Operand;
312 i.OpCode = OpCodes.Br;
314 case Code.Brfalse_S :
315 i.OpCode = OpCodes.Brfalse;
318 i.OpCode = OpCodes.Brtrue;
321 i.OpCode = OpCodes.Beq;
324 i.OpCode = OpCodes.Bge;
327 i.OpCode = OpCodes.Bgt;
330 i.OpCode = OpCodes.Ble;
333 i.OpCode = OpCodes.Blt;
336 i.OpCode = OpCodes.Bne_Un;
339 i.OpCode = OpCodes.Bge_Un;
342 i.OpCode = OpCodes.Bgt_Un;
345 i.OpCode = OpCodes.Ble_Un;
348 i.OpCode = OpCodes.Blt_Un;
351 i.OpCode = OpCodes.Leave;
357 static void Simplify (Instruction i, OpCode op, object operand)
363 public void Accept (ICodeVisitor visitor)
365 visitor.VisitMethodBody (this);
366 m_variables.Accept (visitor);
367 m_instructions.Accept (visitor);
368 m_exceptions.Accept (visitor);
369 m_scopes.Accept (visitor);
371 visitor.TerminateMethodBody (this);