public override void WriteTo(FlashWriter output) { var marks = new Dictionary <ASInstruction, long>(); var sharedExits = new Dictionary <ASInstruction, List <ASInstruction> >(); var forwardCaseExits = new Dictionary <ASInstruction, Tuple <LookUpSwitchIns, int> >(); foreach (ASInstruction instruction in _instructions) { long previousPosition = output.Position; marks.Add(instruction, previousPosition); instruction.WriteTo(output); List <ASInstruction> jumpers = null; if (sharedExits.TryGetValue(instruction, out jumpers)) { foreach (ASInstruction jumper in jumpers) { long position = marks[jumper]; var fixedOffset = (uint)(previousPosition - (position + 4)); ((Jumper)jumper).Offset = fixedOffset; Rewrite(output, jumper, position); } sharedExits.Remove(instruction); } Tuple <LookUpSwitchIns, int> switchIdentity = null; if (forwardCaseExits.TryGetValue(instruction, out switchIdentity)) { int caseIndex = switchIdentity.Item2; LookUpSwitchIns lookUpSwitch = switchIdentity.Item1; long position = marks[lookUpSwitch]; var fixedOffset = (uint)(previousPosition - position); if (caseIndex == lookUpSwitch.CaseOffsets.Count) { lookUpSwitch.DefaultOffset = fixedOffset; } else { lookUpSwitch.CaseOffsets[caseIndex] = fixedOffset; } Rewrite(output, lookUpSwitch, position); } if (instruction.OP == OPCode.LookUpSwitch) { bool requiresRewrite = false; var lookUpSwitch = (LookUpSwitchIns)instruction; ASInstruction[] cases = SwitchExits[lookUpSwitch]; for (int i = 0; i < cases.Length; i++) { ASInstruction exit = cases[i]; if (exit.OP != OPCode.Label) { forwardCaseExits.Add(exit, Tuple.Create(lookUpSwitch, i)); } else { requiresRewrite = true; long exitPosition = marks[exit]; long jumpCount = (previousPosition - (exitPosition + 1)); uint fixedOffset = (uint)(uint.MaxValue - jumpCount); if (i == (cases.Length - 1)) { lookUpSwitch.DefaultOffset = fixedOffset; } else { lookUpSwitch.CaseOffsets[i] = fixedOffset; } } } if (requiresRewrite) { Rewrite(output, lookUpSwitch, previousPosition); } } else if (Jumper.IsValid(instruction.OP)) { var jumper = (Jumper)instruction; if (jumper.Offset == 0) { continue; } ASInstruction exit = null; if (!JumpExits.TryGetValue(jumper, out exit)) { // An exit for this jump instruction could not be found, perhaps its' offset exceeds the index limit? continue; } else if (exit.OP != OPCode.Label || !marks.ContainsKey(exit)) // Forward jumps can have a label for an exit, as long as it is located ahead. { jumpers = null; if (!sharedExits.TryGetValue(exit, out jumpers)) { jumpers = new List <ASInstruction>(); sharedExits.Add(exit, jumpers); } jumpers.Add(jumper); } else // Backward jumps must always have a label for an exit, and must be behind this instruction. { long exitPosition = marks[exit]; long jumpCount = (output.Position - (exitPosition + 1)); var fixedOffset = (uint)(uint.MaxValue - jumpCount); jumper.Offset = fixedOffset; Rewrite(output, jumper, previousPosition); } } } }
private void LoadInstructions() { var caseIndices = new Dictionary <long, int>(); var marks = new Dictionary <long, ASInstruction>(); var sharedExits = new Dictionary <long, List <Jumper> >(); var forwardCaseExits = new Dictionary <long, LookUpSwitchIns>(); using (var input = new FlashReader(_body.Code)) { while (input.IsDataAvailable) { long previousPosition = input.Position; var instruction = ASInstruction.Create(_abc, input); marks[previousPosition] = instruction; _indices.Add(instruction, _indices.Count); _instructions.Add(instruction); List <ASInstruction> instructions = null; if (!_opGroups.TryGetValue(instruction.OP, out instructions)) { instructions = new List <ASInstruction>(); _opGroups.Add(instruction.OP, instructions); } instructions.Add(instruction); List <Jumper> jumpers = null; if (sharedExits.TryGetValue(previousPosition, out jumpers)) { // This is an exit position for a jump instruction, or more. foreach (Jumper jumper in jumpers) { JumpExits.Add(jumper, instruction); } sharedExits.Remove(previousPosition); } LookUpSwitchIns lookUpSwitch = null; if (forwardCaseExits.TryGetValue(previousPosition, out lookUpSwitch)) { int index = caseIndices[previousPosition]; SwitchExits[lookUpSwitch][index] = instruction; caseIndices.Remove(previousPosition); forwardCaseExits.Remove(previousPosition); } if (instruction.OP == OPCode.LookUpSwitch) { lookUpSwitch = (LookUpSwitchIns)instruction; var offsets = new List <uint>(lookUpSwitch.CaseOffsets); offsets.Add(lookUpSwitch.DefaultOffset); var cases = new ASInstruction[offsets.Count]; for (int i = 0; i < offsets.Count; i++) { ASInstruction exit = null; long exitPosition = (previousPosition + offsets[i]); if (exitPosition <= input.Length) { caseIndices.Add(exitPosition, i); forwardCaseExits.Add(exitPosition, lookUpSwitch); } else { cases[i] = exit; exit = marks[(exitPosition - uint.MaxValue) - 1]; } } SwitchExits.Add(lookUpSwitch, cases); } else if (Jumper.IsValid(instruction.OP)) { var jumper = (Jumper)instruction; if (jumper.Offset == 0) { continue; } long exitPosition = (input.Position + jumper.Offset); if (exitPosition == input.Length) { // Jump exit does not exist at this (non-existent)index, do not look for exit. continue; } else if (exitPosition < input.Length) // Forward jump. { jumpers = null; if (!sharedExits.TryGetValue(exitPosition, out jumpers)) { jumpers = new List <Jumper>(); sharedExits.Add(exitPosition, jumpers); } jumpers.Add(jumper); } else // Backwards jump. { var label = (LabelIns)marks[(exitPosition - uint.MaxValue) - 1]; JumpExits.Add(jumper, label); } } } } }