internal bool InlineSubroutine() { bool hasJsrs = false; // start with a pre-amble to load a dummy return address on the stack and to branch to the subroutine { // TODO consider exception handling around these instructions ClassFile.Method.Instruction instr = new ClassFile.Method.Instruction(); instr.PatchOpCode(NormalizedByteCode.__aconst_null); instr.SetPC(inliner.m.Instructions[subroutineIndex].PC); Emit(instr); EmitGoto(subroutineIndex); } bool fallThru = false; for (int instructionIndex = 0; instructionIndex < inliner.m.Instructions.Length; instructionIndex++) { if ((inliner.flags[instructionIndex] & InstructionFlags.Reachable) != 0 && inliner.ma.IsSubroutineActive(instructionIndex, subroutineIndex)) { fallThru = false; branchMap[instructionIndex] = inliner.codeLength; switch (inliner.m.Instructions[instructionIndex].NormalizedOpCode) { case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: case NormalizedByteCode.__ireturn: case NormalizedByteCode.__lreturn: case NormalizedByteCode.__freturn: case NormalizedByteCode.__dreturn: case NormalizedByteCode.__areturn: case NormalizedByteCode.__return: case NormalizedByteCode.__athrow: case NormalizedByteCode.__goto: Emit(inliner.m.Instructions[instructionIndex]); break; case NormalizedByteCode.__jsr: hasJsrs = true; goto default; case NormalizedByteCode.__ret: { int subid = inliner.ma.GetLocalTypeWrapper(instructionIndex, inliner.m.Instructions[instructionIndex].TargetIndex).SubroutineIndex; if (subid == subroutineIndex) { EmitGoto(returnIndex); } else { Emit(inliner.m.Instructions[instructionIndex]); } break; } default: fallThru = true; Emit(inliner.m.Instructions[instructionIndex]); break; } } else if (fallThru) { EmitGoto(instructionIndex); } } endIndex = inliner.codeLength; DoFixups(); return hasJsrs; }
private bool InlineJsrs() { bool hasJsrs = false; List<SubroutineCall> subs = new List<SubroutineCall>(); int len = codeLength; for (int i = 0; i < len; i++) { // note that we're also (needlessly) processing the subroutines here, but that shouldn't be a problem (just a minor waste of cpu) // because the code is unreachable anyway if ((flags[i] & InstructionFlags.Reachable) != 0 && m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__jsr) { int subroutineId = m.Instructions[i].TargetIndex; codeCopy[i].PatchOpCode(NormalizedByteCode.__goto, codeLength); SubroutineCall sub = new SubroutineCall(this, subroutineId, i + 1); hasJsrs |= sub.InlineSubroutine(); subs.Add(sub); } } List<ClassFile.Method.ExceptionTableEntry> exceptions = new List<ClassFile.Method.ExceptionTableEntry>(m.ExceptionTable); foreach (SubroutineCall sub in subs) { sub.DoExceptions(m.ExceptionTable, exceptions); } m.ExceptionTable = exceptions.ToArray(); ClassFile.Method.Instruction instr = new ClassFile.Method.Instruction(); instr.SetTermNop(0xFFFF); Add(instr); Array.Resize(ref codeCopy, codeLength); m.Instructions = codeCopy; return hasJsrs; }
private void EmitGoto(int targetIndex) { ClassFile.Method.Instruction instr = new ClassFile.Method.Instruction(); instr.PatchOpCode(NormalizedByteCode.__goto, targetIndex); instr.SetPC(-1); Emit(instr); }