public InstructionAttribute(char character, string engrish, string description, NodeType type, InstructionGroup group) { Character = character; Engrish = engrish; Description = description; Type = type; Group = group; }
/// <summary> /// Populated the initialization variables and instructions. Also populates the boundary instruction index. /// </summary> private void PopulateInitializationItemsAndFindBoundary() { // we want the collection of instructions before the boundary instruction (base constructor or chained constructor call) InstructionGroup instructionGroup = null; var isConstructorCallFound = false; while (!isConstructorCallFound && InstructionGroup.TryGetNext( this.Constructor.Body.Instructions, instructionGroup?.LastIndex + 1 ?? 0, out instructionGroup)) { var instructionOperandAsMethodReference = instructionGroup.LastInstruction.Operand as MethodReference; if (instructionGroup.IsCall && instructionOperandAsMethodReference != null && instructionOperandAsMethodReference.Name == ".ctor" && (instructionOperandAsMethodReference.DeclaringType.FullName == this.Constructor.DeclaringType.FullName || instructionOperandAsMethodReference.DeclaringType.FullName == this.Constructor.DeclaringType.BaseType.FullName)) { this.InnerBoundaryFirstInstructionIndex = instructionGroup.FirstIndex; this.InnerBoundaryLastInstructionIndex = instructionGroup.LastIndex; this.IsInitializingConstructor = instructionOperandAsMethodReference.DeclaringType.FullName == this.Constructor.DeclaringType.BaseType.FullName; isConstructorCallFound = true; } else { // add the instruction to initialization instructions this.InnerInitializationInstructions.AddRange(instructionGroup.Instructions); } // any variables referenced by instructions should be removed from construction variables // and if we have not yet found the constructor call, then the variable should be put into initialization foreach (var instruction in instructionGroup.Instructions) { VariableDefinition variable; if (!this.TryGetReferencedVariable(instruction, out variable) || !this.InnerConstructionVariables.Contains(variable)) { continue; } this.InnerConstructionVariables.Remove(variable); if (!isConstructorCallFound) { // if an instance arises where a variable is only used in a constructor call // then it would be dropped this.InnerInitializationVariables.Add(variable); } } } if (!isConstructorCallFound) { throw new InvalidOperationException( $"Cannot find base or chained constructor call while multiplexing a constructor: {this.Constructor.FullName}"); } }
/// <summary> /// Grabs the next group of instructions that could potentially be a base or chained construtor call. /// </summary> /// <param name="sourceInstructions">Source instructions to look at.</param> /// <param name="firstIndex">Index of the first instruction to look at.</param> /// <param name="instructionGroup">Output parameter to contain the results.</param> /// <returns><c>true</c> if a group was successfully created, else <c>false</c>.</returns> public static bool TryGetNext(IList <Instruction> sourceInstructions, int firstIndex, out InstructionGroup instructionGroup) { Contract.Requires(sourceInstructions != null); if (firstIndex < 0 || firstIndex >= sourceInstructions.Count) { instructionGroup = null; return(false); } var instructions = new List <Instruction>(); var instruction = sourceInstructions[firstIndex]; instructions.Add(instruction); int lastIndex; if (instruction.OpCode.Code != Code.Ldarg_0) { lastIndex = firstIndex; } else { int i; // calls into base and chained constructors start like this // so we'll look for the next call instruction or any instruction where the next instruction is another ldarg.0 // meaning that the stack was cleared at some point // there is no assumption that this grouping is generally useful, but the hope is that it will catch constructor calls in this specific case var isLastInstructionFound = false; for (i = firstIndex + 1; !isLastInstructionFound && i < sourceInstructions.Count; i++) { instruction = sourceInstructions[i]; instructions.Add(instruction); if (instruction.OpCode.Code == Code.Call || instruction.OpCode.Code == Code.Callvirt || instruction.OpCode.Code == Code.Calli || (instruction.Next != null && instruction.Next.OpCode.Code == Code.Ldarg_0)) { isLastInstructionFound = true; } } lastIndex = i - 1; } instructionGroup = new InstructionGroup(firstIndex, lastIndex, instructions); return(true); }
protected static CreateMethod GetMethod(InstructionGroup group, bool unsigned, bool useReg) { var(regCount, immCount, memCount) = GetOpKindCount(group, useReg); int regId = 1, immId = 1, memId = 1; string doc = group.Operands.Length switch { 0 => "Creates an instruction with no operands", 1 => "Creates an instruction with 1 operand", _ => $"Creates an instruction with {group.Operands.Length} operands", }; var method = new CreateMethod(doc); AddCodeArg(method); int opNum = -1; foreach (var op in group.Operands) { opNum++; switch (op.Split(useReg)) { case InstructionOperand.RegisterMemory: throw new InvalidOperationException(); case InstructionOperand.Register: method.Args.Add(new MethodArg($"op{opNum}: Register", MethodArgType.Register, GetArgName("register", regCount, regId++))); break; case InstructionOperand.Memory: method.Args.Add(new MethodArg($"op{opNum}: Memory operand", MethodArgType.Memory, GetArgName("memory", memCount, memId++))); break; case InstructionOperand.Imm32: method.Args.Add(new MethodArg($"op{opNum}: Immediate value", unsigned ? MethodArgType.UInt32 : MethodArgType.Int32, GetArgName("immediate", immCount, immId++))); break; case InstructionOperand.Imm64: method.Args.Add(new MethodArg($"op{opNum}: Immediate value", unsigned ? MethodArgType.UInt64 : MethodArgType.Int64, GetArgName("immediate", immCount, immId++))); break; default: throw new InvalidOperationException(); } } return(method);
private static void DoInstruction(Instruction ins) { InstructionGroup grp = ins.GetGroup(); Debug.Write(ins.ToString() + " "); if (ins.HasArgument()) { Debug.WriteLine(ReadInt32(cursor, code)); } else { Debug.WriteLine(""); } switch (grp) { case InstructionGroup.Base: BaseInstruction(ins); break; case InstructionGroup.Stack: StackInstruction(ins, ins.HasArgument() ? ReadInt32() : 0); break; case InstructionGroup.Aritmetics: ArithmeticInstruction(ins); break; case InstructionGroup.Bitwise: BitwiseCommand(ins); break; case InstructionGroup.ConditionsAndJumps: CondAndJumpInstruction(ins, ins.HasArgument() ? ReadInt32() : 0); break; } #if DEBUG //Dump(); #endif }
public static void processMethod1(MethodDef method) { method.Body.SimplifyBranches(); InstructionGroups instructionGroups = new InstructionGroups(); InstructionGroup instructionGroup = new InstructionGroup(); int num = 0; int num2 = 0; bool flag = false; foreach (Instruction instruction in method.Body.Instructions) { int num3 = 0; int num4; instruction.CalculateStackUsage(out num4, out num3); instructionGroup.Add(instruction); num2 += num4 - num3; if (num4 == 0 && instruction.OpCode != OpCodes.Nop && (num2 == 0 || instruction.OpCode == OpCodes.Ret)) { if (!flag) { InstructionGroup instructionGroup2 = new InstructionGroup(); instructionGroup2.ID = num++; instructionGroup2.nextGroup = instructionGroup2.ID + 1; instructionGroups.Add(instructionGroup2); instructionGroup2 = new InstructionGroup(); instructionGroup2.ID = num++; instructionGroup2.nextGroup = instructionGroup2.ID + 1; instructionGroups.Add(instructionGroup2); flag = true; } instructionGroup.ID = num++; instructionGroup.nextGroup = instructionGroup.ID + 1; instructionGroups.Add(instructionGroup); instructionGroup = new InstructionGroup(); } } if (instructionGroups.Count == 1) { return; } InstructionGroup last = instructionGroups.getLast(); instructionGroups.Scramble(out instructionGroups); method.Body.Instructions.Clear(); Local local = new Local(controlflow.asm.CorLibTypes.Int32); method.Body.Variables.Add(local); Instruction instruction2 = Instruction.Create(OpCodes.Nop); Instruction instruction3 = Instruction.Create(OpCodes.Br, instruction2); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc, local)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Br, instruction3)); method.Body.Instructions.Add(instruction2); foreach (InstructionGroup instructionGroup3 in instructionGroups) { if (instructionGroup3 != last) { method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc, local)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4, instructionGroup3.ID)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ceq)); Instruction instruction4 = Instruction.Create(OpCodes.Nop); method.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, instruction4)); foreach (Instruction item in instructionGroup3) { method.Body.Instructions.Add(item); } method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4, instructionGroup3.nextGroup)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc, local)); method.Body.Instructions.Add(instruction4); } } method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc, local)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4, instructionGroups.Count - 1)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ceq)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, instruction3)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Br, last[0])); method.Body.Instructions.Add(instruction3); foreach (Instruction item2 in last) { method.Body.Instructions.Add(item2); } method.Body.OptimizeBranches(); method.Body.OptimizeMacros(); }
protected abstract void GenCreate(FileWriter writer, CreateMethod method, InstructionGroup group, int id);
/// <summary> /// Grabs the next group of instructions that could potentially be a base or chained construtor call. /// </summary> /// <param name="sourceInstructions">Source instructions to look at.</param> /// <param name="firstIndex">Index of the first instruction to look at.</param> /// <param name="instructionGroup">Output parameter to contain the results.</param> /// <returns><c>true</c> if a group was successfully created, else <c>false</c>.</returns> public static bool TryGetNext(IList<Instruction> sourceInstructions, int firstIndex, out InstructionGroup instructionGroup) { Contract.Requires(sourceInstructions != null); if (firstIndex < 0 || firstIndex >= sourceInstructions.Count) { instructionGroup = null; return false; } var instructions = new List<Instruction>(); var instruction = sourceInstructions[firstIndex]; instructions.Add(instruction); int lastIndex; if (instruction.OpCode.Code != Code.Ldarg_0) { lastIndex = firstIndex; } else { int i; // calls into base and chained constructors start like this // so we'll look for the next call instruction or any instruction where the next instruction is another ldarg.0 // meaning that the stack was cleared at some point // there is no assumption that this grouping is generally useful, but the hope is that it will catch constructor calls in this specific case var isLastInstructionFound = false; for (i = firstIndex + 1; !isLastInstructionFound && i < sourceInstructions.Count; i++) { instruction = sourceInstructions[i]; instructions.Add(instruction); if (instruction.OpCode.Code == Code.Call || instruction.OpCode.Code == Code.Callvirt || instruction.OpCode.Code == Code.Calli || (instruction.Next != null && instruction.Next.OpCode.Code == Code.Ldarg_0)) { isLastInstructionFound = true; } } lastIndex = i - 1; } instructionGroup = new InstructionGroup(firstIndex, lastIndex, instructions); return true; }
private static InstructionDescription MAKE_INST(InstructionCode code, string name, InstructionGroup group, InstructionFlags flags, OperandFlags oflags0, OperandFlags oflags1, int opReg, uint opcode0, uint opcode1) { return new InstructionDescription(code, name, group, flags, new OperandFlags[] { oflags0, oflags1 }, opReg, (int)opcode0, (int)opcode1); }
private InstructionDescription(InstructionCode code, string name, InstructionGroup group, InstructionFlags flags, OperandFlags[] operandFlags, int opReg, int opcode0, int opcode1) { Contract.Requires(operandFlags != null); _code = code; _name = name; _group = (byte)group; _flags = (byte)flags; _operandFlags = new ReadOnlyCollection<OperandFlags>((OperandFlags[])operandFlags.Clone()); _opcodeR = (short)opReg; _opcode0 = opcode0; _opcode1 = opcode1; }