Instruction LoadIndirect(TypeSig type) { switch (type.GetElementType()) { case ElementType.Boolean: return Instruction.Create(OpCodes.Ldind_I1); case ElementType.Char: return Instruction.Create(OpCodes.Ldind_U2); case ElementType.I1: return Instruction.Create(OpCodes.Ldind_I1); case ElementType.U1: return Instruction.Create(OpCodes.Ldind_U1); case ElementType.I2: return Instruction.Create(OpCodes.Ldind_I2); case ElementType.U2: return Instruction.Create(OpCodes.Ldind_U2); case ElementType.I4: return Instruction.Create(OpCodes.Ldind_I4); case ElementType.U4: return Instruction.Create(OpCodes.Ldind_U4); case ElementType.I8: return Instruction.Create(OpCodes.Ldind_I8); case ElementType.U8: return Instruction.Create(OpCodes.Ldind_I8); case ElementType.R4: return Instruction.Create(OpCodes.Ldind_R4); case ElementType.R8: return Instruction.Create(OpCodes.Ldind_R8); case ElementType.String: return Instruction.Create(OpCodes.Ldind_Ref); case ElementType.I: return Instruction.Create(OpCodes.Ldind_I); case ElementType.U: return Instruction.Create(OpCodes.Ldind_I); case ElementType.ValueType: return Instruction.Create(OpCodes.Ldobj, generatedModule.Import(type).ToTypeDefOrRef()); case ElementType.Class: return Instruction.Create(OpCodes.Ldind_Ref); case ElementType.Array: return Instruction.Create(OpCodes.Ldind_Ref); case ElementType.Object: return Instruction.Create(OpCodes.Ldind_Ref); case ElementType.SZArray: return Instruction.Create(OpCodes.Ldind_Ref); case ElementType.Ptr: return Instruction.Create(OpCodes.Ldind_I); case ElementType.FnPtr: return Instruction.Create(OpCodes.Ldind_I); case ElementType.Var: return Instruction.Create(OpCodes.Ldobj, generatedModule.Import(type).ToTypeDefOrRef()); case ElementType.MVar: return Instruction.Create(OpCodes.Ldobj, generatedModule.Import(type).ToTypeDefOrRef()); case ElementType.TypedByRef: return Instruction.Create(OpCodes.Ldobj, generatedModule.Import(type).ToTypeDefOrRef()); case ElementType.GenericInst: var gis = type as GenericInstSig; if (gis.GenericType.IsValueTypeSig) return Instruction.Create(OpCodes.Ldobj, generatedModule.Import(type).ToTypeDefOrRef()); return Instruction.Create(OpCodes.Ldind_Ref); case ElementType.End: case ElementType.Void: case ElementType.ByRef: case ElementType.ValueArray: case ElementType.R: case ElementType.CModReqd: case ElementType.CModOpt: case ElementType.Internal: case ElementType.Module: case ElementType.Sentinel: case ElementType.Pinned: default: return Instruction.Create(OpCodes.Nop); } }
static TypeSig GetArgType(MethodDef method, TypeSig arg) { if (arg.GetElementType() != ElementType.MVar) { return(arg); } var mvar = (GenericMVar)arg; foreach (var gp in method.GenericParameters) { if (gp.Number != mvar.Number) { continue; } foreach (var gpc in gp.GenericParamConstraints) { return(gpc.Constraint.ToTypeSig()); } } return(arg); }
public bool SimplifyTernaryOperator(List <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; ILVariable trueLocVar = null; ILExpression trueExpr; ILLabel trueFall; ILVariable falseLocVar = null; ILExpression falseExpr; ILLabel falseFall; object unused; if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) && trueLocVar == falseLocVar && trueFall == falseFall) || (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) && labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) && body.Contains(labelToBasicBlock[trueLabel]) && body.Contains(labelToBasicBlock[falseLabel]) ) { bool isStloc = trueLocVar != null; ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret; TypeSig retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType; bool retTypeIsBoolean = retType.GetElementType() == ElementType.Boolean; int leftBoolVal; int rightBoolVal; ILExpression newExpr; // a ? true:false is equivalent to a // a ? false:true is equivalent to !a // a ? true : b is equivalent to a || b // a ? b : true is equivalent to !a || b // a ? b : false is equivalent to a && b // a ? false : b is equivalent to !a && b if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0)) ) { // It can be expressed as trivilal expression if (leftBoolVal != 0) { newExpr = condExpr; } else { newExpr = new ILExpression(ILCode.LogicNot, null, condExpr) { InferredType = corLib.Boolean }; } } else if ((retTypeIsBoolean || falseExpr.InferredType.GetElementType() == ElementType.Boolean) && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && (leftBoolVal == 0 || leftBoolVal == 1)) { // It can be expressed as logical expression if (leftBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr); } } else if ((retTypeIsBoolean || trueExpr.InferredType.GetElementType() == ElementType.Boolean) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && (rightBoolVal == 0 || rightBoolVal == 1)) { // It can be expressed as logical expression if (rightBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr); } } else { // Ternary operator tends to create long complicated return statements if (opCode == ILCode.Ret) { return(false); } // Only simplify generated variables if (opCode == ILCode.Stloc && !trueLocVar.GeneratedByDecompiler) { return(false); } // Create ternary expression newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr); } var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); var listNodes = new List <ILNode>(); var newExprNodes = newExpr.GetSelfAndChildrenRecursive <ILNode>(listNodes).ToArray(); foreach (var node in labelToBasicBlock[trueLabel].GetSelfAndChildrenRecursive <ILNode>(listNodes).Except(newExprNodes)) { newExpr.ILRanges.AddRange(node.AllILRanges); } foreach (var node in labelToBasicBlock[falseLabel].GetSelfAndChildrenRecursive <ILNode>(listNodes).Except(newExprNodes)) { newExpr.ILRanges.AddRange(node.AllILRanges); } newExpr.ILRanges.AddRange(tail[0].ILRanges); tail[1].AddSelfAndChildrenRecursiveILRanges(newExpr.ILRanges); head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr)); if (isStloc) { head.Body.Add(new ILExpression(ILCode.Br, trueFall)); } // Remove the old basic blocks body.RemoveOrThrow(labelToBasicBlock[trueLabel]); body.RemoveOrThrow(labelToBasicBlock[falseLabel]); return(true); } return(false); }
void Hash(TypeSig sig, int level) { if (sig == null) { return; } if (level++ > 20) { return; } hasher.Hash((byte)0x41); var etype = sig.GetElementType(); hasher.Hash((byte)etype); switch (etype) { case ElementType.Ptr: case ElementType.ByRef: case ElementType.SZArray: case ElementType.Pinned: Hash(sig.Next, level); break; case ElementType.Array: var arySig = (ArraySig)sig; hasher.Hash(arySig.Rank); hasher.Hash(arySig.Sizes.Count); hasher.Hash(arySig.LowerBounds.Count); Hash(sig.Next, level); break; case ElementType.CModReqd: case ElementType.CModOpt: Hash(((ModifierSig)sig).Modifier); Hash(sig.Next, level); break; case ElementType.ValueArray: hasher.Hash(((ValueArraySig)sig).Size); Hash(sig.Next, level); break; case ElementType.Module: hasher.Hash(((ModuleSig)sig).Index); Hash(sig.Next, level); break; case ElementType.GenericInst: var gis = (GenericInstSig)sig; Hash(gis.GenericType, level); foreach (var ga in gis.GenericArguments) { Hash(ga, level); } Hash(sig.Next, level); break; case ElementType.FnPtr: Hash(((FnPtrSig)sig).Signature); break; case ElementType.Var: case ElementType.MVar: hasher.Hash(((GenericSig)sig).Number); break; case ElementType.ValueType: case ElementType.Class: Hash(((TypeDefOrRefSig)sig).TypeDefOrRef); break; case ElementType.End: case ElementType.Void: case ElementType.Boolean: case ElementType.Char: case ElementType.I1: case ElementType.U1: case ElementType.I2: case ElementType.U2: case ElementType.I4: case ElementType.U4: case ElementType.I8: case ElementType.U8: case ElementType.R4: case ElementType.R8: case ElementType.String: case ElementType.TypedByRef: case ElementType.I: case ElementType.U: case ElementType.R: case ElementType.Object: case ElementType.Internal: case ElementType.Sentinel: default: break; } }
public static bool IsValueTypeOrVoid(this TypeSig type) { var elemType = type.GetElementType(); return(elemType == ElementType.Void || elemType == ElementType.ValueType); }
public static bool IsVoid(this TypeSig type) { return(type.GetElementType() == ElementType.Void); }
void Write(BinaryWriter writer, TypeSig sig, int level) { if (level++ > 20) { return; } writer.Write((byte)ObjectType.TypeSig); var etype = sig.GetElementType(); writer.Write((byte)etype); switch (etype) { case ElementType.Ptr: case ElementType.ByRef: case ElementType.SZArray: case ElementType.Pinned: Write(writer, sig.Next, level); break; case ElementType.Array: var arySig = (ArraySig)sig; writer.Write(arySig.Rank); writer.Write(arySig.Sizes.Count); writer.Write(arySig.LowerBounds.Count); Write(writer, sig.Next, level); break; case ElementType.CModReqd: case ElementType.CModOpt: Write(writer, ((ModifierSig)sig).Modifier); Write(writer, sig.Next, level); break; case ElementType.ValueArray: writer.Write(((ValueArraySig)sig).Size); Write(writer, sig.Next, level); break; case ElementType.Module: writer.Write(((ModuleSig)sig).Index); Write(writer, sig.Next, level); break; case ElementType.GenericInst: var gis = (GenericInstSig)sig; Write(writer, gis.GenericType, level); foreach (var ga in gis.GenericArguments) { Write(writer, ga, level); } Write(writer, sig.Next, level); break; case ElementType.FnPtr: Write(writer, ((FnPtrSig)sig).Signature); break; case ElementType.Var: case ElementType.MVar: writer.Write(((GenericSig)sig).Number); break; case ElementType.ValueType: case ElementType.Class: Write(writer, ((TypeDefOrRefSig)sig).TypeDefOrRef); break; case ElementType.End: case ElementType.Void: case ElementType.Boolean: case ElementType.Char: case ElementType.I1: case ElementType.U1: case ElementType.I2: case ElementType.U2: case ElementType.I4: case ElementType.U4: case ElementType.I8: case ElementType.U8: case ElementType.R4: case ElementType.R8: case ElementType.String: case ElementType.TypedByRef: case ElementType.I: case ElementType.U: case ElementType.R: case ElementType.Object: case ElementType.Internal: case ElementType.Sentinel: default: break; } }
public static void WriteInstruction(string line, ModuleDefUser mod, CilBody epBody) { string[] splitline = line.Split(new string[] { ", " }, StringSplitOptions.None); Instruction previous; TypeSig type = mod.CorLibTypes.Int32; var consoleRef = new TypeRefUser(mod, "System", "Console", mod.CorLibTypes.AssemblyRef); var stringRef = new TypeRefUser(mod, "System", "String", mod.CorLibTypes.AssemblyRef); switch (splitline[0]) { case "ldstr": ldstr(epBody, splitline[1]); return; case "ldint": ldint(epBody, int.Parse(splitline[1])); return; case "ldbool": ldbool(epBody, splitline[1]); return; case "call": int placeholder; switch (splitline[1]) { case "print": previous = epBody.Instructions[epBody.Instructions.Count - 1]; if (previous.OpCode == OpCodes.Ldstr) { type = mod.CorLibTypes.String; } else if (previous.OpCode == OpCodes.Call) { type = getReturnType(previous.GetOperand()); } else if (previous.IsLdloc()) { type = previous.GetLocal(epBody.Variables).Type; } var consoleWrite1 = new MemberRefUser(mod, "WriteLine", MethodSig.CreateStatic(mod.CorLibTypes.Void, type), consoleRef); epBody.Instructions.Add(OpCodes.Call.ToInstruction(consoleWrite1)); return; case "readline": var consoleRead1 = new MemberRefUser(mod, "ReadLine", MethodSig.CreateStatic(mod.CorLibTypes.String), consoleRef); epBody.Instructions.Add(OpCodes.Call.ToInstruction(consoleRead1)); return; case "concat": var concat = new MemberRefUser(mod, "Concat", MethodSig.CreateStatic(mod.CorLibTypes.String, mod.CorLibTypes.String, mod.CorLibTypes.String), stringRef); epBody.Instructions.Add(OpCodes.Call.ToInstruction(concat)); return; case "seq": var seq = new MemberRefUser(mod, "op_Equality", MethodSig.CreateStatic(mod.CorLibTypes.Boolean, mod.CorLibTypes.String, mod.CorLibTypes.String), stringRef); epBody.Instructions.Add(OpCodes.Call.ToInstruction(seq)); return; case "return": epBody.Instructions.Add(OpCodes.Ret.ToInstruction()); return; case "add": epBody.Instructions.Add(OpCodes.Add.ToInstruction()); return; case "sub": epBody.Instructions.Add(OpCodes.Sub.ToInstruction()); return; case "mult": epBody.Instructions.Add(OpCodes.Mul.ToInstruction()); return; case "div": epBody.Instructions.Add(OpCodes.Div_Un.ToInstruction()); return; case "eq": epBody.Instructions.Add(OpCodes.Ceq.ToInstruction()); return; case "gt": epBody.Instructions.Add(OpCodes.Cgt.ToInstruction()); return; case "lt": epBody.Instructions.Add(OpCodes.Clt.ToInstruction()); return; } epBody.Instructions.Add(OpCodes.Call.ToInstruction(findfunc(splitline[1]))); return; case "ldvar": ldvar(epBody, splitline[1]); return; case "setvar": Local local = getvar(typeFromString(mod, splitline[2]), splitline[1], epBody.Variables); epBody.Instructions.Add(OpCodes.Stloc.ToInstruction(epBody.Variables.Add(local))); return; case "newfunc": List <string> arguments = new List <string>(); foreach (string arg in splitline) { arguments.Add(arg); } arguments.RemoveRange(0, 3); currentfunc = newfunc(mod, splitline[1], typeFromString(mod, splitline[2]), argumentsFromStrings(mod, arguments.ToArray())); return; case "endfunc": currentfunc = mod.EntryPoint; return; case "br": handleBrBegin(epBody, int.Parse(splitline[1]), "br"); return; case "brtrue": handleBrBegin(epBody, int.Parse(splitline[1]), "brtrue"); return; case "brfalse": handleBrBegin(epBody, int.Parse(splitline[1]), "brfalse"); return; case "brend": //wasted instruction, fix potentially epBody.Instructions.Add(OpCodes.Nop.ToInstruction()); placeholder = epBody.Instructions.Count - 1; int branch = int.Parse(splitline[1]); if (manager.branchExists(branch)) { handleBrEnd(epBody, branch, placeholder, manager.getBranchType(branch)); } else { manager.pushBranch(branch, placeholder, "brend"); } return; case "pop?": previous = epBody.Instructions[epBody.Instructions.Count - 1]; if (previous.OpCode != OpCodes.Call) { return; } type = getReturnType(previous.GetOperand()); if (type.GetElementType() != ElementType.Void) { epBody.Instructions.Add(OpCodes.Pop.ToInstruction()); } return; case "arg": epBody.Instructions.Add(OpCodes.Ldarg.ToInstruction(mod.EntryPoint.Parameters[int.Parse(splitline[1])])); return; } Console.WriteLine(line); throw new Exception("unknown intermediate instruction"); }