using System; using System.Collections.Generic; using System.Linq; using System.Text; using ILRuntime.Mono.Cecil; using ILRuntime.Mono.Cecil.Cil; using ILRuntime.CLR.TypeSystem; using ILRuntime.CLR.Method; using ILRuntime.Runtime.Intepreter.OpCodes; namespace ILRuntime.Runtime.Intepreter.RegisterVM { class RegisterVMSymbolLink { public int BaseRegisterIndex; public RegisterVMSymbol Value; } struct InlineMethodInfo { public short LocalStartRegister; public ILMethod Method; } struct RegisterVMSymbol { public Instruction Instruction; public ILMethod Method; public RegisterVMSymbolLink ParentSymbol; } class CodeBasicBlock { List instructions = new List(); List finalInstructions = new List(); HashSet canRemove = new HashSet(); HashSet pendingCP = new HashSet(); HashSet prevBlocks = new HashSet(); HashSet nextBlocks = new HashSet(); Dictionary instructionMapping = new Dictionary(); short endRegister = -1; Instruction entry; public List Instructions { get { return instructions; } } public List FinalInstructions { get { return finalInstructions; } } public HashSet CanRemove { get { return canRemove; } } public HashSet PendingCP { get { return pendingCP; } } public HashSet PreviousBlocks { get { return prevBlocks; } } public HashSet NextBlocks { get { return nextBlocks; } } public Dictionary InstructionMapping { get { return instructionMapping; } } public bool NeedLoadConstantElimination { get; set; } public short EndRegister { get { return endRegister; } set { endRegister = value; } } public void AddInstruction(Instruction op) { if (instructions.Count == 0) entry = op; instructions.Add(op); } public static List BuildBasicBlocks(MethodBody body, out Dictionary entryMapping) { entryMapping = new Dictionary(); HashSet branchTargets = new HashSet(); foreach (var i in body.Instructions) { switch (i.OpCode.OperandType) { case OperandType.InlineBrTarget: case OperandType.ShortInlineBrTarget: branchTargets.Add((Instruction)i.Operand); break; case OperandType.InlineSwitch: { var arr = i.Operand as Instruction[]; foreach (var j in arr) branchTargets.Add(j); } break; } } List res = new List(); CodeBasicBlock cur = new CodeBasicBlock(); res.Add(cur); foreach (var i in body.Instructions) { if (branchTargets.Contains(i)) { if(cur.entry != null && cur.entry != i) { entryMapping[cur.entry] = res.Count - 1; cur = new CodeBasicBlock(); res.Add(cur); } } cur.AddInstruction(i); if (i.OpCode.Code == Code.Switch || i.OpCode.Code == Code.Throw || i.OpCode.OperandType == OperandType.InlineBrTarget || i.OpCode.OperandType == OperandType.ShortInlineBrTarget || i.OpCode.Code == Code.Endfinally) { if (cur.entry != null) { if (i.OpCode.OperandType == OperandType.InlineBrTarget || i.OpCode.OperandType == OperandType.ShortInlineBrTarget) { if (cur.entry != (Instruction)i.Operand) { entryMapping[cur.entry] = res.Count - 1; cur = new CodeBasicBlock(); res.Add(cur); } } else { if (i.Operand is Instruction) { if (cur.entry != (Instruction)i.Operand) { entryMapping[cur.entry] = res.Count - 1; cur = new CodeBasicBlock(); res.Add(cur); } } else { entryMapping[cur.entry] = res.Count - 1; cur = new CodeBasicBlock(); res.Add(cur); } } } } } if (cur.entry != null) entryMapping[cur.entry] = res.Count - 1; else res.RemoveAt(res.Count - 1); for (int i = 0; i < res.Count; i++) { var block = res[i]; var lastIns = block.instructions[block.instructions.Count - 1]; switch (lastIns.OpCode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: { var dstBlock = res[entryMapping[(Instruction)lastIns.Operand]]; dstBlock.prevBlocks.Add(block); block.nextBlocks.Add(dstBlock); switch (lastIns.OpCode.Code) { case Code.Brfalse: case Code.Brfalse_S: case Code.Brtrue: case Code.Brtrue_S: case Code.Beq: case Code.Beq_S: case Code.Bge: case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: case Code.Bgt: case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: case Code.Ble: case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: case Code.Blt: case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: case Code.Bne_Un: case Code.Bne_Un_S: if (i < res.Count - 1) { var next = res[i + 1]; block.nextBlocks.Add(next); next.prevBlocks.Add(block); } break; default: continue; } } break; case OperandType.InlineSwitch: { Instruction[] targets = (Instruction[])lastIns.Operand; foreach(var t in targets) { var dstBlock = res[entryMapping[t]]; dstBlock.prevBlocks.Add(block); block.nextBlocks.Add(dstBlock); } } break; } if (i < res.Count - 1) { var next = res[i + 1]; block.nextBlocks.Add(next); next.prevBlocks.Add(block); } } return res; } } }