@Override
  void write(MethodWriter function, Globals globals) {
    if (reserved.getMaxLoopCounter() > 0) {
      // if there is infinite loop protection, we do this once:
      // int #loop = settings.getMaxLoopCounter()
      function.push(reserved.getMaxLoopCounter());
      function.visitVarInsn(Opcodes.ISTORE, loop.getSlot());
    }

    for (AStatement statement : statements) {
      statement.write(function, globals);
    }

    if (!methodEscape) {
      if (rtnType.sort == Sort.VOID) {
        function.returnValue();
      } else {
        throw createError(new IllegalStateException("Illegal tree structure."));
      }
    }

    String staticHandleFieldName = Def.getUserFunctionHandleFieldName(name, parameters.size());
    globals.addConstantInitializer(
        new Constant(
            location,
            WriterConstants.METHOD_HANDLE_TYPE,
            staticHandleFieldName,
            this::initializeConstant));
  }
  @Override
  void analyze(Locals locals) {
    if (statements == null || statements.isEmpty()) {
      throw createError(
          new IllegalArgumentException("Cannot generate an empty function [" + name + "]."));
    }

    locals = Locals.newLocalScope(locals);

    AStatement last = statements.get(statements.size() - 1);

    for (AStatement statement : statements) {
      // Note that we do not need to check after the last statement because
      // there is no statement that can be unreachable after the last.
      if (allEscape) {
        throw createError(new IllegalArgumentException("Unreachable statement."));
      }

      statement.lastSource = statement == last;

      statement.analyze(locals);

      methodEscape = statement.methodEscape;
      allEscape = statement.allEscape;
    }

    if (!methodEscape && rtnType.sort != Sort.VOID) {
      throw createError(
          new IllegalArgumentException(
              "Not all paths provide a return value for method [" + name + "]."));
    }

    if (reserved.getMaxLoopCounter() > 0) {
      loop = locals.getVariable(null, FunctionReserved.LOOP);
    }
  }