/** * \brief Run the program for the given literal ID, with the interpreter * out of line. * * Assumes not in_anchored. */ static really_inline hwlmcb_rv_t roseProcessMatch(const struct RoseEngine *t, struct hs_scratch *scratch, u64a end, size_t match_len, u32 id) { DEBUG_PRINTF("id=%u\n", id); const u32 *programs = getByOffset(t, t->litProgramOffset); assert(id < t->literalCount); const u64a som = 0; const u8 flags = 0; return roseRunProgram(t, scratch, programs[id], som, end, match_len, flags); }
int roseAnchoredCallback(u64a start, u64a end, u32 id, void *ctx) { struct hs_scratch *scratch = ctx; assert(scratch && scratch->magic == SCRATCH_MAGIC); struct RoseContext *tctxt = &scratch->tctxt; struct core_info *ci = &scratch->core_info; const struct RoseEngine *t = ci->rose; u64a real_end = ci->buf_offset + end; // index after last byte DEBUG_PRINTF("MATCH id=%u offsets=[???,%llu]\n", id, real_end); DEBUG_PRINTF("STATE groups=0x%016llx\n", tctxt->groups); if (can_stop_matching(scratch)) { DEBUG_PRINTF("received a match when we're already dead!\n"); return MO_HALT_MATCHING; } const size_t match_len = 0; /* delayed literals need to be delivered before real literals; however * delayed literals only come from the floating table so if we are going * to deliver a literal here it must be too early for a delayed literal */ /* no history checks from anchored region and we are before the flush * boundary */ if (real_end <= t->floatingMinLiteralMatchOffset) { roseFlushLastByteHistory(t, scratch, real_end); tctxt->lastEndOffset = real_end; } const u32 *programs = getByOffset(t, t->litProgramOffset); assert(id < t->literalCount); const u8 flags = ROSE_PROG_FLAG_IN_ANCHORED; if (roseRunProgram(t, scratch, programs[id], start, real_end, match_len, flags) == HWLM_TERMINATE_MATCHING) { assert(can_stop_matching(scratch)); DEBUG_PRINTF("caller requested termination\n"); return MO_HALT_MATCHING; } DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups); if (real_end > t->floatingMinLiteralMatchOffset) { recordAnchoredLiteralMatch(t, scratch, id, real_end); } return MO_CONTINUE_MATCHING; }
/** * \brief Match callback adaptor used for matches from pure-literal cases. * * Literal match IDs in this path run limited Rose programs that do not use * Rose state (which is not initialised in the pure-literal path). They can * still, for example, check lookarounds or literal masks. */ hwlmcb_rv_t rosePureLiteralCallback(size_t start, size_t end, u32 id, void *context) { DEBUG_PRINTF("start=%zu, end=%zu, id=%u\n", start, end, id); struct hs_scratch *scratch = context; struct core_info *ci = &scratch->core_info; const u64a real_end = (u64a)end + ci->buf_offset + 1; const u64a som = 0; const size_t match_len = end - start + 1; const struct RoseEngine *rose = ci->rose; const u32 *programs = getByOffset(rose, rose->litProgramOffset); assert(id < rose->literalCount); const u8 flags = 0; return roseRunProgram(rose, scratch, programs[id], som, real_end, match_len, flags); }
int roseReportAdaptor(u64a start, u64a end, ReportID id, void *context) { struct hs_scratch *scratch = context; assert(scratch && scratch->magic == SCRATCH_MAGIC); DEBUG_PRINTF("id=%u matched at [%llu,%llu]\n", id, start, end); const struct RoseEngine *rose = scratch->core_info.rose; // Our match ID is the program offset. const u32 program = id; const size_t match_len = 0; // Unused in this path. const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP; hwlmcb_rv_t rv = roseRunProgram(rose, scratch, program, start, end, match_len, flags); if (rv == HWLM_TERMINATE_MATCHING) { return MO_HALT_MATCHING; } return can_stop_matching(scratch) ? MO_HALT_MATCHING : MO_CONTINUE_MATCHING; }
void roseStreamEodExec(const struct RoseEngine *t, u64a offset, struct hs_scratch *scratch) { assert(scratch); assert(t->requiresEodCheck); DEBUG_PRINTF("ci buf %p/%zu his %p/%zu\n", scratch->core_info.buf, scratch->core_info.len, scratch->core_info.hbuf, scratch->core_info.hlen); // We should not have been called if we've already been told to terminate // matching. assert(!told_to_stop_matching(scratch)); if (t->maxBiAnchoredWidth != ROSE_BOUND_INF && offset > t->maxBiAnchoredWidth) { DEBUG_PRINTF("bailing, we are beyond max width\n"); /* also some of the history/state may be stale */ return; } if (!t->eodProgramOffset) { DEBUG_PRINTF("no eod program\n"); return; } roseStreamInitEod(t, offset, scratch); DEBUG_PRINTF("running eod program at %u\n", t->eodProgramOffset); // There should be no pending delayed literals. assert(!scratch->tctxt.filledDelayedSlots); const u64a som = 0; const size_t match_len = 0; const u8 flags = ROSE_PROG_FLAG_SKIP_MPV_CATCHUP; // Note: we ignore the result, as this is the last thing to ever happen on // a scan. roseRunProgram(t, scratch, t->eodProgramOffset, som, offset, match_len, flags); }
hwlmcb_rv_t roseDelayRebuildCallback(size_t start, size_t end, u32 id, void *ctx) { struct hs_scratch *scratch = ctx; struct RoseContext *tctx = &scratch->tctxt; struct core_info *ci = &scratch->core_info; const struct RoseEngine *t = ci->rose; size_t rb_len = MIN(ci->hlen, t->delayRebuildLength); u64a real_end = ci->buf_offset - rb_len + end + 1; // index after last byte #ifdef DEBUG DEBUG_PRINTF("REBUILD MATCH id=%u offsets=[%llu,%llu]: ", id, start + ci->buf_offset - rb_len, real_end); printMatch(ci, start + ci->buf_offset - rb_len, real_end); printf("\n"); #endif DEBUG_PRINTF("STATE groups=0x%016llx\n", tctx->groups); const u32 *delayRebuildPrograms = getByOffset(t, t->litDelayRebuildProgramOffset); assert(id < t->literalCount); const u32 program = delayRebuildPrograms[id]; if (program) { const u64a som = 0; const size_t match_len = end - start + 1; const u8 flags = 0; UNUSED hwlmcb_rv_t rv = roseRunProgram(t, scratch, program, som, real_end, match_len, flags); assert(rv != HWLM_TERMINATE_MATCHING); } /* we are just repopulating the delay queue, groups should be * already set from the original scan. */ return tctx->groups; }
/** * \brief Execute a boundary report program. * * Returns MO_HALT_MATCHING if the stream is exhausted or the user has * instructed us to halt, or MO_CONTINUE_MATCHING otherwise. */ int roseRunBoundaryProgram(const struct RoseEngine *rose, u32 program, u64a stream_offset, struct hs_scratch *scratch) { DEBUG_PRINTF("running boundary program at offset %u\n", program); if (can_stop_matching(scratch)) { DEBUG_PRINTF("can stop matching\n"); return MO_HALT_MATCHING; } if (rose->hasSom && scratch->deduper.current_report_offset == ~0ULL) { /* we cannot delay the initialization of the som deduper logs any longer * as we are reporting matches. This is done explicitly as we are * shortcutting the som handling in the vacuous repeats as we know they * all come from non-som patterns. */ fatbit_clear(scratch->deduper.som_log[0]); fatbit_clear(scratch->deduper.som_log[1]); scratch->deduper.som_log_dirty = 0; } // Keep assertions in program report path happy. At offset zero, there can // have been no earlier reports. At EOD, all earlier reports should have // been handled and we will have been caught up to the stream offset by the // time we are running boundary report programs. scratch->tctxt.minMatchOffset = stream_offset; const u64a som = 0; const size_t match_len = 0; const u8 flags = 0; hwlmcb_rv_t rv = roseRunProgram(rose, scratch, program, som, stream_offset, match_len, flags); if (rv == HWLM_TERMINATE_MATCHING) { return MO_HALT_MATCHING; } return MO_CONTINUE_MATCHING; }