return MO_CONTINUE_MATCHING;
}
-/**
- * \brief Check for (and deliver) reports from active output-exposed (suffix
- * or outfix) NFAs.
- *
- * \return MO_HALT_MATCHING if the user instructs us to stop.
- */
-static rose_inline
-int roseCheckNfaEod(const struct RoseEngine *t, struct hs_scratch *scratch,
- u64a offset, const char is_streaming) {
- if (!t->eodNfaIterOffset) {
- DEBUG_PRINTF("no engines that report at EOD\n");
- return MO_CONTINUE_MATCHING;
- }
-
- /* data, len is used for state decompress, should be full available data */
- u8 key = 0;
- if (is_streaming) {
- const u8 *eod_data = scratch->core_info.hbuf;
- size_t eod_len = scratch->core_info.hlen;
- key = eod_len ? eod_data[eod_len - 1] : 0;
- }
-
- const u8 *aa = getActiveLeafArray(t, scratch->core_info.state);
- const u32 aaCount = t->activeArrayCount;
-
- const struct mmbit_sparse_iter *it = getByOffset(t, t->eodNfaIterOffset);
- assert(ISALIGNED(it));
-
- u32 idx = 0;
- struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
-
- for (u32 qi = mmbit_sparse_iter_begin(aa, aaCount, &idx, it, si_state);
- qi != MMB_INVALID;
- qi = mmbit_sparse_iter_next(aa, aaCount, qi, &idx, it, si_state)) {
- const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
- const struct NFA *nfa = getNfaByInfo(t, info);
-
- DEBUG_PRINTF("checking nfa %u\n", qi);
- assert(nfaAcceptsEod(nfa));
-
- char *fstate = scratch->fullState + info->fullStateOffset;
- const char *sstate = scratch->core_info.state + info->stateOffset;
-
- if (is_streaming) {
- // Decompress stream state.
- nfaExpandState(nfa, fstate, sstate, offset, key);
- }
-
- if (nfaCheckFinalState(nfa, fstate, sstate, offset, roseReportAdaptor,
- roseReportSomAdaptor,
- scratch) == MO_HALT_MATCHING) {
- DEBUG_PRINTF("user instructed us to stop\n");
- return MO_HALT_MATCHING;
- }
- }
-
- return MO_CONTINUE_MATCHING;
-}
-
static rose_inline
void cleanupAfterEodMatcher(const struct RoseEngine *t, u64a offset,
struct hs_scratch *scratch) {
return;
}
- if (roseCheckNfaEod(t, scratch, offset, is_streaming) == MO_HALT_MATCHING) {
- return;
- }
-
if (!t->eodIterProgramOffset && !t->ematcherOffset) {
DEBUG_PRINTF("no eod accepts\n");
return;
return end >= min_bound && end <= max_bound;
}
+static rose_inline
+hwlmcb_rv_t roseEnginesEod(const struct RoseEngine *rose,
+ struct hs_scratch *scratch, u64a offset,
+ u32 iter_offset) {
+ const char is_streaming = rose->mode != HS_MODE_BLOCK;
+
+ /* data, len is used for state decompress, should be full available data */
+ u8 key = 0;
+ if (is_streaming) {
+ const u8 *eod_data = scratch->core_info.hbuf;
+ size_t eod_len = scratch->core_info.hlen;
+ key = eod_len ? eod_data[eod_len - 1] : 0;
+ }
+
+ const u8 *aa = getActiveLeafArray(rose, scratch->core_info.state);
+ const u32 aaCount = rose->activeArrayCount;
+
+ const struct mmbit_sparse_iter *it = getByOffset(rose, iter_offset);
+ assert(ISALIGNED(it));
+
+ u32 idx = 0;
+ struct mmbit_sparse_state si_state[MAX_SPARSE_ITER_STATES];
+
+ for (u32 qi = mmbit_sparse_iter_begin(aa, aaCount, &idx, it, si_state);
+ qi != MMB_INVALID;
+ qi = mmbit_sparse_iter_next(aa, aaCount, qi, &idx, it, si_state)) {
+ const struct NfaInfo *info = getNfaInfoByQueue(rose, qi);
+ const struct NFA *nfa = getNfaByInfo(rose, info);
+
+ DEBUG_PRINTF("checking nfa %u\n", qi);
+ assert(nfaAcceptsEod(nfa));
+
+ char *fstate = scratch->fullState + info->fullStateOffset;
+ const char *sstate = scratch->core_info.state + info->stateOffset;
+
+ if (is_streaming) {
+ // Decompress stream state.
+ nfaExpandState(nfa, fstate, sstate, offset, key);
+ }
+
+ if (nfaCheckFinalState(nfa, fstate, sstate, offset, roseReportAdaptor,
+ roseReportSomAdaptor,
+ scratch) == MO_HALT_MATCHING) {
+ DEBUG_PRINTF("user instructed us to stop\n");
+ return HWLM_TERMINATE_MATCHING;
+ }
+ }
+
+ return HWLM_CONTINUE_MATCHING;
+}
+
static
void updateSeqPoint(struct RoseContext *tctxt, u64a offset,
const char from_mpv) {
}
PROGRAM_NEXT_INSTRUCTION
+ PROGRAM_CASE(ENGINES_EOD) {
+ if (roseEnginesEod(t, scratch, end, ri->iter_offset) ==
+ HWLM_TERMINATE_MATCHING) {
+ return HWLM_TERMINATE_MATCHING;
+ }
+ }
+ PROGRAM_NEXT_INSTRUCTION
+
PROGRAM_CASE(END) {
DEBUG_PRINTF("finished\n");
return HWLM_CONTINUE_MATCHING;
case ROSE_INSTR_CHECK_STATE: return &u.checkState;
case ROSE_INSTR_SPARSE_ITER_BEGIN: return &u.sparseIterBegin;
case ROSE_INSTR_SPARSE_ITER_NEXT: return &u.sparseIterNext;
+ case ROSE_INSTR_ENGINES_EOD: return &u.enginesEod;
case ROSE_INSTR_END: return &u.end;
}
assert(0);
case ROSE_INSTR_CHECK_STATE: return sizeof(u.checkState);
case ROSE_INSTR_SPARSE_ITER_BEGIN: return sizeof(u.sparseIterBegin);
case ROSE_INSTR_SPARSE_ITER_NEXT: return sizeof(u.sparseIterNext);
+ case ROSE_INSTR_ENGINES_EOD: return sizeof(u.enginesEod);
case ROSE_INSTR_END: return sizeof(u.end);
}
assert(0);
ROSE_STRUCT_CHECK_STATE checkState;
ROSE_STRUCT_SPARSE_ITER_BEGIN sparseIterBegin;
ROSE_STRUCT_SPARSE_ITER_NEXT sparseIterNext;
+ ROSE_STRUCT_ENGINES_EOD enginesEod;
ROSE_STRUCT_END end;
} u;
* Returns the pair (program offset, sparse iter offset).
*/
static
-pair<u32, u32> makeSparseIterProgram(build_context &bc,
+vector<RoseInstruction> makeSparseIterProgram(build_context &bc,
map<u32, vector<vector<RoseInstruction>>> &predProgramLists,
const vector<RoseInstruction> &root_program,
const vector<RoseInstruction> &pre_program) {
// Add blocks to deal with non-root edges (triggered by sparse iterator or
// mmbit_isset checks). This operation will flatten the program up to this
// point.
- u32 iter_offset = addPredBlocks(bc, predProgramLists, program, false);
+ addPredBlocks(bc, predProgramLists, program, false);
// If we have a root program, replace the END instruction with it. Note
// that the root program has already been flattened.
program.insert(end(program), begin(root_program), end(root_program));
}
- applyFinalSpecialisation(program);
- return {writeProgram(bc, program), iter_offset};
+ return program;
}
static
}
static
-u32 buildLiteralProgram(RoseBuildImpl &build, build_context &bc, u32 final_id,
- const vector<RoseEdge> &lit_edges) {
+vector<RoseInstruction> buildLiteralProgram(RoseBuildImpl &build,
+ build_context &bc, u32 final_id,
+ const vector<RoseEdge> &lit_edges) {
const auto &g = build.g;
DEBUG_PRINTF("final id %u, %zu lit edges\n", final_id, lit_edges.size());
// Put it all together.
return makeSparseIterProgram(bc, predProgramLists, root_program,
- pre_program).first;
+ pre_program);
+}
+
+static
+u32 writeLiteralProgram(RoseBuildImpl &build, build_context &bc, u32 final_id,
+ const vector<RoseEdge> &lit_edges) {
+ auto program = buildLiteralProgram(build, bc, final_id, lit_edges);
+ if (program.empty()) {
+ return 0;
+ }
+ // Note: already flattened.
+ applyFinalSpecialisation(program);
+ return writeProgram(bc, program);
}
static
const auto &lit_edges = lit_edge_map[finalId];
litPrograms[finalId] =
- buildLiteralProgram(build, bc, finalId, lit_edges);
+ writeLiteralProgram(build, bc, finalId, lit_edges);
delayRebuildPrograms[finalId] =
buildDelayRebuildProgram(build, bc, finalId);
}
}
static
-u32 writeEodProgram(RoseBuildImpl &build, build_context &bc) {
- if (build.eod_event_literal_id == MO_INVALID_IDX) {
- return 0;
+u32 writeEodProgram(RoseBuildImpl &build, build_context &bc,
+ u32 eodNfaIterOffset) {
+ vector<RoseInstruction> program;
+
+ if (build.eod_event_literal_id != MO_INVALID_IDX) {
+ const RoseGraph &g = build.g;
+ const auto &lit_info =
+ build.literal_info.at(build.eod_event_literal_id);
+ assert(lit_info.delayed_ids.empty());
+ assert(!lit_info.squash_group);
+ assert(!lit_info.requires_benefits);
+
+ // Collect all edges leading into EOD event literal vertices.
+ vector<RoseEdge> edge_list;
+ for (const auto &v : lit_info.vertices) {
+ for (const auto &e : in_edges_range(v, g)) {
+ edge_list.push_back(e);
+ }
+ }
+
+ // Sort edge list for determinism, prettiness.
+ sort(begin(edge_list), end(edge_list),
+ [&g](const RoseEdge &a, const RoseEdge &b) {
+ return tie(g[source(a, g)].idx, g[target(a, g)].idx) <
+ tie(g[source(b, g)].idx, g[target(b, g)].idx);
+ });
+
+ program = buildLiteralProgram(build, bc, MO_INVALID_IDX, edge_list);
}
- const RoseGraph &g = build.g;
- const auto &lit_info = build.literal_info.at(build.eod_event_literal_id);
- assert(lit_info.delayed_ids.empty());
- assert(!lit_info.squash_group);
- assert(!lit_info.requires_benefits);
-
- // Collect all edges leading into EOD event literal vertices.
- vector<RoseEdge> edge_list;
- for (const auto &v : lit_info.vertices) {
- for (const auto &e : in_edges_range(v, g)) {
- edge_list.push_back(e);
+ if (eodNfaIterOffset) {
+ auto ri = RoseInstruction(ROSE_INSTR_ENGINES_EOD);
+ ri.u.enginesEod.iter_offset = eodNfaIterOffset;
+ if (!program.empty()) {
+ assert(program.back().code() == ROSE_INSTR_END);
+ program.pop_back();
}
+ program.push_back(move(ri));
+ program = flattenProgram({program});
}
- // Sort edge list for determinism, prettiness.
- sort(begin(edge_list), end(edge_list),
- [&g](const RoseEdge &a, const RoseEdge &b) {
- return tie(g[source(a, g)].idx, g[target(a, g)].idx) <
- tie(g[source(b, g)].idx, g[target(b, g)].idx);
- });
+ if (program.empty()) {
+ return 0;
+ }
- return buildLiteralProgram(build, bc, MO_INVALID_IDX, edge_list);
+ applyFinalSpecialisation(program);
+ return writeProgram(bc, program);
}
static
tie(litProgramOffset, litDelayRebuildProgramOffset) =
buildLiteralPrograms(*this, bc);
- u32 eodProgramOffset = writeEodProgram(*this, bc);
+ u32 eodProgramOffset = writeEodProgram(*this, bc, eodNfaIterOffset);
u32 eodIterProgramOffset;
u32 eodIterOffset;
tie(eodIterProgramOffset, eodIterOffset) = buildEodAnchorProgram(*this, bc);
engine->eodProgramOffset = eodProgramOffset;
engine->eodIterProgramOffset = eodIterProgramOffset;
engine->eodIterOffset = eodIterOffset;
- engine->eodNfaIterOffset = eodNfaIterOffset;
engine->lastByteHistoryIterOffset = lastByteOffset;