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);
			}