docs: def _compute_stacksize(self):
          """Get a code list, compute its maximal stack usage."""
          # This is done by scanning the code, and computing for each opcode
          # the stack state at the opcode.
          code = self.code
  
          # A mapping from labels to their positions in the code list
          label_pos = dict((op, pos)
                           for pos, (op, arg) in enumerate(code)
                           if isinstance(op, Label))
  
          # sf_targets are the targets of SETUP_FINALLY opcodes. They are recorded
          # because they have special stack behaviour. If an exception was raised
          # in the block pushed by a SETUP_FINALLY opcode, the block is popped
          # and 3 objects are pushed. On return or continue, the block is popped
          # and 2 objects are pushed. If nothing happened, the block is popped by
          # a POP_BLOCK opcode and 1 object is pushed by a (LOAD_CONST, None)
          # operation.
          #
          # Our solution is to record the stack state of SETUP_FINALLY targets
          # as having 3 objects pushed, which is the maximum. However, to make
          # stack recording consistent, the get_next_stacks function will always
          # yield the stack state of the target as if 1 object was pushed, but
          # this will be corrected in the actual stack recording.
  
          sf_targets = set(label_pos[arg]
                           for op, arg in code
                           if op == SETUP_FINALLY)
  
          # What we compute - for each opcode, its stack state, as an n-tuple.
          # n is the number of blocks pushed. For each block, we record the number
          # of objects pushed.
          stacks = [None] * len(code)
  
          def get_next_stacks(pos, curstack):
              """Get a code position and the stack state before the operation
              was done, and yield pairs (pos, curstack) for the next positions
              to be explored - those are the positions to which you can get
              from the given (pos, curstack).
  
              If the given position was already explored, nothing will be yielded.
              """
              op, arg = code[pos]
  
              if isinstance(op, Label):
                  # We should check if we already reached a node only if it is
                  # a label.
                  if pos in sf_targets:
                      curstack = curstack[:-1] + (curstack[-1] + 2,)
                  if stacks[pos] is None:
                      stacks[pos] = curstack
                  else:
                      if stacks[pos] != curstack:
                          raise ValueError("Inconsistent code")
                      return
  
              def newstack(n):
                  # Return a new stack, modified by adding n elements to the last
                  # block
                  if curstack[-1] + n < 0:
                      raise ValueError("Popped a non-existing element")
                  return curstack[:-1] + (curstack[-1]+n,)
  
              if not isopcode(op):
                  # label or SetLineno - just continue to next line
                  yield pos+1, curstack
  
              elif op in (STOP_CODE, RETURN_VALUE, RAISE_VARARGS):
                  # No place in particular to continue to
                  pass
  
              elif op == MAKE_CLOSURE and python_version == '2.4':
                  # This is only relevant in Python 2.4 - in Python 2.5 the stack
                  # effect of MAKE_CLOSURE can be calculated from the arg.
                  # In Python 2.4, it depends on the number of freevars of TOS,
                  # which should be a code object.
                  if pos == 0:
                      raise ValueError("MAKE_CLOSURE can't be the first opcode")
                  lastop, lastarg = code[pos-1]
                  if lastop != LOAD_CONST:
                      raise ValueError(
                          "MAKE_CLOSURE should come after a LOAD_CONST op")
                  try:
                      nextrapops = len(lastarg.freevars)
                  except AttributeError:
                      try:
                          nextrapops = len(lastarg.co_freevars)
                      except AttributeError:
                          raise ValueError(
                              "MAKE_CLOSURE preceding const should "
                              "be a code or a Code object")
  
                  yield pos+1, newstack(-arg-nextrapops)
  
              elif op not in hasflow:
                  # Simple change of stack
                  pop, push = getse(op, arg)
                  yield pos+1, newstack(push - pop)
  
              elif op in (JUMP_FORWARD, JUMP_ABSOLUTE):
                  # One possibility for a jump
                  yield label_pos[arg], curstack
  
              elif python_version < '2.7' and op in (JUMP_IF_FALSE, JUMP_IF_TRUE):
                  # Two possibilities for a jump
                  yield label_pos[arg], curstack
                  yield pos+1, curstack
  
              elif python_version >= '2.7' and op in (POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE):
                  # Two possibilities for a jump
                  yield label_pos[arg], newstack(-1)
                  yield pos+1, newstack(-1)
  
              elif python_version >= '2.7' and op in (JUMP_IF_TRUE_OR_POP, JUMP_IF_FALSE_OR_POP):
                  # Two possibilities for a jump
                  yield label_pos[arg], curstack
                  yield pos+1, newstack(-1)
  
              elif op == FOR_ITER:
                  # FOR_ITER pushes next(TOS) on success, and pops TOS and jumps
                  # on failure
                  yield label_pos[arg], newstack(-1)
                  yield pos+1, newstack(1)
  
              elif op == BREAK_LOOP:
                  # BREAK_LOOP jumps to a place specified on block creation, so
                  # it is ignored here
                  pass
  
              elif op == CONTINUE_LOOP:
                  # CONTINUE_LOOP jumps to the beginning of a loop which should
                  # already ave been discovered, but we verify anyway.
                  # It pops a block.
                  if python_version == '2.6':
                    pos, stack = label_pos[arg], curstack[:-1]
                    if stacks[pos] != stack: #this could be a loop with a 'with' inside
                      yield pos, stack[:-1] + (stack[-1]-1,)
                    else:
                      yield pos, stack
                  else:
                    yield label_pos[arg], curstack[:-1]
  
              elif op == SETUP_LOOP:
                  # We continue with a new block.
                  # On break, we jump to the label and return to current stack
                  # state.
                  yield label_pos[arg], curstack
                  yield pos+1, curstack + (0,)
  
              elif op == SETUP_EXCEPT:
                  # We continue with a new block.
                  # On exception, we jump to the label with 3 extra objects on
                  # stack
                  yield label_pos[arg], newstack(3)
                  yield pos+1, curstack + (0,)
  
              elif op == SETUP_FINALLY:
                  # We continue with a new block.
                  # On exception, we jump to the label with 3 extra objects on
                  # stack, but to keep stack recording consistent, we behave as
                  # if we add only 1 object. Extra 2 will be added to the actual
                  # recording.
                  yield label_pos[arg], newstack(1)
                  yield pos+1, curstack + (0,)
  
              elif python_version == '2.7' and op == SETUP_WITH:
                  yield label_pos[arg], curstack
                  yield pos+1, newstack(-1) + (1,)
  
              elif op == POP_BLOCK:
                  # Just pop the block
                  yield pos+1, curstack[:-1]
  
              elif op == END_FINALLY:
                  # Since stack recording of SETUP_FINALLY targets is of 3 pushed
                  # objects (as when an exception is raised), we pop 3 objects.
                  yield pos+1, newstack(-3)
  
              elif op == WITH_CLEANUP:
                  # Since WITH_CLEANUP is always found after SETUP_FINALLY
                  # targets, and the stack recording is that of a raised
                  # exception, we can simply pop 1 object and let END_FINALLY
                  # pop the remaining 3.
                  if python_version == '2.7':
                    yield pos+1, newstack(2)
                  else:
                    yield pos+1, newstack(-1)
  
              else:
                  assert False, "Unhandled opcode: %r" % op
  
  
          # Now comes the calculation: open_positions holds positions which are
          # yet to be explored. In each step we take one open position, and
          # explore it by adding the positions to which you can get from it, to
          # open_positions. On the way, we update maxsize.
          # open_positions is a list of tuples: (pos, stack state)
          maxsize = 0
          open_positions = [(0, (0,))]
          while open_positions:
              pos, curstack = open_positions.pop()
              maxsize = max(maxsize, sum(curstack))
              open_positions.extend(get_next_stacks(pos, curstack))
  
          return maxsize