public void processBlock(BasicBlockStatement stat, PrimitiveExpressionList data, StructClass cl) {
    ConstantPool pool = cl.getPool();
    StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
    BasicBlock block = stat.getBlock();
    ExpressionStack stack = data.getStack();
    List<Exprent> exprList = data.getExpressions();
    InstructionSequence seq = block.getSeq();

    for (int i = 0; i < seq.length(); i++) {
      Instruction instr = seq.getInstr(i);
      Integer offset = block.getOriginalOffset(i);
      Set<Integer> offsets = offset >= 0 ? Set.of(offset) : null;

      switch (instr.opcode) {
        case CodeConstants.opc_aconst_null:
          pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_NULL, null, offsets));
          break;
        case CodeConstants.opc_bipush:
        case CodeConstants.opc_sipush:
          pushEx(stack, exprList, new ConstExprent(instr.operand(0), true, offsets));
          break;
        case CodeConstants.opc_lconst_0:
        case CodeConstants.opc_lconst_1:
          pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_LONG, (long)(instr.opcode - CodeConstants.opc_lconst_0), offsets));
          break;
        case CodeConstants.opc_fconst_0:
        case CodeConstants.opc_fconst_1:
        case CodeConstants.opc_fconst_2:
          pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_FLOAT, (float)(instr.opcode - CodeConstants.opc_fconst_0), offsets));
          break;
        case CodeConstants.opc_dconst_0:
        case CodeConstants.opc_dconst_1:
          pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_DOUBLE, (double)(instr.opcode - CodeConstants.opc_dconst_0), offsets));
          break;
        case CodeConstants.opc_ldc:
        case CodeConstants.opc_ldc_w:
        case CodeConstants.opc_ldc2_w: {
          PooledConstant cn = pool.getConstant(instr.operand(0));
          if (cn instanceof PrimitiveConstant) {
            pushEx(stack, exprList, new ConstExprent(constants[cn.type - CodeConstants.CONSTANT_Integer], ((PrimitiveConstant)cn).value, offsets));
          }
          else if (cn instanceof LinkConstant) {
            //TODO: for now treat Links as Strings
            pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_STRING, ((LinkConstant)cn).elementName, offsets));
          }
          break;
        }
        case CodeConstants.opc_iload:
        case CodeConstants.opc_lload:
        case CodeConstants.opc_fload:
        case CodeConstants.opc_dload:
        case CodeConstants.opc_aload:
          pushEx(stack, exprList, new VarExprent(instr.operand(0), varTypes[instr.opcode - CodeConstants.opc_iload], varProcessor, offset));
          break;
        case CodeConstants.opc_iaload:
        case CodeConstants.opc_laload:
        case CodeConstants.opc_faload:
        case CodeConstants.opc_daload:
        case CodeConstants.opc_aaload:
        case CodeConstants.opc_baload:
        case CodeConstants.opc_caload:
        case CodeConstants.opc_saload: {
          Exprent index = stack.pop();
          Exprent arr = stack.pop();
          VarType type = instr.opcode == CodeConstants.opc_laload ? VarType.VARTYPE_LONG : instr.opcode == CodeConstants.opc_daload ? VarType.VARTYPE_DOUBLE : null;
          pushEx(stack, exprList, new ArrayExprent(arr, index, arrTypes[instr.opcode - CodeConstants.opc_iaload], offsets), type);
          break;
        }
        case CodeConstants.opc_istore:
        case CodeConstants.opc_lstore:
        case CodeConstants.opc_fstore:
        case CodeConstants.opc_dstore:
        case CodeConstants.opc_astore: {
          Exprent value = stack.pop();
          int varIndex = instr.operand(0);
          VarExprent left = new VarExprent(varIndex, varTypes[instr.opcode - CodeConstants.opc_istore], varProcessor, nextMeaningfulOffset(block, i));
          exprList.add(new AssignmentExprent(left, value, offsets));
          break;
        }
        case CodeConstants.opc_iastore:
        case CodeConstants.opc_lastore:
        case CodeConstants.opc_fastore:
        case CodeConstants.opc_dastore:
        case CodeConstants.opc_aastore:
        case CodeConstants.opc_bastore:
        case CodeConstants.opc_castore:
        case CodeConstants.opc_sastore: {
          Exprent value = stack.pop();
          Exprent index = stack.pop();
          Exprent array = stack.pop();
          ArrayExprent left = new ArrayExprent(array, index, arrTypes[instr.opcode - CodeConstants.opc_iastore], offsets);
          exprList.add(new AssignmentExprent(left, value, offsets));
          break;
        }
        case CodeConstants.opc_iadd:
        case CodeConstants.opc_ladd:
        case CodeConstants.opc_fadd:
        case CodeConstants.opc_dadd:
        case CodeConstants.opc_isub:
        case CodeConstants.opc_lsub:
        case CodeConstants.opc_fsub:
        case CodeConstants.opc_dsub:
        case CodeConstants.opc_imul:
        case CodeConstants.opc_lmul:
        case CodeConstants.opc_fmul:
        case CodeConstants.opc_dmul:
        case CodeConstants.opc_idiv:
        case CodeConstants.opc_ldiv:
        case CodeConstants.opc_fdiv:
        case CodeConstants.opc_ddiv:
        case CodeConstants.opc_irem:
        case CodeConstants.opc_lrem:
        case CodeConstants.opc_frem:
        case CodeConstants.opc_drem:
          pushEx(stack, exprList, new FunctionExprent(func1[(instr.opcode - CodeConstants.opc_iadd) / 4], stack, offsets));
          break;
        case CodeConstants.opc_ishl:
        case CodeConstants.opc_lshl:
        case CodeConstants.opc_ishr:
        case CodeConstants.opc_lshr:
        case CodeConstants.opc_iushr:
        case CodeConstants.opc_lushr:
        case CodeConstants.opc_iand:
        case CodeConstants.opc_land:
        case CodeConstants.opc_ior:
        case CodeConstants.opc_lor:
        case CodeConstants.opc_ixor:
        case CodeConstants.opc_lxor:
          pushEx(stack, exprList, new FunctionExprent(func2[(instr.opcode - CodeConstants.opc_ishl) / 2], stack, offsets));
          break;
        case CodeConstants.opc_ineg:
        case CodeConstants.opc_lneg:
        case CodeConstants.opc_fneg:
        case CodeConstants.opc_dneg:
          pushEx(stack, exprList, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack, offsets));
          break;
        case CodeConstants.opc_iinc: {
          VarExprent varExpr = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor);
          int type = instr.operand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD;
          List<Exprent> operands = Arrays.asList(varExpr.copy(), new ConstExprent(VarType.VARTYPE_INT, Math.abs(instr.operand(1)), null));
          exprList.add(new AssignmentExprent(varExpr, new FunctionExprent(type, operands, offsets), offsets));
          break;
        }
        case CodeConstants.opc_i2l:
        case CodeConstants.opc_i2f:
        case CodeConstants.opc_i2d:
        case CodeConstants.opc_l2i:
        case CodeConstants.opc_l2f:
        case CodeConstants.opc_l2d:
        case CodeConstants.opc_f2i:
        case CodeConstants.opc_f2l:
        case CodeConstants.opc_f2d:
        case CodeConstants.opc_d2i:
        case CodeConstants.opc_d2l:
        case CodeConstants.opc_d2f:
        case CodeConstants.opc_i2b:
        case CodeConstants.opc_i2c:
        case CodeConstants.opc_i2s:
          pushEx(stack, exprList, new FunctionExprent(func3[instr.opcode - CodeConstants.opc_i2l], stack, offsets));
          break;
        case CodeConstants.opc_lcmp:
        case CodeConstants.opc_fcmpl:
        case CodeConstants.opc_fcmpg:
        case CodeConstants.opc_dcmpl:
        case CodeConstants.opc_dcmpg:
          pushEx(stack, exprList, new FunctionExprent(func4[instr.opcode - CodeConstants.opc_lcmp], stack, offsets));
          break;
        case CodeConstants.opc_ifeq:
        case CodeConstants.opc_ifne:
        case CodeConstants.opc_iflt:
        case CodeConstants.opc_ifge:
        case CodeConstants.opc_ifgt:
        case CodeConstants.opc_ifle:
          exprList.add(new IfExprent(negIfs[func5[instr.opcode - CodeConstants.opc_ifeq]], stack, offsets));
          break;
        case CodeConstants.opc_if_icmpeq:
        case CodeConstants.opc_if_icmpne:
        case CodeConstants.opc_if_icmplt:
        case CodeConstants.opc_if_icmpge:
        case CodeConstants.opc_if_icmpgt:
        case CodeConstants.opc_if_icmple:
        case CodeConstants.opc_if_acmpeq:
        case CodeConstants.opc_if_acmpne:
          exprList.add(new IfExprent(negIfs[func6[instr.opcode - CodeConstants.opc_if_icmpeq]], stack, offsets));
          break;
        case CodeConstants.opc_ifnull:
        case CodeConstants.opc_ifnonnull:
          exprList.add(new IfExprent(negIfs[func7[instr.opcode - CodeConstants.opc_ifnull]], stack, offsets));
          break;
        case CodeConstants.opc_tableswitch:
        case CodeConstants.opc_lookupswitch:
          exprList.add(new SwitchExprent(stack.pop(), offsets));
          break;
        case CodeConstants.opc_ireturn:
        case CodeConstants.opc_lreturn:
        case CodeConstants.opc_freturn:
        case CodeConstants.opc_dreturn:
        case CodeConstants.opc_areturn:
        case CodeConstants.opc_return:
        case CodeConstants.opc_athrow:
          exprList.add(new ExitExprent(instr.opcode == CodeConstants.opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN,
                                       instr.opcode == CodeConstants.opc_return ? null : stack.pop(),
                                       instr.opcode == CodeConstants.opc_athrow ? null : methodDescriptor.ret,
                                       offsets));
          break;
        case CodeConstants.opc_monitorenter:
        case CodeConstants.opc_monitorexit:
          exprList.add(new MonitorExprent(func8[instr.opcode - CodeConstants.opc_monitorenter], stack.pop(), offsets));
          break;
        case CodeConstants.opc_checkcast:
        case CodeConstants.opc_instanceof:
          stack.push(new ConstExprent(new VarType(pool.getPrimitiveConstant(instr.operand(0)).getString(), true), null, null));
        case CodeConstants.opc_arraylength:
          pushEx(stack, exprList, new FunctionExprent(functionMap.get(instr.opcode), stack, offsets));
          break;
        case CodeConstants.opc_getstatic:
        case CodeConstants.opc_getfield:
          pushEx(stack, exprList,
                 new FieldExprent(pool.getLinkConstant(instr.operand(0)), instr.opcode == CodeConstants.opc_getstatic ? null : stack.pop(), offsets));
          break;
        case CodeConstants.opc_putstatic:
        case CodeConstants.opc_putfield:
          Exprent valField = stack.pop();
          Exprent exprField =
            new FieldExprent(pool.getLinkConstant(instr.operand(0)), instr.opcode == CodeConstants.opc_putstatic ? null : stack.pop(), offsets);
          exprList.add(new AssignmentExprent(exprField, valField, offsets));
          break;
        case CodeConstants.opc_invokevirtual:
        case CodeConstants.opc_invokespecial:
        case CodeConstants.opc_invokestatic:
        case CodeConstants.opc_invokeinterface:
        case CodeConstants.opc_invokedynamic:
          if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecodeVersion >= CodeConstants.BYTECODE_JAVA_7) {
            LinkConstant invoke_constant = pool.getLinkConstant(instr.operand(0));

            List<PooledConstant> bootstrap_arguments = null;
            if (instr.opcode == CodeConstants.opc_invokedynamic && bootstrap != null) {
              bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
            }

            InvocationExprent exprInv = new InvocationExprent(instr.opcode, invoke_constant, bootstrap_arguments, stack, offsets);
            if (exprInv.getDescriptor().ret.getType() == CodeConstants.TYPE_VOID) {
              exprList.add(exprInv);
            }
            else {
              pushEx(stack, exprList, exprInv);
            }
          }
          break;
        case CodeConstants.opc_new:
        case CodeConstants.opc_anewarray:
        case CodeConstants.opc_multianewarray:
          int dimensions = (instr.opcode == CodeConstants.opc_new) ? 0 : (instr.opcode == CodeConstants.opc_anewarray) ? 1 : instr.operand(1);
          VarType arrType = new VarType(pool.getPrimitiveConstant(instr.operand(0)).getString(), true);
          if (instr.opcode != CodeConstants.opc_multianewarray) {
            arrType = arrType.resizeArrayDim(arrType.getArrayDim() + dimensions);
          }
          pushEx(stack, exprList, new NewExprent(arrType, stack, dimensions, offsets));
          break;
        case CodeConstants.opc_newarray:
          pushEx(stack, exprList, new NewExprent(new VarType(arrTypeIds[instr.operand(0) - 4], 1), stack, 1, offsets));
          break;
        case CodeConstants.opc_dup:
          pushEx(stack, exprList, stack.getByOffset(-1).copy());
          break;
        case CodeConstants.opc_dup_x1:
          insertByOffsetEx(-2, stack, exprList, -1);
          break;
        case CodeConstants.opc_dup_x2:
          if (stack.getByOffset(-2).getExprType().getStackSize() == 2) {
            insertByOffsetEx(-2, stack, exprList, -1);
          }
          else {
            insertByOffsetEx(-3, stack, exprList, -1);
          }
          break;
        case CodeConstants.opc_dup2:
          if (stack.getByOffset(-1).getExprType().getStackSize() == 2) {
            pushEx(stack, exprList, stack.getByOffset(-1).copy());
          }
          else {
            pushEx(stack, exprList, stack.getByOffset(-2).copy());
            pushEx(stack, exprList, stack.getByOffset(-2).copy());
          }
          break;
        case CodeConstants.opc_dup2_x1:
          if (stack.getByOffset(-1).getExprType().getStackSize() == 2) {
            insertByOffsetEx(-2, stack, exprList, -1);
          }
          else {
            insertByOffsetEx(-3, stack, exprList, -2);
            insertByOffsetEx(-3, stack, exprList, -1);
          }
          break;
        case CodeConstants.opc_dup2_x2:
          if (stack.getByOffset(-1).getExprType().getStackSize() == 2) {
            if (stack.getByOffset(-2).getExprType().getStackSize() == 2) {
              insertByOffsetEx(-2, stack, exprList, -1);
            }
            else {
              insertByOffsetEx(-3, stack, exprList, -1);
            }
          }
          else {
            if (stack.getByOffset(-3).getExprType().getStackSize() == 2) {
              insertByOffsetEx(-3, stack, exprList, -2);
              insertByOffsetEx(-3, stack, exprList, -1);
            }
            else {
              insertByOffsetEx(-4, stack, exprList, -2);
              insertByOffsetEx(-4, stack, exprList, -1);
            }
          }
          break;
        case CodeConstants.opc_swap:
          insertByOffsetEx(-2, stack, exprList, -1);
          stack.pop();
          break;
        case CodeConstants.opc_pop:
          stack.pop();
          break;
        case CodeConstants.opc_pop2:
          if (stack.getByOffset(-1).getExprType().getStackSize() == 1) {
            // Since the value at the top of the stack is a value of category 1 (JVMS9 2.11.1),
            // we should remove one more item from the stack.
            // See JVMS9 pop2 chapter.
            stack.pop();
          }
          stack.pop();
          break;
      }
    }
  }
public void processBlock(BasicBlockStatement stat, PrimitiveExpressionList data, StructClass cl)