// May not return all args. The args are returned in reverse order. static PushedArgs GetPushedArgInstructions(IList <Instruction> instructions, int index, int numArgs) { var pushedArgs = new PushedArgs(numArgs); Instruction instr; int skipPushes = 0; while (index >= 0 && pushedArgs.CanAddMore) { instr = GetPreviousInstruction(instructions, ref index); if (instr == null) { break; } instr.CalculateStackUsage(false, out int pushes, out int pops); if (pops == -1) { break; } if (instr.OpCode.Code == Code.Dup) { pushes = 1; pops = 0; } if (pushes > 1) { break; } if (skipPushes > 0) { skipPushes -= pushes; if (skipPushes < 0) { break; } skipPushes += pops; } else { if (pushes == 1) { pushedArgs.Add(instr); } skipPushes += pops; } } instr = pushedArgs.Get(0); if (instr != null && instr.OpCode.Code == Code.Dup) { instr = GetPreviousInstruction(instructions, ref index); if (instr != null) { instr.CalculateStackUsage(false, out int pushes, out int pops); if (pushes == 1 && pops == 0) { pushedArgs.Set(0, instr); } } } pushedArgs.FixDups(); return(pushedArgs); }
// May not return all args. The args are returned in reverse order. static PushedArgs GetPushedArgInstructions(IList <Instruction> instructions, int index, int numArgs) { var pushedArgs = new PushedArgs(numArgs); if (!pushedArgs.CanAddMore) { return(pushedArgs); } Dictionary <int, Branch> branches = null; var states = new Stack <State>(); var state = new State(index, null, 0, 0, 1, new HashSet <int>()); var isBacktrack = false; states.Push(state.Clone()); while (true) { while (state.index >= 0) { if (branches != null && branches.TryGetValue(state.index, out var branch) && state.visited.Add(state.index)) { branch.current = 0; var brState = state.Clone(); brState.branch = branch; states.Push(brState); } if (!isBacktrack) { state.index--; } isBacktrack = false; var update = UpdateState(instructions, state, pushedArgs); if (update == Update.Finish) { return(pushedArgs); } if (update == Update.Fail) { break; } } if (states.Count == 0) { return(pushedArgs); } var prevValidArgs = state.validArgs; state = states.Pop(); if (state.validArgs < prevValidArgs) { for (int i = state.validArgs + 1; i <= prevValidArgs; i++) { pushedArgs.Pop(); } } if (branches == null) { branches = GetBranches(instructions); } else { isBacktrack = true; state.index = state.branch.Variants[state.branch.current++]; if (state.branch.current < state.branch.Variants.Count) { states.Push(state.Clone()); } else { state.branch = null; } } } }
// May not return all args. The args are returned in reverse order. static PushedArgs getPushedArgInstructions(IList<Instruction> instructions, int index, int numArgs) { var pushedArgs = new PushedArgs(numArgs); Instruction instr; int skipPushes = 0; while (index >= 0 && pushedArgs.CanAddMore) { instr = getPreviousInstruction(instructions, ref index); if (instr == null) break; int pushes, pops; instr.CalculateStackUsage(false, out pushes, out pops); if (pops == -1) break; if (instr.OpCode.Code == Code.Dup) { pushes = 1; pops = 0; } if (pushes > 1) break; if (skipPushes > 0) { skipPushes -= pushes; if (skipPushes < 0) break; skipPushes += pops; } else { if (pushes == 1) pushedArgs.add(instr); skipPushes += pops; } } instr = pushedArgs.get(0); if (instr != null && instr.OpCode.Code == Code.Dup) { instr = getPreviousInstruction(instructions, ref index); if (instr != null) { int pushes, pops; instr.CalculateStackUsage(false, out pushes, out pops); if (pushes == 1 && pops == 0) pushedArgs.set(0, instr); } } pushedArgs.fixDups(); return pushedArgs; }
private static Update UpdateState(IList <Instruction> instructions, State state, PushedArgs pushedArgs) { if (state.index < 0 || state.index >= instructions.Count) { return(Update.Fail); } var instr = instructions[state.index]; if (!Instr.IsFallThrough(instr.OpCode)) { return(Update.Fail); } instr.CalculateStackUsage(false, out int pushes, out int pops); if (pops == -1) { return(Update.Fail); } var isDup = instr.OpCode.Code == Code.Dup; if (isDup) { pushes = 1; pops = 0; } if (pushes > 1) { return(Update.Fail); } if (state.skipPushes > 0) { state.skipPushes -= pushes; if (state.skipPushes < 0) { return(Update.Fail); } state.skipPushes += pops; } else { if (pushes == 1) { if (isDup) { state.addPushes++; } else { for (; state.addPushes > 0; state.addPushes--) { pushedArgs.Add(instr); state.validArgs++; if (!pushedArgs.CanAddMore) { return(Update.Finish); } } state.addPushes = 1; } } state.skipPushes += pops; } return(Update.Ok); }