private void findSubroutineSuccessors(
		final int id,
		final Label[] JSRs,
		final int nJSRs){
	// iterates over all the basic blocks...
	Label l = labels;
	while(l != null)
		{
		// for those that belong to subroutine 'id'...
		if((l.status & id) != 0)
			{
			if((l.status & Label.JSR) != 0)
				{
				// finds the subroutine to which 'l' leads by following the
				// second edge of l.successors (see {@link #visitJumpInsn})
				int nId = l.successors.next.successor.status & ~0xFFF;
				if(nId != id)
					{
					// calls this method recursively with l pushed onto the
					// JSRs stack to find the successors of the RET blocks
					// of this nested subroutine 'nId'
					JSRs[nJSRs] = l;
					findSubroutineSuccessors(nId, JSRs, nJSRs + 1);
					}
				}
			else if((l.status & Label.RET) != 0)
				{
				/*
									 * finds the JSR block in the JSRs stack that corresponds to
									 * this RET block, and updates the successors of this RET
									 * block accordingly. This corresponding JSR is the one that
									 * leads to the subroutine to which the RET block belongs.
									 * But the RET block can belong to several subroutines (if a
									 * nested subroutine returns to its parent subroutine
									 * implicitely, without a RET). So, in fact, the JSR that
									 * corresponds to this RET is the first block in the JSRs
									 * stack, starting from the bottom of the stack, that leads
									 * to a subroutine to which the RET block belongs.
									 */
				for(int i = 0; i < nJSRs; ++i)
					{
					int JSRstatus = JSRs[i].successors.next.successor.status;
					if(((JSRstatus & ~0xFFF) & (l.status & ~0xFFF)) != 0)
						{
						Edge e = new Edge();
						e.info = l.inputStackTop;
						e.successor = JSRs[i].successors.successor;
						e.next = l.successors;
						l.successors = e;
						break;
						}
					}
				}
			}
		l = l.successor;
		}
}