/// <summary> /// Transform the given body. /// </summary> public void Transform(Dex target, MethodBody body) { foreach (var ins in body.Instructions) { switch (ins.Code) { case RCode.Invoke_direct: case RCode.Invoke_virtual: case RCode.Invoke_interface: MethodDefinition method; if (((MethodReference)ins.Operand).TryResolve(target, out method)) { if (method.Owner.IsInterface) { ins.Code = RCode.Invoke_interface; } else if (method.IsDirect) { ins.Code = RCode.Invoke_direct; } else { ins.Code = RCode.Invoke_virtual; } } break; } } }
/// <summary> /// Default ctor /// </summary> public BranchReRouter(MethodBody body) { List<Instruction> list = null; // Record instructions with branch targets foreach (var inst in body.Instructions) { switch (inst.Code) { case RCode.Goto: case RCode.Leave: case RCode.If_eq: case RCode.If_ne: case RCode.If_lt: case RCode.If_ge: case RCode.If_gt: case RCode.If_le: case RCode.If_eqz: case RCode.If_nez: case RCode.If_ltz: case RCode.If_gez: case RCode.If_gtz: case RCode.If_lez: case RCode.Packed_switch: case RCode.Sparse_switch: list = list ?? new List<Instruction>(); list.Add(inst); break; } } branches = list; exceptionHandlers = body.Exceptions.Any() ? body.Exceptions.ToArray() : null; }
/// <summary> /// Replace all references to oldRegister with newRegister in the given instruction set. /// </summary> public void ReplaceRegisterWith(Register oldRegister, Register newRegister, MethodBody body) { var oldRegister2 = (oldRegister.Type == RType.Wide) ? body.GetNext(oldRegister) : null; var newRegister2 = (newRegister.Type == RType.Wide) ? body.GetNext(newRegister) : null; if (oldRegister.IsKeepWithNext != newRegister.IsKeepWithNext) throw new ArgumentException("New register has different keep-with-next value"); HashSet<Instruction> list; if (map.TryGetValue(oldRegister, out list)) { list.ForEach(x => x.ReplaceRegisterWith(oldRegister, newRegister)); // Update newRegister AddRange(newRegister, list); } if (oldRegister2 != null) { if (map.TryGetValue(oldRegister2, out list)) { list.ForEach(x => x.ReplaceRegisterWith(oldRegister2, newRegister2)); // Update newRegister2 AddRange(newRegister2, list); } } }
/// <summary> /// Transform the given body. /// </summary> private static void TransformTempToVariable(MethodBody body, List<BasicBlock> basicBlocks) { body.Instructions.UpdateIndexCache(); var allTempRegisterRanges = CollectTempRegisterUsageRanges(basicBlocks).Values.ToList(); foreach (var iterator in basicBlocks) { var block = iterator; // Collect all register ranges that fit completly within this block and are used exactly 2 times var registerRanges = allTempRegisterRanges.Where(x => (x.InstructionCount == 2) && x.ContainsExactlyOne(block)).ToList(); foreach (var range in registerRanges) { var firstIns = range.Range.First; var lastIns = range.Range.Last; if (!lastIns.Code.IsMove()) continue; var reg = range.Register; if (lastIns.Registers[1] != reg) continue; var varReg = lastIns.Registers[0]; if (varReg.Category != RCategory.Variable) continue; // Replace firstIns.ReplaceRegisterWith(reg, varReg); lastIns.ConvertToNop(); } } }
private static IEnumerable<IRLTransformation> GetTransformations(Dex target, MethodBody body) { foreach (var transformation in optimizations1) { transformation.Transform(target, body); yield return transformation; } var noopRemove = new NopRemoveTransformation(); noopRemove.Transform(target, body); yield return noopRemove; bool hasChanges = true; while (hasChanges) { hasChanges = false; foreach (var transformation in incrementalOptimizations) { bool changed = transformation.Transform(target, body); if (changed) noopRemove.Transform(target, body); hasChanges = changed || hasChanges; yield return transformation; } } foreach (var transformation in optimizations2) { transformation.Transform(target, body); yield return transformation; } }
public bool Transform(Dex target, MethodBody body) { #if DEBUG //return; #endif return DoOptimization(body); }
static void AssertOpCodeSequence (OpCode [] expected, MethodBody body) { var opcodes = body.Instructions.Select (i => i.OpCode).ToArray (); Assert.AreEqual (expected.Length, opcodes.Length); for (int i = 0; i < opcodes.Length; i++) Assert.AreEqual (expected [i], opcodes [i]); }
public void InnerProcess() { body = Method.Body; body.SimplifyMacros(); InjectStopwatch(); HandleReturns(); body.InitLocals = true; body.OptimizeMacros(); }
/// <summary> /// Transform the given body. /// </summary> public void Transform(Dex target, MethodBody body) { var basicBlocks = BasicBlock.Find(body); var registerCount = body.Registers.Count(); if (registerCount > MaxRegisters) return; Dictionary<Instruction, ConstantKey> allConstInstructions; CollectReadOnlyConstInstructions(body, out allConstInstructions); RegisterUsageMap registerUsageMap = null; foreach (var block in basicBlocks) { // Select all const instructions that have a next instruction in the block. var list = block.Instructions.ToList(); var isLargeBlock = list.Count > LargeBlockSize; if (isLargeBlock) continue; var constInstructionKeys = list.Where(x => allConstInstructions.ContainsKey(x)).Select(x => allConstInstructions[x]).ToList(); // Select all const instructions where the next instruction is a move. while (constInstructionKeys.Count > 0) { // Take the first instruction var insKey = constInstructionKeys[0]; constInstructionKeys.RemoveAt(0); // Get the register var reg = insKey.Instruction.Registers[0]; // Are there other const instructions of the same type and the same operand? var sameConstInstructions = constInstructionKeys.Where(x => x.Equals(insKey)).ToList(); if (sameConstInstructions.Count == 0) continue; if (sameConstInstructions.Count < 4) continue; // It is now save to use the register for all const operations foreach (var other in sameConstInstructions) { // Replace all register uses var otherReg = other.Instruction.Registers[0]; // Find usages registerUsageMap = registerUsageMap ?? new RegisterUsageMap(body.Instructions); registerUsageMap.ReplaceRegisterWith(otherReg, reg, body); // Remove const constInstructionKeys.Remove(other); allConstInstructions.Remove(other.Instruction); // Change const to nop which will be removed later other.Instruction.ConvertToNop(); } } } }
public ControlFlowGraph2(MethodBody body) { _body = body; _basicBlocks = new ControlFlowGraph(body).ToList(); _entries = _basicBlocks.ToDictionary(b => b.Entry, b => b); _exits = _basicBlocks.ToDictionary(b => b.Exit, b => b); _entryInstructions = _basicBlocks.Select(b => b.Entry).ToList(); IncludeExceptionHandlers(body); }
public bool Transform(Dex target, MethodBody body) { bool hasChanges = false; var registerUsage = new RegisterUsageMap2(body); hasChanges = InlineIntConstsIntoBinOp(registerUsage); return hasChanges; }
/// <summary> /// Transform the given body. /// </summary> public bool Transform(Dex target, MethodBody body) { bool hasChanges = false; // Find all "const" instructions and record register usage var allConstInstructions = new List<Instruction>(); var registerUsage = new Dictionary<Register, List<Instruction>>(); CollectInstructionInformation(body, allConstInstructions, registerUsage); // Find all basic blocks var basicBlocks = BasicBlock.Find(body); // Go over each block foreach (var iterator in basicBlocks) { var block = iterator; // Select all const instructions where the next instruction is a move. foreach (var ins in allConstInstructions) { var r = ins.Registers[0]; // Only optimize const instructions to temp registers if (r.Category != RCategory.Temp) continue; // Get all instructions using this register var all = registerUsage[r]; if ((all.Count != 2) || (all[0] != ins)) continue; var next = all[1]; // Opcode must match if (next.Code != ConstToMove(ins.Code)) continue; // Register must match if (next.Registers[1] != r) continue; // The following are the most expensive, so only test them if we have to. // Only optimize is instruction is in current block if (!block.Contains(ins)) continue; // Next must be in same basic block if (!block.Contains(next)) continue; // We found a replacement r = next.Registers[0]; ins.Registers[0] = r; next.ConvertToNop(); hasChanges = true; } } return hasChanges; }
public MethodBody ReadMethodBody (MethodDefinition method) { this.method = method; this.body = new MethodBody (method); reader.context = method; ReadMethodBody (); return this.body; }
public void Read(MethodBody body, InstructionMapper mapper) { var method_token = body.Method.MetadataToken; PdbFunction function; if (!functions.TryGetValue (method_token.ToUInt32 (), out function)) return; ReadSequencePoints (function, mapper); ReadScopeAndLocals (function.scopes, null, body, mapper); }
public void Read(MethodBody body, InstructionMapper mapper) { var method_token = body.Method.MetadataToken; var entry = symbol_file.GetMethodByToken (method_token.ToInt32 ()); if (entry == null) return; var scopes = ReadScopes (entry, body, mapper); ReadLineNumbers (entry, mapper); ReadLocalVariables (entry, body, scopes); }
public VariableDefinition InjectStopwatch(MethodBody body, int index) { // inject as variable var stopwatchVar = new VariableDefinition("methodTimerStopwatch", StopwatchType); body.Variables.Add(stopwatchVar); body.Insert(index, new List<Instruction>(new[] { Instruction.Create(OpCodes.Call, StartNewMethod), Instruction.Create(OpCodes.Stloc, stopwatchVar) })); return stopwatchVar; }
public bool Transform(Dex target, MethodBody body) { bool hasChanges = false; var graph = new ControlFlowGraph2(body); var registerUsage = new RegisterUsageMap2(graph); hasChanges = EliminateRegisterAssigments(registerUsage); return hasChanges; }
public MSILDisassembler(MethodBody body) { MethodBody = body; Section section = Section.GetSectionByRva(body.Method._netheader._assembly, body.Method.RVA); _ilOffset = new OffsetConverter(section).RvaToFileOffset(body.Method.RVA) + (uint)body.HeaderSize; _reader = section.ParentAssembly._peImage.Reader; TokenResolver = new MetaDataTokenResolver(body.Method._netheader); }
/// <summary> /// Find all instructions that are "const" and have a destination register that is never assigned to. /// </summary> private static void CollectReadOnlyConstInstructions(MethodBody body, out Dictionary<Instruction, ConstantKey> constInstructions) { // Find all const instructions constInstructions = body.Instructions .Where(ins => ins.Code.IsConst() && !ins.Registers[0].PreventOptimization) .ToDictionary(ins => ins, ins => new ConstantKey(ins)); if (constInstructions.Count == 0) return; // Select all registers used by the const instructions var constRegs = new Dictionary<Register, Instruction>(); var toRemove = new HashSet<Instruction>(); foreach (var ins in constInstructions.Keys) { var reg = ins.Registers[0]; if (constRegs.ContainsKey(reg)) { // Oops, duplicate register, remove this one toRemove.Add(ins); toRemove.Add(constRegs[reg]); } else { // Add it constRegs[reg] = ins; } } foreach (var ins in toRemove) { constInstructions.Remove(ins); constRegs.Remove(ins.Registers[0]); } foreach (var ins in body.Instructions) { if (constInstructions.ContainsKey(ins)) continue; var insRegs = ins.Registers; for (var k = 0; k < insRegs.Count; k++) { var reg = insRegs[k]; Instruction constInst; if (constRegs.TryGetValue(reg, out constInst)) { if (ins.IsDestinationRegister(k)) { // Register is a destination in another instruction, the constInst is not readonly. constInstructions.Remove(constInst); constRegs.Remove(reg); } } } } }
public void Execute() { moduleWeaver.LogInfo("\t\t" + propertyData.PropertyDefinition.Name); var property = propertyData.PropertyDefinition; setMethodBody = property.SetMethod.Body; instructions = property.SetMethod.Body.Instructions; foreach (var instruction in GetInstructions()) { Inject(instruction); } }
public bool Transform(Dex target, MethodBody body) { bool hasChanges = false; #if DEBUG //return; #endif var instructions = body.Instructions; var hasNops = instructions.Any(x => x.Code == RCode.Nop); if (!hasNops) return false; var rerouter = new BranchReRouter(body); var i = 0; while (i < instructions.Count) { var inst = instructions[i]; if (inst.Code != RCode.Nop) { i++; continue; } if (body.Exceptions.Count > 0) { foreach (var ex in body.Exceptions.Where(x => x.TryEnd == inst).ToList()) { var exTryEnd = ex.TryEnd; if (exTryEnd.Index > ex.TryStart.Index) exTryEnd = exTryEnd.Previous; if (exTryEnd == ex.TryStart) { // empty exception handler -- remove. body.Exceptions.Remove(ex); } else { ex.TryEnd = exTryEnd; } } } if (i < instructions.Count - 1) { var next = instructions[i + 1]; rerouter.Reroute(inst, next); } instructions.RemoveAt(i); hasChanges = true; } return hasChanges; }
/// <summary> /// Transform the given body. /// </summary> public void Transform(Dex target, MethodBody body) { // Find all basic blocks var basicBlocks = BasicBlock.Find(body); // Replace temp with variable registers with possible. TransformTempToVariable(body, basicBlocks); // Share registers in block only TransformInBlock(body, basicBlocks); // Share register across blocks TransformCrossBlock(body, basicBlocks); }
public void Execute() { moduleWeaver.LogDebug("\t\t" + propertyData.PropertyDefinition.Name); var property = propertyData.PropertyDefinition; setMethodBody = property.SetMethod.Body; instructions = property.SetMethod.Body.Instructions; var indexes = GetIndexes(); indexes.Reverse(); foreach (var index in indexes) { InjectAtIndex(index); } }
/// <summary> /// Transform the given body. /// </summary> private static void TransformCrossBlock(MethodBody body, ICollection<BasicBlock> basicBlocks) { // Find all basic blocks if (basicBlocks.Count <= 1) return; // No need for this transformation var availableShortRegisters = new List<Register>(); // List of register available from previous blocks var availableWideRegisters = new List<Register>(); // List of register available from previous blocks var allTempRegisterRanges = CollectTempRegisterUsageRanges(basicBlocks) .Values .Where(x => x.Register.KeepWith != RFlags.KeepWithPrev) .ToList(); foreach (var iterator in basicBlocks) { var block = iterator; // Collect all register ranges that fit completly within this block var registerRanges = allTempRegisterRanges.Where(x => x.IsRegisterAssignedInFirstInstruction && block.Contains(x.Range)).ToList(); // For each register, look for an available to use instead foreach (var range in registerRanges) { // Validate the range if (!block.ContainsEntireRange(range.Range)) { throw new CompilerException("Usage range falls outside block."); } var r = range.Register; var availableList = r.KeepWith == RFlags.KeepWithNext ? availableWideRegisters : availableShortRegisters; var replacement = availableList.FirstOrDefault(x => r.Type == x.Type); if (replacement != null) { // We can replace r with the replacement we found. range.ReplaceRegisterWith(r, replacement, body); // Replacement is no longer available within this block availableList.Remove(replacement); } } // Make all registers available to following blocks foreach (var range in registerRanges) { var r = range.Register; var availableList = r.KeepWith == RFlags.KeepWithNext ? availableWideRegisters : availableShortRegisters; if (!availableList.Contains(r)) availableList.Add(r); } } }
public bool Transform(Dex target, MethodBody body) { foreach (var ins in body.Instructions) { if (ins.Code == RCode.Check_cast) { var typeReference = (TypeReference) ins.Operand; if(typeReference.Descriptor == "Ljava/lang/Object;") ins.ConvertToNop(); } } return false; }
protected ILMethodBodyRewriter(IMetadataHost host, MethodBody methodBody, ILGenerator generator) { Contract.Requires(host != null); Contract.Requires(methodBody != null); Contract.Requires(generator != null); Contract.Requires(methodBody != Dummy.MethodBody); this.host = host; this.methodBody = methodBody; this.generator = generator; // Make a label for each branch target this.offset2Label = ILMethodBodyRewriter.RecordBranchTargets(this.methodBody.Operations); //Record all offsets that appear as part of an exception handler this.offsetsUsedInExceptionInformation = ILMethodBodyRewriter.RecordExceptionHandlerOffsets(this.methodBody.OperationExceptionInformation); }
static void WriteExceptionHandlers(TextWriter writer, MethodBody body) { if (!body.HasExceptionHandlers) return; foreach (var handler in body.ExceptionHandlers) { writer.Write ("\t"); writer.WriteLine (".try {0} to {1} {2} handler {3} to {4}", FormatLabel (handler.TryStart), FormatLabel (handler.TryEnd), FormatHandlerType (handler), FormatLabel (handler.HandlerStart), FormatLabel (handler.HandlerEnd)); } }
public void AddVariableIndex() { var object_ref = new TypeReference ("System", "Object", null, null, false); var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); var body = new MethodBody (method); var x = new VariableDefinition ("x", object_ref); var y = new VariableDefinition ("y", object_ref); body.Variables.Add (x); body.Variables.Add (y); Assert.AreEqual (0, x.Index); Assert.AreEqual (1, y.Index); }
/// <summary> /// Transform the given body towards Dex compilation. /// <returns> /// Returns the name of the last applied tranformation, or null on full processing. /// </returns> /// </summary> internal static string Transform(Dex target, MethodBody body, int stopAfterSteps = int.MaxValue) { if (stopAfterSteps == 0) return "(no proccessing)"; int stepCount = 0; foreach (var applied in GetTransformations(target, body)) { if (++stepCount > stopAfterSteps) { return applied.GetType().Name; } } return null; }
public void Execute() { logger.LogMessage("\t\t" + propertyData.PropertyDefinition.Name); var property = propertyData.PropertyDefinition; setMethodBody = property.SetMethod.Body; instructions = property.SetMethod.Body.Instructions; logger.LogMessage("\t\t\tCheckForEquality=" + propertyData.CheckForEquality); var indexes = GetIndexes(); indexes.Reverse(); foreach (var index in indexes) { InjectAtIndex(index); } }
public void GetMethodBody_Pinvoke() { MethodBody mb = typeof(MethodInfoTest).GetMethod("dllImportMethod").GetMethodBody(); Assert.IsNull(mb); }
static void ProcessMethod(MethodDefinition method, HashSet <TypeReference> typeset) { // this is needed in case we return an enum, a struct or something mapped // to p/invoke (i.e. no ctor called). We also need to check for arrays. TypeReference t = method.ReturnType; AddType(typeset, t); if (method.HasParameters) { // an "out" from a p/invoke must be flagged foreach (ParameterDefinition parameter in method.Parameters) { // we don't want the reference (&) on the type t = parameter.ParameterType.GetElementType(); AddType(typeset, t); } } if (!method.HasBody) { return; } MethodBody body = method.Body; if (body.HasVariables) { // add every type of variables we use foreach (VariableDefinition variable in body.Variables) { t = variable.VariableType; AddType(typeset, t); } } // add every type we create or refer to (e.g. loading fields from an enum) foreach (Instruction ins in body.Instructions) { if (ins.Operand == null) { continue; } t = ins.Operand as TypeReference; if (t == null) { MethodReference m = ins.Operand as MethodReference; if (m != null) { t = m.DeclaringType; GenericInstanceType generic = (t as GenericInstanceType); if (generic != null) { t = generic.GetElementType(); } } else { FieldReference f = ins.Operand as FieldReference; if (f != null) { t = f.DeclaringType; } } } if (t != null) { AddType(typeset, t); } } }
public static void OptimizeMacros(this MethodBody self) { if (self == null) { throw new ArgumentNullException("self"); } var method = self.Method; foreach (var instruction in self.Instructions) { int index; switch (instruction.OpCode.Code) { case Code.Ldarg: index = ((ParameterDefinition)instruction.Operand).Index; if (index == -1 && instruction.Operand == self.ThisParameter) { index = 0; } else if (method.HasThis) { index++; } switch (index) { case 0: MakeMacro(instruction, OpCodes.Ldarg_0); break; case 1: MakeMacro(instruction, OpCodes.Ldarg_1); break; case 2: MakeMacro(instruction, OpCodes.Ldarg_2); break; case 3: MakeMacro(instruction, OpCodes.Ldarg_3); break; default: if (index < 256) { ExpandMacro(instruction, OpCodes.Ldarg_S, instruction.Operand); } break; } break; case Code.Ldloc: index = ((VariableDefinition)instruction.Operand).Index; switch (index) { case 0: MakeMacro(instruction, OpCodes.Ldloc_0); break; case 1: MakeMacro(instruction, OpCodes.Ldloc_1); break; case 2: MakeMacro(instruction, OpCodes.Ldloc_2); break; case 3: MakeMacro(instruction, OpCodes.Ldloc_3); break; default: if (index < 256) { ExpandMacro(instruction, OpCodes.Ldloc_S, instruction.Operand); } break; } break; case Code.Stloc: index = ((VariableDefinition)instruction.Operand).Index; switch (index) { case 0: MakeMacro(instruction, OpCodes.Stloc_0); break; case 1: MakeMacro(instruction, OpCodes.Stloc_1); break; case 2: MakeMacro(instruction, OpCodes.Stloc_2); break; case 3: MakeMacro(instruction, OpCodes.Stloc_3); break; default: if (index < 256) { ExpandMacro(instruction, OpCodes.Stloc_S, instruction.Operand); } break; } break; case Code.Ldarga: index = ((ParameterDefinition)instruction.Operand).Index; if (index == -1 && instruction.Operand == self.ThisParameter) { index = 0; } else if (method.HasThis) { index++; } if (index < 256) { ExpandMacro(instruction, OpCodes.Ldarga_S, instruction.Operand); } break; case Code.Ldloca: if (((VariableDefinition)instruction.Operand).Index < 256) { ExpandMacro(instruction, OpCodes.Ldloca_S, instruction.Operand); } break; case Code.Ldc_I4: int i = (int)instruction.Operand; switch (i) { case -1: MakeMacro(instruction, OpCodes.Ldc_I4_M1); break; case 0: MakeMacro(instruction, OpCodes.Ldc_I4_0); break; case 1: MakeMacro(instruction, OpCodes.Ldc_I4_1); break; case 2: MakeMacro(instruction, OpCodes.Ldc_I4_2); break; case 3: MakeMacro(instruction, OpCodes.Ldc_I4_3); break; case 4: MakeMacro(instruction, OpCodes.Ldc_I4_4); break; case 5: MakeMacro(instruction, OpCodes.Ldc_I4_5); break; case 6: MakeMacro(instruction, OpCodes.Ldc_I4_6); break; case 7: MakeMacro(instruction, OpCodes.Ldc_I4_7); break; case 8: MakeMacro(instruction, OpCodes.Ldc_I4_8); break; default: if (i >= -128 && i < 128) { ExpandMacro(instruction, OpCodes.Ldc_I4_S, (sbyte)i); } break; } break; } } OptimizeBranches(self); }
public InstructionValidator(MethodBody methodBody, Instruction instruction) { this.instruction = instruction; this.methodBody = methodBody; }
private void PushUnknownAndWarnAboutInvalidIL(Stack <StackSlot> stack, MethodBody methodBody, int offset) { WarnAboutInvalidILInMethod(methodBody, offset); PushUnknown(stack); }
private static void EmitStringArrayEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il, GeneratedVariableIdentifier generatedPtrVar) { if (generatedPtrVar == null) { throw new ArgumentNullException(nameof(generatedPtrVar)); } // Note: only works for string vectors (1d arrays). // We do not (and will probably never) support 2d or higher string arrays var free = wrapper.Module.ImportReference(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringArrayPtr")); // FreeStringArrayPtr(string_array_ptr, string_array.Length) // load string_array_ptr il.Emit(OpCodes.Ldloc, generatedPtrVar.Definition.Index); // load string_array.Length il.Emit(OpCodes.Ldarg, parameter.Index); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); // call FreeStringArrayPtr il.Emit(OpCodes.Call, free); }
public Tests() { this.MainClassType = Type.GetType($"{@namespace}.{mainclass},{@namespace}"); this.MainMethod = this.MainClassType.GetMethod("Main", new[] { typeof(string[]) }); this.MainMethodBody = this.MainMethod.GetMethodBody(); }
static void EmitStringEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il) { var p = parameter.ParameterType; var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringPtr")); // FreeStringPtr(ptr) var variable_name = parameter.Name + "_string_ptr"; var v = body.Variables.First(m => m.Name == variable_name); il.Emit(OpCodes.Ldloc, v.Index); il.Emit(OpCodes.Call, free); }
public void GetMethodBody_Runtime() { MethodBody mb = typeof(AsyncCallback).GetMethod("Invoke").GetMethodBody(); Assert.IsNull(mb); }
protected virtual void WarnAboutInvalidILInMethod(MethodBody method, int ilOffset) { }
protected override bool MatchesPredicate(MethodBody body, int instructionIndex) { return(!isVisitedMap[body.Instructions[instructionIndex]] && !IsWithinExceptionHandler(body.ExceptionHandlers, body.Instructions[instructionIndex])); }
static void EmitStringArrayEpilogue(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il) { // Note: only works for string vectors (1d arrays). // We do not (and will probably never) support 2d or higher string arrays var p = parameter.ParameterType; var free = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "FreeStringArrayPtr")); // FreeStringArrayPtr(string_array_ptr, string_array.Length) var variable_name = parameter.Name + "_string_array_ptr"; var v = body.Variables.First(m => m.Name == variable_name); // load string_array_ptr il.Emit(OpCodes.Ldloc, v.Index); // load string_array.Length il.Emit(OpCodes.Ldarg, parameter.Index); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); // call FreeStringArrayPtr il.Emit(OpCodes.Call, free); }
public MethodEditor(MethodDefinition method) { _body = method.Body; _il = method.Body.GetILProcessor(); }
public static void SimplifyMacros(MethodBody self) { if (self == null) { throw new ArgumentNullException("self"); } foreach (Instruction instruction in self.Instructions) { if (instruction.OpCode.OpCodeType != OpCodeType.Macro) { continue; } switch (instruction.OpCode.Code) { case Code.Ldarg_0: ExpandMacro(instruction, OpCodes.Ldarg, GetParameter(self, 0)); break; case Code.Ldarg_1: ExpandMacro(instruction, OpCodes.Ldarg, GetParameter(self, 1)); break; case Code.Ldarg_2: ExpandMacro(instruction, OpCodes.Ldarg, GetParameter(self, 2)); break; case Code.Ldarg_3: ExpandMacro(instruction, OpCodes.Ldarg, GetParameter(self, 3)); break; case Code.Ldloc_0: ExpandMacro(instruction, OpCodes.Ldloc, self.Variables [0]); break; case Code.Ldloc_1: ExpandMacro(instruction, OpCodes.Ldloc, self.Variables [1]); break; case Code.Ldloc_2: ExpandMacro(instruction, OpCodes.Ldloc, self.Variables [2]); break; case Code.Ldloc_3: ExpandMacro(instruction, OpCodes.Ldloc, self.Variables [3]); break; case Code.Stloc_0: ExpandMacro(instruction, OpCodes.Stloc, self.Variables [0]); break; case Code.Stloc_1: ExpandMacro(instruction, OpCodes.Stloc, self.Variables [1]); break; case Code.Stloc_2: ExpandMacro(instruction, OpCodes.Stloc, self.Variables [2]); break; case Code.Stloc_3: ExpandMacro(instruction, OpCodes.Stloc, self.Variables [3]); break; case Code.Ldarg_S: instruction.OpCode = OpCodes.Ldarg; break; case Code.Ldarga_S: instruction.OpCode = OpCodes.Ldarga; break; case Code.Starg_S: instruction.OpCode = OpCodes.Starg; break; case Code.Ldloc_S: instruction.OpCode = OpCodes.Ldloc; break; case Code.Ldloca_S: instruction.OpCode = OpCodes.Ldloca; break; case Code.Stloc_S: instruction.OpCode = OpCodes.Stloc; break; case Code.Ldc_I4_M1: ExpandMacro(instruction, OpCodes.Ldc_I4, -1); break; case Code.Ldc_I4_0: ExpandMacro(instruction, OpCodes.Ldc_I4, 0); break; case Code.Ldc_I4_1: ExpandMacro(instruction, OpCodes.Ldc_I4, 1); break; case Code.Ldc_I4_2: ExpandMacro(instruction, OpCodes.Ldc_I4, 2); break; case Code.Ldc_I4_3: ExpandMacro(instruction, OpCodes.Ldc_I4, 3); break; case Code.Ldc_I4_4: ExpandMacro(instruction, OpCodes.Ldc_I4, 4); break; case Code.Ldc_I4_5: ExpandMacro(instruction, OpCodes.Ldc_I4, 5); break; case Code.Ldc_I4_6: ExpandMacro(instruction, OpCodes.Ldc_I4, 6); break; case Code.Ldc_I4_7: ExpandMacro(instruction, OpCodes.Ldc_I4, 7); break; case Code.Ldc_I4_8: ExpandMacro(instruction, OpCodes.Ldc_I4, 8); break; case Code.Ldc_I4_S: ExpandMacro(instruction, OpCodes.Ldc_I4, (int)(sbyte)instruction.Operand); break; case Code.Br_S: instruction.OpCode = OpCodes.Br; break; case Code.Brfalse_S: instruction.OpCode = OpCodes.Brfalse; break; case Code.Brtrue_S: instruction.OpCode = OpCodes.Brtrue; break; case Code.Beq_S: instruction.OpCode = OpCodes.Beq; break; case Code.Bge_S: instruction.OpCode = OpCodes.Bge; break; case Code.Bgt_S: instruction.OpCode = OpCodes.Bgt; break; case Code.Ble_S: instruction.OpCode = OpCodes.Ble; break; case Code.Blt_S: instruction.OpCode = OpCodes.Blt; break; case Code.Bne_Un_S: instruction.OpCode = OpCodes.Bne_Un; break; case Code.Bge_Un_S: instruction.OpCode = OpCodes.Bge_Un; break; case Code.Bgt_Un_S: instruction.OpCode = OpCodes.Bgt_Un; break; case Code.Ble_Un_S: instruction.OpCode = OpCodes.Ble_Un; break; case Code.Blt_Un_S: instruction.OpCode = OpCodes.Blt_Un; break; case Code.Leave_S: instruction.OpCode = OpCodes.Leave; break; } } }
static void EmitParameterEpilogues(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il) { foreach (var p in wrapper.Parameters) { if (p.ParameterType.Name == "StringBuilder") { EmitStringBuilderEpilogue(wrapper, native, p, body, il); } if (!p.ParameterType.IsArray && p.ParameterType.Name == "String") { EmitStringEpilogue(wrapper, p, body, il); } if (p.ParameterType.IsArray && p.ParameterType.GetElementType().Name == "String") { EmitStringArrayEpilogue(wrapper, p, body, il); } } }
public void ReplaceByNop(MethodBody methodBody, Instruction instruction) { methodBody.GetILProcessor().Replace(instruction, Instruction.Create(OpCodes.Nop)); }
private static void EmitReturnTypeWrapper(MethodDefinition wrapper, MethodDefinition native, MethodBody body, ILProcessor il) { if (wrapper.Parameters.Count < native.Parameters.Count) { // Convenience wrapper. The result is stored in the last local variable il.Emit(OpCodes.Ldloc, body.Variables.Count - 1); } else if (wrapper.ReturnType != native.ReturnType) { if (wrapper.ReturnType.Name == "String") { // String return-type wrapper // return new string((sbyte*)((void*)GetString())); var intptr_to_voidpointer = wrapper.Module.Import(mscorlib.MainModule.GetType("System.IntPtr").GetMethods() .First(m => { return (m.Name == "op_Explicit" && m.ReturnType.Name == "Void*"); })); var string_constructor = wrapper.Module.Import(mscorlib.MainModule.GetType("System.String").GetConstructors() .First(m => { var p = m.Parameters; return(p.Count > 0 && p[0].ParameterType.Name == "SByte*"); })); il.Emit(OpCodes.Call, intptr_to_voidpointer); il.Emit(OpCodes.Newobj, string_constructor); } else if (wrapper.ReturnType.Resolve().IsEnum) { // Nothing to do } else if (wrapper.ReturnType.Name == "Boolean" && native.ReturnType.Name == "Byte") { // Nothing to do // It appears that a byte with 1 = true (GL_TRUE) and 0 = false (GL_FALSE) // can be reinterpreted as a bool without a problem. // Todo: maybe we should return (value == 0 ? false : true) just to be // on the safe side? } else { Console.Error.WriteLine("Return wrapper for '{1}' not implemented yet ({0})", native.Name, wrapper.ReturnType.Name); } } else { // nothing to do, the native call leaves the return value // on the stack and we return that unmodified to the caller. } }
private static GeneratedVariableIdentifier EmitStringArrayParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il) { // string[] masrhaling: // IntPtr ptr = MarshalStringArrayToPtr(strings); // try { calli } // finally { FreeStringArrayPtr(ptr); } var marshal_str_array_to_ptr = wrapper.Module.ImportReference(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringArrayToPtr")); // IntPtr ptr; var variableDefinition = new VariableDefinition(TypeIntPtr); body.Variables.Add(variableDefinition); int generatedPointerVarIndex = body.Variables.Count - 1; GeneratedVariableIdentifier stringArrayPtrVar = new GeneratedVariableIdentifier(body, variableDefinition, parameter.Name + "_string_array_ptr"); // ptr = MarshalStringArrayToPtr(strings); il.Emit(OpCodes.Call, marshal_str_array_to_ptr); il.Emit(OpCodes.Stloc, generatedPointerVarIndex); il.Emit(OpCodes.Ldloc, generatedPointerVarIndex); // The finally block will be emitted in the function epilogue return(stringArrayPtrVar); }
public BasicBlockIterator(MethodBody methodBody) { _methodBranchTargets = methodBody.ComputeBranchTargets(); _currentBlockIndex = -1; _foundEndOfPrevBlock = true; }
static void EmitConvenienceWrapper(MethodDefinition wrapper, MethodDefinition native, int difference, MethodBody body, ILProcessor il) { if (wrapper.Parameters.Count > 2) { // Todo: emit all parameters bar the last two throw new NotImplementedException(); } if (wrapper.ReturnType.Name != "Void") { if (difference == 2) { // Convert sized out-array/reference to return value, for example: // void GenTextures(int n, int[] textures) -> int GenTexture() // { // const int n = 1; // int buffers; // calli GenTextures(n, &textures); // return result; // } body.Variables.Add(new VariableDefinition(wrapper.ReturnType)); il.Emit(OpCodes.Ldc_I4, 1); // const int n = 1 il.Emit(OpCodes.Ldloca, body.Variables.Count - 1); // &buffers } else if (difference == 1) { // Convert unsized out-array/reference to return value, for example: // void GetBoolean(GetPName pname, out bool data) -> bool GetBoolean(GetPName pname) // { // bool result; // GetBooleanv(pname, &result); // return result; // } body.Variables.Add(new VariableDefinition(wrapper.ReturnType)); EmitParameters(wrapper, native, body, il); il.Emit(OpCodes.Ldloca, body.Variables.Count - 1); } else { Console.Error.WriteLine("Unknown wrapper type for ({0})", native.Name); } } else { if (difference == 1) { // Convert in-array/reference to single element, for example: // void DeleteTextures(int n, ref int textures) -> void DeleteTexture(int texture) // { // const int n = 1; // calli DeleteTextures(n, &textures); // } il.Emit(OpCodes.Ldc_I4, 1); // const int n = 1 il.Emit(OpCodes.Ldarga, wrapper.Parameters.Last()); // &textures } else { Console.Error.WriteLine("Unknown wrapper type for ({0})", native.Name); } } }
public void GetMethodBody_Abstract() { MethodBody mb = typeof(ICloneable).GetMethod("Clone").GetMethodBody(); Assert.IsNull(mb); }
public ControlFlowAnalysis(MethodBody methodBody) { this.methodBody = methodBody; this.exceptionHandlersStart = new HashSet <string>(); }
static void EmitStringBuilderEpilogue(MethodDefinition wrapper, MethodDefinition native, ParameterDefinition parameter, MethodBody body, ILProcessor il) { var p = parameter.ParameterType; if (p.Name == "StringBuilder") { // void GetShaderInfoLog(..., StringBuilder foo) // try { // foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1); -- already emitted // glGetShaderInfoLog(..., foo_sb_ptr); -- already emitted // MarshalPtrToStringBuilder(foo_sb_ptr, foo); // } // finally { // Marshal.FreeHGlobal(foo_sb_ptr); // } // Make sure we have imported BindingsBase::MasrhalPtrToStringBuilder and Marshal::FreeHGlobal var ptr_to_sb = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalPtrToStringBuilder")); var free_hglobal = wrapper.Module.Import(TypeMarshal.Methods.First(m => m.Name == "FreeHGlobal")); var block = new ExceptionHandler(ExceptionHandlerType.Finally); block.TryStart = body.Instructions[0]; var variable_name = parameter.Name + " _sb_ptr"; var v = body.Variables.First(m => m.Name == variable_name); il.Emit(OpCodes.Ldloc, v.Index); il.Emit(OpCodes.Ldarg, parameter.Index); il.Emit(OpCodes.Call, ptr_to_sb); block.TryEnd = body.Instructions.Last(); block.HandlerStart = body.Instructions.Last(); il.Emit(OpCodes.Ldloc, v.Index); il.Emit(OpCodes.Call, free_hglobal); block.HandlerEnd = body.Instructions.Last(); } }
static void EmitStringBuilderParameter(MethodDefinition method, ParameterDefinition parameter, MethodBody body, ILProcessor il) { var p = parameter.ParameterType; // void GetShaderInfoLog(..., StringBuilder foo) // IntPtr foo_sb_ptr; // try { // foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1); // glGetShaderInfoLog(..., foo_sb_ptr); // MarshalPtrToStringBuilder(foo_sb_ptr, sb); // } // finally { // Marshal.FreeHGlobal(sb_ptr); // } // Make sure we have imported StringBuilder::Capacity and Marshal::AllocHGlobal var sb_get_capacity = method.Module.Import(TypeStringBuilder.Methods.First(m => m.Name == "get_Capacity")); var alloc_hglobal = method.Module.Import(TypeMarshal.Methods.First(m => m.Name == "AllocHGlobal")); // IntPtr ptr; var variable_name = parameter.Name + " _sb_ptr"; body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr)); int index = body.Variables.Count - 1; // ptr = Marshal.AllocHGlobal(sb.Capacity + 1); il.Emit(OpCodes.Callvirt, sb_get_capacity); il.Emit(OpCodes.Call, alloc_hglobal); il.Emit(OpCodes.Stloc, index); il.Emit(OpCodes.Ldloc, index); // We'll emit the try-finally block in the epilogue implementation, // because we haven't yet emitted all necessary instructions here. }
bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, out Exception exception) { try { var body = new MethodBody(initComp); var il = body.GetILProcessor(); il.Emit(OpCodes.Nop); if (initCompRuntime != null) { // Generating branching code for the Previewer // IL_0007: call class [mscorlib]System.Func`2<class [mscorlib]System.Type,string> class [Xamarin.Forms.Xaml.Internals]Xamarin.Forms.Xaml.XamlLoader::get_XamlFileProvider() // IL_000c: brfalse IL_0031 // IL_0011: call class [mscorlib]System.Func`2<class [mscorlib]System.Type,string> class [Xamarin.Forms.Xaml.Internals]Xamarin.Forms.Xaml.XamlLoader::get_XamlFileProvider() // IL_0016: ldarg.0 // IL_0017: call instance class [mscorlib]System.Type object::GetType() // IL_001c: callvirt instance !1 class [mscorlib]System.Func`2<class [mscorlib]System.Type, string>::Invoke(!0) // IL_0021: brfalse IL_0031 // IL_0026: ldarg.0 // IL_0027: call instance void class Xamarin.Forms.Xaml.UnitTests.XamlLoaderGetXamlForTypeTests::__InitComponentRuntime() // IL_002c: ret // IL_0031: nop var nop = Instruction.Create(OpCodes.Nop); var getXamlFileProvider = body.Method.Module.ImportReference(body.Method.Module.ImportReference(typeof(Xamarin.Forms.Xaml.Internals.XamlLoader)) .Resolve() .Properties.FirstOrDefault(pd => pd.Name == "XamlFileProvider") .GetMethod); il.Emit(OpCodes.Call, getXamlFileProvider); il.Emit(OpCodes.Brfalse, nop); il.Emit(OpCodes.Call, getXamlFileProvider); il.Emit(OpCodes.Ldarg_0); var getType = body.Method.Module.ImportReference(body.Method.Module.ImportReference(typeof(object)) .Resolve() .Methods.FirstOrDefault(md => md.Name == "GetType")); il.Emit(OpCodes.Call, getType); var func = body.Method.Module.ImportReference(body.Method.Module.ImportReference(typeof(Func <Type, string>)) .Resolve() .Methods.FirstOrDefault(md => md.Name == "Invoke")); func = func.ResolveGenericParameters(body.Method.Module.ImportReference(typeof(Func <Type, string>)), body.Method.Module); il.Emit(OpCodes.Callvirt, func); il.Emit(OpCodes.Brfalse, nop); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, initCompRuntime); il.Emit(OpCodes.Ret); il.Append(nop); } var visitorContext = new ILContext(il, body, body.Method.Module); rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null); rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null); rootnode.Accept(new PruneIgnoredNodesVisitor(), null); rootnode.Accept(new CreateObjectVisitor(visitorContext), null); rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null); rootnode.Accept(new SetFieldVisitor(visitorContext), null); rootnode.Accept(new SetResourcesVisitor(visitorContext), null); rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null); il.Emit(OpCodes.Ret); initComp.Body = body; exception = null; return(true); } catch (Exception e) { exception = e; return(false); } }
static bool IsEmptyDefault(this MethodBody body) { return(body.Instructions.All(instruction => instruction.OpCode == OpCodes.Nop || instruction.OpCode == OpCodes.Ret)); }
static void EmitStringArrayParameter(MethodDefinition wrapper, ParameterDefinition parameter, MethodBody body, ILProcessor il) { var p = parameter.ParameterType; // string[] masrhaling: // IntPtr ptr = MarshalStringArrayToPtr(strings); // try { calli } // finally { FreeStringArrayPtr(ptr); } var marshal_str_array_to_ptr = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalStringArrayToPtr")); // IntPtr ptr; var variable_name = parameter.Name + "_string_array_ptr"; body.Variables.Add(new VariableDefinition(variable_name, TypeIntPtr)); int index = body.Variables.Count - 1; // ptr = MarshalStringArrayToPtr(strings); il.Emit(OpCodes.Call, marshal_str_array_to_ptr); il.Emit(OpCodes.Stloc, index); il.Emit(OpCodes.Ldloc, index); // The finally block will be emitted in the function epilogue }
private void CheckForInvalidStack(Stack <StackSlot> stack, int depthRequired, MethodBody method, int ilOffset) { if (stack.Count < depthRequired) { WarnAboutInvalidILInMethod(method, ilOffset); while (stack.Count < depthRequired) { stack.Push(new StackSlot()); // Push dummy values to avoid crashes. } // Analysis of this method will be incorrect. } }
public static void Emit(this MethodBody body, Action <ILProcessor> il) { il(body.GetILProcessor()); }
static int EmitParameters(MethodDefinition method, MethodDefinition native, MethodBody body, ILProcessor il) { int i; for (i = 0; i < method.Parameters.Count; i++) { var parameter = method.Parameters[i]; var p = method.Module.Import(method.Parameters[i].ParameterType); il.Emit(OpCodes.Ldarg, i); if (p.Name.Contains("Int32") && native.Parameters[i].ParameterType.Name.Contains("IntPtr")) { // This is a convenience Int32 overload for an IntPtr (size_t) parameter. // We need to convert the loaded argument to IntPtr. il.Emit(OpCodes.Conv_I); } else if (p.Name == "StringBuilder") { EmitStringBuilderParameter(method, parameter, body, il); } else if (p.Name == "String" && !p.IsArray) { EmitStringParameter(method, parameter, body, il); } else if (p.IsByReference) { body.Variables.Add(new VariableDefinition(new PinnedType(p))); var index = body.Variables.Count - 1; il.Emit(OpCodes.Stloc, index); il.Emit(OpCodes.Ldloc, index); il.Emit(OpCodes.Conv_I); } else if (p.IsArray) { if (p.Name != method.Module.Import(typeof(string[])).Name) { // .Net treats 1d arrays differently than higher rank arrays. // 1d arrays are directly supported by instructions such as ldlen and ldelema. // Higher rank arrays must be accessed through System.Array methods such as get_Length. // 1d array: // check array is not null // check ldlen array > 0 // ldc.i4.0 // ldelema // 2d array: // check array is not null // check array.get_Length() > 0 // ldc.i4.0 // ldc.i4.0 // call instance T& T[0..., 0...]::Address(int32, int32) // Mono treats everything as a 1d array. // Interestingly, the .Net approach works on both Mono and .Net. // The Mono approach fails when using high-rank arrays on .Net. // We should report a bug to http://bugzilla.xamarin.com // Pin the array and pass the address // of its first element. var array = (ArrayType)p; var element_type = p.GetElementType(); body.Variables.Add(new VariableDefinition(new PinnedType(new ByReferenceType(element_type)))); int pinned_index = body.Variables.Count - 1; var empty = il.Create(OpCodes.Ldc_I4, 0); var pin = il.Create(OpCodes.Ldarg, i); var end = il.Create(OpCodes.Stloc, pinned_index); // if (array == null) goto empty il.Emit(OpCodes.Brfalse, empty); // else if (array.Length != 0) goto pin il.Emit(OpCodes.Ldarg, i); if (array.Rank == 1) { il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); } else { var get_length = method.Module.Import( mscorlib.MainModule.GetType("System.Array").Methods.First(m => m.Name == "get_Length")); il.Emit(OpCodes.Callvirt, get_length); } il.Emit(OpCodes.Brtrue, pin); // empty: IntPtr ptr = IntPtr.Zero il.Append(empty); il.Emit(OpCodes.Conv_U); il.Emit(OpCodes.Br, end); // pin: &array[0] il.Append(pin); if (array.Rank == 1) { // 1d array (vector), address is taken by ldelema il.Emit(OpCodes.Ldc_I4, 0); il.Emit(OpCodes.Ldelema, element_type); } else { // 2d-3d array, address must be taken as follows: // call instance T& T[0..., 0..., 0...]::Address(int, int, int) ByReferenceType t_ref = array.ElementType.MakeByReferenceType(); MethodReference get_address = new MethodReference("Address", t_ref, array); for (int r = 0; r < array.Rank; r++) { get_address.Parameters.Add(new ParameterDefinition(TypeInt32)); } get_address.HasThis = true; // emit the get_address call for (int r = 0; r < array.Rank; r++) { il.Emit(OpCodes.Ldc_I4, 0); } il.Emit(OpCodes.Call, get_address); } // end: fixed (IntPtr ptr = &array[0]) il.Append(end); il.Emit(OpCodes.Ldloc, pinned_index); il.Emit(OpCodes.Conv_I); } else { EmitStringArrayParameter(method, parameter, body, il); } } } return(i); }