private void advanceAndSchedule(
      IntList next, int threadId, int pointer, int inputIndex, Runtime runtime) {
    Instruction instruction = program.at(pointer);
    switch (instruction.type()) {
      case MATCH_START:
        if (inputIndex == 0 && runtime.matchingAtPartitionStart) {
          advanceAndSchedule(next, threadId, pointer + 1, inputIndex, runtime);
        } else {
          runtime.scheduleKill(threadId);
        }
        break;
      case MATCH_END:
        if (inputIndex == runtime.inputLength) {
          advanceAndSchedule(next, threadId, pointer + 1, inputIndex, runtime);
        } else {
          runtime.scheduleKill(threadId);
        }
        break;
      case JUMP:
        advanceAndSchedule(next, threadId, ((Jump) instruction).getTarget(), inputIndex, runtime);
        break;
      case SPLIT:
        int forked = runtime.forkThread(threadId);
        advanceAndSchedule(next, threadId, ((Split) instruction).getFirst(), inputIndex, runtime);
        advanceAndSchedule(next, forked, ((Split) instruction).getSecond(), inputIndex, runtime);
        break;
      case SAVE:
        runtime.patternCaptures.save(threadId, inputIndex);
        advanceAndSchedule(next, threadId, pointer + 1, inputIndex, runtime);
        break;
      default: // MATCH_LABEL or DONE
        runtime.threads.set(threadId, pointer);
        next.add(threadId);
        break;
    }
  }
For a particular thread identified by `threadId`, process consecutive instructions of the
program, from the instruction at `pointer` up to the next instruction which consumes a label or
to the program end. The resulting thread state (the pointer of the first not processed
instruction) is recorded in `next`. There might be multiple threads recorded in `next`, as a
result of the instruction `SPLIT`.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/rowpattern/matcher/Matcher.java