rose: Use an interpreter for role runtime

Replace much of the RoseRole structure with an interpreted program,
simplifying the Rose runtime and making it much more flexible.
This commit is contained in:
Justin Viiret 2015-11-19 09:32:05 +11:00 committed by Matthew Barr
parent a7d8dafb71
commit 9cb2233589
14 changed files with 1682 additions and 1197 deletions

View File

@ -470,6 +470,7 @@ set (hs_exec_SRCS
src/rose/runtime.h
src/rose/rose.h
src/rose/rose_internal.h
src/rose/rose_program.h
src/rose/rose_types.h
src/rose/rose_common.h
src/util/bitutils.h

View File

@ -169,11 +169,12 @@ int roseEodRunIterator(const struct RoseEngine *t, u8 *state, u64a offset,
/* mark role as handled so we don't touch it again in this walk */
fatbit_set(handled_roles, t->roleCount, role);
DEBUG_PRINTF("fire report for role %u, report=%u\n", role,
tr->reportId);
int rv = scratch->tctxt.cb(offset, tr->reportId,
scratch->tctxt.userCtx);
if (rv == MO_HALT_MATCHING) {
u64a som = 0;
int work_done = 0;
hwlmcb_rv_t rv =
roseRunRoleProgram(t, tr->programOffset, offset, &som,
&(scratch->tctxt), &work_done);
if (rv == HWLM_TERMINATE_MATCHING) {
return MO_HALT_MATCHING;
}
}

View File

@ -31,6 +31,7 @@
#include "infix.h"
#include "match.h"
#include "miracle.h"
#include "rose_program.h"
#include "rose.h"
#include "som/som_runtime.h"
#include "util/bitutils.h"
@ -319,22 +320,18 @@ hwlmcb_rv_t ensureMpvQueueFlushed(const struct RoseEngine *t,
static rose_inline
hwlmcb_rv_t roseHandleSuffixTrigger(const struct RoseEngine *t,
const struct RoseRole *tr, u64a som,
u32 qi, u32 top, u64a som,
u64a end, struct RoseContext *tctxt,
char in_anchored) {
DEBUG_PRINTF("woot we have a mask/follower/suffix/... role\n");
DEBUG_PRINTF("suffix qi=%u, top event=%u\n", qi, top);
assert(tr->suffixOffset);
const struct NFA *nfa
= (const struct NFA *)((const char *)t + tr->suffixOffset);
u8 *aa = getActiveLeafArray(t, tctxt->state);
struct hs_scratch *scratch = tctxtToScratch(tctxt);
u32 aaCount = t->activeArrayCount;
u32 qCount = t->queueCount;
u32 qi = nfa->queueIndex;
const u32 aaCount = t->activeArrayCount;
const u32 qCount = t->queueCount;
struct mq *q = &scratch->queues[qi];
const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
const struct NFA *nfa = getNfaByInfo(t, info);
struct core_info *ci = &scratch->core_info;
s64a loc = (s64a)end - ci->buf_offset;
@ -368,7 +365,6 @@ hwlmcb_rv_t roseHandleSuffixTrigger(const struct RoseEngine *t,
}
}
u32 top = tr->suffixEvent;
assert(top == MQE_TOP || (top >= MQE_TOP_FIRST && top < MQE_INVALID));
pushQueueSom(q, top, loc, som);
@ -748,14 +744,12 @@ found_miracle:
return 1;
}
static rose_inline
char roseTestLeftfix(const struct RoseEngine *t, const struct RoseRole *tr,
u64a end, struct RoseContext *tctxt) {
static really_inline
char roseTestLeftfix(const struct RoseEngine *t, u32 qi, u32 leftfixLag,
ReportID leftfixReport, u64a end,
struct RoseContext *tctxt) {
struct hs_scratch *scratch = tctxtToScratch(tctxt);
struct core_info *ci = &scratch->core_info;
assert(tr->flags & ROSE_ROLE_FLAG_ROSE);
u32 qi = tr->leftfixQueue;
u32 ri = queueToLeftIndex(t, qi);
const struct LeftNfaInfo *left = getLeftTable(t) + ri;
@ -763,9 +757,9 @@ char roseTestLeftfix(const struct RoseEngine *t, const struct RoseRole *tr,
DEBUG_PRINTF("testing %s %s %u/%u with lag %u (maxLag=%u)\n",
(left->transient ? "transient" : "active"),
(left->infix ? "infix" : "prefix"),
ri, qi, tr->leftfixLag, left->maxLag);
ri, qi, leftfixLag, left->maxLag);
assert(tr->leftfixLag <= left->maxLag);
assert(leftfixLag <= left->maxLag);
struct mq *q = scratch->queues + qi;
u32 qCount = t->queueCount;
@ -776,7 +770,7 @@ char roseTestLeftfix(const struct RoseEngine *t, const struct RoseRole *tr,
return 0;
}
if (unlikely(end < tr->leftfixLag)) {
if (unlikely(end < leftfixLag)) {
assert(0); /* lag is the literal length */
return 0;
}
@ -816,9 +810,9 @@ char roseTestLeftfix(const struct RoseEngine *t, const struct RoseRole *tr,
}
}
s64a loc = (s64a)end - ci->buf_offset - tr->leftfixLag;
s64a loc = (s64a)end - ci->buf_offset - leftfixLag;
assert(loc >= q_cur_loc(q));
assert(tr->leftfixReport != MO_INVALID_IDX);
assert(leftfixReport != MO_INVALID_IDX);
if (left->transient) {
s64a start_loc = loc - left->transient;
@ -855,7 +849,7 @@ char roseTestLeftfix(const struct RoseEngine *t, const struct RoseRole *tr,
pushQueueNoMerge(q, MQE_END, loc);
char rv = nfaQueueExecRose(q->nfa, q, tr->leftfixReport);
char rv = nfaQueueExecRose(q->nfa, q, leftfixReport);
if (!rv) { /* nfa is dead */
DEBUG_PRINTF("leftfix %u died while trying to catch up\n", ri);
mmbit_unset(getActiveLeftArray(t, tctxt->state), arCount, ri);
@ -869,12 +863,12 @@ char roseTestLeftfix(const struct RoseEngine *t, const struct RoseRole *tr,
q->cur = q->end = 0;
pushQueueAt(q, 0, MQE_START, loc);
DEBUG_PRINTF("checking for report %u\n", tr->leftfixReport);
DEBUG_PRINTF("checking for report %u\n", leftfixReport);
DEBUG_PRINTF("leftfix done %hhd\n", (signed char)rv);
return rv == MO_MATCHES_PENDING;
} else {
DEBUG_PRINTF("checking for report %u\n", tr->leftfixReport);
char rv = nfaInAcceptState(q->nfa, tr->leftfixReport, q);
DEBUG_PRINTF("checking for report %u\n", leftfixReport);
char rv = nfaInAcceptState(q->nfa, leftfixReport, q);
DEBUG_PRINTF("leftfix done %hhd\n", (signed char)rv);
return rv;
}
@ -882,136 +876,84 @@ char roseTestLeftfix(const struct RoseEngine *t, const struct RoseRole *tr,
static rose_inline
void roseSetRole(const struct RoseEngine *t, u8 *state,
struct RoseContext *tctxt, const struct RoseRole *tr) {
DEBUG_PRINTF("set role %u on: idx=%u, depth=%u, groups=0x%016llx\n",
(u32)(tr - getRoleTable(t)),
tr->stateIndex, tr->depth, tr->groups);
void *role_state = getRoleState(state);
assert(tr < getRoleTable(t) + t->roleCount);
int leafNode = !!(tr->stateIndex == MMB_INVALID);
// If this role is a leaf node, it doesn't have a state index to switch
// on and it doesn't need any history stored or other work done. So we can
// bail.
/* may be a ghost role; still need to set groups */
if (leafNode) {
tctxt->groups |= tr->groups;
DEBUG_PRINTF("role %u is a leaf node, no work to do.\n",
(u32)(tr - getRoleTable(t)));
return;
}
// Switch this role on in the state bitvector, checking whether it was set
// already.
char alreadySet = mmbit_set(role_state, t->rolesWithStateCount,
tr->stateIndex);
// Roles that we've already seen have had most of their bookkeeping done:
// all we need to do is update the offset table if this is an
// offset-tracking role.
if (alreadySet) {
DEBUG_PRINTF("role already set\n");
return;
}
// If this role's depth is greater than the current depth, update it
update_depth(tctxt, tr);
// Switch on this role's groups
tctxt->groups |= tr->groups;
struct RoseContext *tctxt, u32 stateIndex, u8 depth) {
DEBUG_PRINTF("state idx=%u, depth=%u\n", stateIndex, depth);
mmbit_set(getRoleState(state), t->rolesWithStateCount, stateIndex);
update_depth(tctxt, depth);
}
static rose_inline
void roseTriggerInfixes(const struct RoseEngine *t, const struct RoseRole *tr,
u64a start, u64a end, struct RoseContext *tctxt) {
void roseTriggerInfix(const struct RoseEngine *t, u64a start, u64a end, u32 qi,
u32 topEvent, u8 cancel, struct RoseContext *tctxt) {
struct core_info *ci = &tctxtToScratch(tctxt)->core_info;
DEBUG_PRINTF("infix time! @%llu\t(s%llu)\n", end, start);
assert(tr->infixTriggerOffset);
u32 qCount = t->queueCount;
u32 arCount = t->activeLeftCount;
struct fatbit *aqa = tctxtToScratch(tctxt)->aqa;
u8 *activeLeftArray = getActiveLeftArray(t, tctxt->state);
s64a loc = (s64a)end - ci->buf_offset;
const struct RoseTrigger *curr_r = (const struct RoseTrigger *)
((const char *)t + tr->infixTriggerOffset);
assert(ISALIGNED_N(curr_r, alignof(struct RoseTrigger)));
assert(curr_r->queue != MO_INVALID_IDX); /* shouldn't be here if no
* triggers */
do {
u32 qi = curr_r->queue;
u32 ri = queueToLeftIndex(t, qi);
u32 topEvent = curr_r->event;
u8 cancel = curr_r->cancel_prev_top;
assert(topEvent < MQE_INVALID);
u32 ri = queueToLeftIndex(t, qi);
assert(topEvent < MQE_INVALID);
const struct LeftNfaInfo *left = getLeftInfoByQueue(t, qi);
assert(!left->transient);
const struct LeftNfaInfo *left = getLeftInfoByQueue(t, qi);
assert(!left->transient);
DEBUG_PRINTF("rose %u (qi=%u) event %u\n", ri, qi, topEvent);
DEBUG_PRINTF("rose %u (qi=%u) event %u\n", ri, qi, topEvent);
struct mq *q = tctxtToScratch(tctxt)->queues + qi;
const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
struct mq *q = tctxtToScratch(tctxt)->queues + qi;
const struct NfaInfo *info = getNfaInfoByQueue(t, qi);
char alive = mmbit_set(activeLeftArray, arCount, ri);
u8 *activeLeftArray = getActiveLeftArray(t, tctxt->state);
const u32 arCount = t->activeLeftCount;
char alive = mmbit_set(activeLeftArray, arCount, ri);
if (alive && info->no_retrigger) {
DEBUG_PRINTF("yawn\n");
goto next_infix;
}
if (alive && info->no_retrigger) {
DEBUG_PRINTF("yawn\n");
return;
}
if (alive && nfaSupportsZombie(getNfaByInfo(t, info)) && ci->buf_offset
&& !fatbit_isset(aqa, qCount, qi)
&& isZombie(t, tctxt->state, left)) {
DEBUG_PRINTF("yawn - zombie\n");
goto next_infix;
}
struct fatbit *aqa = tctxtToScratch(tctxt)->aqa;
const u32 qCount = t->queueCount;
if (cancel) {
DEBUG_PRINTF("dominating top: (re)init\n");
fatbit_set(aqa, qCount, qi);
initRoseQueue(t, qi, left, tctxt);
if (alive && nfaSupportsZombie(getNfaByInfo(t, info)) && ci->buf_offset &&
!fatbit_isset(aqa, qCount, qi) && isZombie(t, tctxt->state, left)) {
DEBUG_PRINTF("yawn - zombie\n");
return;
}
if (cancel) {
DEBUG_PRINTF("dominating top: (re)init\n");
fatbit_set(aqa, qCount, qi);
initRoseQueue(t, qi, left, tctxt);
pushQueueAt(q, 0, MQE_START, loc);
nfaQueueInitState(q->nfa, q);
} else if (!fatbit_set(aqa, qCount, qi)) {
DEBUG_PRINTF("initing %u\n", qi);
initRoseQueue(t, qi, left, tctxt);
if (alive) {
s32 sp = -(s32)loadRoseDelay(t, tctxt->state, left);
pushQueueAt(q, 0, MQE_START, sp);
loadStreamState(q->nfa, q, sp);
} else {
pushQueueAt(q, 0, MQE_START, loc);
nfaQueueInitState(q->nfa, q);
} else if (!fatbit_set(aqa, qCount, qi)) {
DEBUG_PRINTF("initing %u\n", qi);
initRoseQueue(t, qi, left, tctxt);
if (alive) {
s32 sp = -(s32)loadRoseDelay(t, tctxt->state, left);
pushQueueAt(q, 0, MQE_START, sp);
loadStreamState(q->nfa, q, sp);
} else {
pushQueueAt(q, 0, MQE_START, loc);
nfaQueueInitState(q->nfa, q);
}
} else if (!alive) {
}
} else if (!alive) {
q->cur = q->end = 0;
pushQueueAt(q, 0, MQE_START, loc);
nfaQueueInitState(q->nfa, q);
} else if (isQueueFull(q)) {
reduceQueue(q, loc, left->maxQueueLen, q->nfa->maxWidth);
if (isQueueFull(q)) {
/* still full - reduceQueue did nothing */
DEBUG_PRINTF("queue %u full (%u items) -> catching up nfa\n", qi,
q->end - q->cur);
pushQueueNoMerge(q, MQE_END, loc);
nfaQueueExecRose(q->nfa, q, MO_INVALID_IDX);
q->cur = q->end = 0;
pushQueueAt(q, 0, MQE_START, loc);
nfaQueueInitState(q->nfa, q);
} else if (isQueueFull(q)) {
reduceQueue(q, loc, left->maxQueueLen, q->nfa->maxWidth);
if (isQueueFull(q)) {
/* still full - reduceQueue did nothing */
DEBUG_PRINTF("queue %u full (%u items) -> catching up nfa\n",
qi, q->end - q->cur);
pushQueueNoMerge(q, MQE_END, loc);
nfaQueueExecRose(q->nfa, q, MO_INVALID_IDX);
q->cur = q->end = 0;
pushQueueAt(q, 0, MQE_START, loc);
}
}
}
pushQueueSom(q, topEvent, loc, start);
next_infix:
++curr_r;
} while (curr_r->queue != MO_INVALID_IDX);
pushQueueSom(q, topEvent, loc, start);
}
static really_inline
@ -1024,10 +966,11 @@ int reachHasBit(const u8 *reach, u8 c) {
* are satisfied.
*/
static rose_inline
int roseCheckLookaround(const struct RoseEngine *t, const struct RoseRole *tr,
u64a end, struct RoseContext *tctxt) {
assert(tr->lookaroundIndex != MO_INVALID_IDX);
assert(tr->lookaroundCount > 0);
int roseCheckLookaround(const struct RoseEngine *t, u32 lookaroundIndex,
u32 lookaroundCount, u64a end,
struct RoseContext *tctxt) {
assert(lookaroundIndex != MO_INVALID_IDX);
assert(lookaroundCount > 0);
const struct core_info *ci = &tctxtToScratch(tctxt)->core_info;
DEBUG_PRINTF("end=%llu, buf_offset=%llu, buf_end=%llu\n", end,
@ -1035,12 +978,12 @@ int roseCheckLookaround(const struct RoseEngine *t, const struct RoseRole *tr,
const u8 *base = (const u8 *)t;
const s8 *look_base = (const s8 *)(base + t->lookaroundTableOffset);
const s8 *look = look_base + tr->lookaroundIndex;
const s8 *look_end = look + tr->lookaroundCount;
const s8 *look = look_base + lookaroundIndex;
const s8 *look_end = look + lookaroundCount;
assert(look < look_end);
const u8 *reach_base = base + t->lookaroundReachOffset;
const u8 *reach = reach_base + tr->lookaroundIndex * REACH_BITVECTOR_LEN;
const u8 *reach = reach_base + lookaroundIndex * REACH_BITVECTOR_LEN;
// The following code assumes that the lookaround structures are ordered by
// increasing offset.
@ -1113,38 +1056,6 @@ int roseCheckLookaround(const struct RoseEngine *t, const struct RoseRole *tr,
return 1;
}
static rose_inline
int roseCheckRolePreconditions(const struct RoseEngine *t,
const struct RoseRole *tr, u64a end,
struct RoseContext *tctxt) {
// If this role can only match at end-of-block, then check that it's so.
if (tr->flags & ROSE_ROLE_FLAG_ONLY_AT_END) {
struct core_info *ci = &tctxtToScratch(tctxt)->core_info;
if (end != ci->buf_offset + ci->len) {
DEBUG_PRINTF("role %u should only match at end of data, skipping\n",
(u32)(tr - getRoleTable(t)));
return 0;
}
}
if (tr->lookaroundIndex != MO_INVALID_IDX) {
if (!roseCheckLookaround(t, tr, end, tctxt)) {
DEBUG_PRINTF("failed lookaround check\n");
return 0;
}
}
assert(!tr->leftfixQueue || (tr->flags & ROSE_ROLE_FLAG_ROSE));
if (tr->flags & ROSE_ROLE_FLAG_ROSE) {
if (!roseTestLeftfix(t, tr, end, tctxt)) {
DEBUG_PRINTF("failed leftfix check\n");
return 0;
}
}
return 1;
}
static
int roseNfaEarliestSom(u64a from_offset, UNUSED u64a offset, UNUSED ReportID id,
void *context) {
@ -1154,20 +1065,18 @@ int roseNfaEarliestSom(u64a from_offset, UNUSED u64a offset, UNUSED ReportID id,
}
static rose_inline
u64a roseGetHaigSom(const struct RoseEngine *t, const struct RoseRole *tr,
UNUSED u64a end, struct RoseContext *tctxt) {
assert(tr->flags & ROSE_ROLE_FLAG_ROSE);
u32 qi = tr->leftfixQueue;
u64a roseGetHaigSom(const struct RoseEngine *t, const u32 qi,
UNUSED const u32 leftfixLag,
struct RoseContext *tctxt) {
u32 ri = queueToLeftIndex(t, qi);
UNUSED const struct LeftNfaInfo *left = getLeftTable(t) + ri;
DEBUG_PRINTF("testing %s prefix %u/%u with lag %u (maxLag=%u)\n",
left->transient ? "transient" : "active", ri, qi,
tr->leftfixLag, left->maxLag);
leftfixLag, left->maxLag);
assert(tr->leftfixLag <= left->maxLag);
assert(leftfixLag <= left->maxLag);
struct mq *q = tctxtToScratch(tctxt)->queues + qi;
@ -1186,98 +1095,217 @@ u64a roseGetHaigSom(const struct RoseEngine *t, const struct RoseRole *tr,
return start;
}
static rose_inline
char roseCheckRootBounds(u64a end, u32 min_bound, u32 max_bound) {
assert(max_bound <= ROSE_BOUND_INF);
assert(min_bound <= max_bound);
if (end < min_bound) {
return 0;
}
return max_bound == ROSE_BOUND_INF || end <= max_bound;
}
#define PROGRAM_CASE(name) \
case ROSE_ROLE_INSTR_##name: { \
DEBUG_PRINTF("instruction: " #name " (%u)\n", ROSE_ROLE_INSTR_##name); \
const struct ROSE_ROLE_STRUCT_##name *ri = \
(const struct ROSE_ROLE_STRUCT_##name *)pc;
#define PROGRAM_NEXT_INSTRUCTION \
pc += ROUNDUP_N(sizeof(*ri), ROSE_INSTR_MIN_ALIGN); \
break; \
}
static really_inline
hwlmcb_rv_t roseHandleRoleEffects(const struct RoseEngine *t,
const struct RoseRole *tr, u64a end,
struct RoseContext *tctxt, char in_anchored,
int *work_done) {
u64a som = 0ULL;
if (tr->flags & ROSE_ROLE_FLAG_SOM_ADJUST) {
som = end - tr->somAdjust;
DEBUG_PRINTF("som requested som %llu = %llu - %u\n", som, end,
tr->somAdjust);
} else if (tr->flags & ROSE_ROLE_FLAG_SOM_ROSEFIX) {
som = roseGetHaigSom(t, tr, end, tctxt);
DEBUG_PRINTF("som from rosefix %llu\n", som);
}
hwlmcb_rv_t roseRunRoleProgram_i(const struct RoseEngine *t, u32 programOffset,
u64a end, u64a *som, struct RoseContext *tctxt,
char in_anchored, int *work_done) {
assert(programOffset);
if (tr->infixTriggerOffset) {
roseTriggerInfixes(t, tr, som, end, tctxt);
tctxt->groups |= tr->groups; /* groups may have been cleared by infix
* going quiet before */
}
DEBUG_PRINTF("program begins at offset %u\n", programOffset);
if (tr->suffixOffset) {
hwlmcb_rv_t rv = roseHandleSuffixTrigger(t, tr, som, end, tctxt,
in_anchored);
if (rv != HWLM_CONTINUE_MATCHING) {
return rv;
}
}
const char *pc = getByOffset(t, programOffset);
if (tr->reportId != MO_INVALID_IDX) {
hwlmcb_rv_t rv;
if (tr->flags & ROSE_ROLE_FLAG_REPORT_START) {
/* rose role knows its start offset */
assert(tr->flags & ROSE_ROLE_FLAG_SOM_ROSEFIX);
assert(!(tr->flags & ROSE_ROLE_FLAG_CHAIN_REPORT));
if (tr->flags & ROSE_ROLE_FLAG_SOM_REPORT) {
rv = roseHandleSomSom(t, tctxt->state, tr->reportId, som, end,
tctxt, in_anchored);
} else {
rv = roseHandleSomMatch(t, tctxt->state, tr->reportId, som, end,
tctxt, in_anchored);
assert(*(const u8 *)pc != ROSE_ROLE_INSTR_END);
for (;;) {
assert(ISALIGNED_N(pc, ROSE_INSTR_MIN_ALIGN));
u8 code = *(const u8 *)pc;
assert(code <= ROSE_ROLE_INSTR_END);
switch ((enum RoseRoleInstructionCode)code) {
PROGRAM_CASE(ANCHORED_DELAY) {
if (in_anchored && end > t->floatingMinLiteralMatchOffset) {
DEBUG_PRINTF("delay until playback\n");
update_depth(tctxt, ri->depth);
tctxt->groups |= ri->groups;
*work_done = 1;
pc += ri->done_jump;
continue;
}
}
} else {
if (tr->flags & ROSE_ROLE_FLAG_SOM_REPORT) {
/* do som management */
rv = roseHandleSom(t, tctxt->state, tr->reportId, end, tctxt,
in_anchored);
} else if (tr->flags & ROSE_ROLE_FLAG_CHAIN_REPORT) {
rv = roseCatchUpAndHandleChainMatch(t, tctxt->state,
tr->reportId, end, tctxt,
in_anchored);
} else {
rv = roseHandleMatch(t, tctxt->state, tr->reportId, end, tctxt,
in_anchored);
}
}
PROGRAM_NEXT_INSTRUCTION
if (rv != HWLM_CONTINUE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
PROGRAM_CASE(CHECK_ONLY_EOD) {
struct core_info *ci = &tctxtToScratch(tctxt)->core_info;
if (end != ci->buf_offset + ci->len) {
DEBUG_PRINTF("should only match at end of data\n");
pc += ri->fail_jump;
continue;
}
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(CHECK_ROOT_BOUNDS) {
if (!in_anchored &&
!roseCheckRootBounds(end, ri->min_bound, ri->max_bound)) {
DEBUG_PRINTF("failed root bounds check\n");
pc += ri->fail_jump;
continue;
}
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(CHECK_LOOKAROUND) {
if (!roseCheckLookaround(t, ri->index, ri->count, end, tctxt)) {
DEBUG_PRINTF("failed lookaround check\n");
pc += ri->fail_jump;
continue;
}
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(CHECK_LEFTFIX) {
if (!roseTestLeftfix(t, ri->queue, ri->lag, ri->report, end,
tctxt)) {
DEBUG_PRINTF("failed lookaround check\n");
pc += ri->fail_jump;
continue;
}
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SOM_ADJUST) {
assert(ri->distance <= end);
*som = end - ri->distance;
DEBUG_PRINTF("som is (end - %u) = %llu\n", ri->distance, *som);
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SOM_LEFTFIX) {
*som = roseGetHaigSom(t, ri->queue, ri->lag, tctxt);
DEBUG_PRINTF("som from leftfix is %llu\n", *som);
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(TRIGGER_INFIX) {
roseTriggerInfix(t, *som, end, ri->queue, ri->event, ri->cancel,
tctxt);
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(TRIGGER_SUFFIX) {
if (roseHandleSuffixTrigger(t, ri->queue, ri->event, *som, end,
tctxt, in_anchored) ==
HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT) {
if (roseHandleMatch(t, tctxt->state, ri->report, end, tctxt,
in_anchored) == HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_CHAIN) {
if (roseCatchUpAndHandleChainMatch(t, tctxt->state, ri->report,
end, tctxt, in_anchored) ==
HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_EOD) {
if (tctxt->cb(end, ri->report, tctxt->userCtx) ==
MO_HALT_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_SOM_INT) {
if (roseHandleSom(t, tctxt->state, ri->report, end, tctxt,
in_anchored) == HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_SOM) {
if (roseHandleSomSom(t, tctxt->state, ri->report, *som, end,
tctxt,
in_anchored) == HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_SOM_KNOWN) {
if (roseHandleSomMatch(t, tctxt->state, ri->report, *som, end,
tctxt, in_anchored) ==
HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SET_STATE) {
roseSetRole(t, tctxt->state, tctxt, ri->index, ri->depth);
*work_done = 1;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SET_GROUPS) {
tctxt->groups |= ri->groups;
DEBUG_PRINTF("set groups 0x%llx -> 0x%llx\n", ri->groups,
tctxt->groups);
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(END) {
DEBUG_PRINTF("finished\n");
return HWLM_CONTINUE_MATCHING;
}
PROGRAM_NEXT_INSTRUCTION
}
}
roseSetRole(t, tctxt->state, tctxt, tr);
*work_done = 1;
assert(0); // unreachable
return HWLM_CONTINUE_MATCHING;
}
static really_inline
hwlmcb_rv_t roseHandleRole(const struct RoseEngine *t,
const struct RoseRole *tr, u64a end,
struct RoseContext *tctxt, char in_anchored,
int *work_done) {
DEBUG_PRINTF("hi role %zd (flags %08x)\n", tr - getRoleTable(t),
tr->flags);
if (in_anchored && end > t->floatingMinLiteralMatchOffset) {
DEBUG_PRINTF("delay until playback, just do groups/depth now\n");
update_depth(tctxt, tr);
tctxt->groups |= tr->groups;
*work_done = 1;
return HWLM_CONTINUE_MATCHING;
}
#undef PROGRAM_CASE
#undef PROGRAM_NEXT_INSTRUCTION
if (!roseCheckRolePreconditions(t, tr, end, tctxt)) {
return HWLM_CONTINUE_MATCHING;
}
/* We now know the role has matched. We can now trigger things that need to
* be triggered and record things that need to be recorded.*/
return roseHandleRoleEffects(t, tr, end, tctxt, in_anchored, work_done);
hwlmcb_rv_t roseRunRoleProgram(const struct RoseEngine *t, u32 programOffset,
u64a end, u64a *som, struct RoseContext *tctxt,
int *work_done) {
return roseRunRoleProgram_i(t, programOffset, end, som, tctxt, 0,
work_done);
}
static really_inline
@ -1364,9 +1392,12 @@ hwlmcb_rv_t roseWalkSparseIterator(const struct RoseEngine *t,
/* mark role as handled so we don't touch it again in this walk */
fatbit_set(handled_roles, t->roleCount, role);
hwlmcb_rv_t rv = roseHandleRole(t, tr, end, tctxt,
0 /* in_anchored */, &work_done);
if (rv == HWLM_TERMINATE_MATCHING) {
if (!tr->programOffset) {
continue;
}
u64a som = 0ULL;
if (roseRunRoleProgram_i(t, tr->programOffset, end, &som, tctxt, 0,
&work_done) == HWLM_TERMINATE_MATCHING) {
return HWLM_TERMINATE_MATCHING;
}
}
@ -1381,51 +1412,26 @@ hwlmcb_rv_t roseWalkSparseIterator(const struct RoseEngine *t,
return HWLM_CONTINUE_MATCHING;
}
// Check that the predecessor bounds are satisfied for a root role with special
// requirements (anchored, or unanchored but with preceding dots).
static rose_inline
char roseCheckRootBounds(const struct RoseEngine *t, const struct RoseRole *tr,
u64a end) {
assert(tr->predOffset != ROSE_OFFSET_INVALID);
const struct RosePred *tp = getPredTable(t) + tr->predOffset;
assert(tp->role == MO_INVALID_IDX);
// Check history. We only use a subset of our history types for root or
// anchored root roles.
assert(tp->historyCheck == ROSE_ROLE_HISTORY_NONE ||
tp->historyCheck == ROSE_ROLE_HISTORY_ANCH);
return roseCheckPredHistory(tp, end);
}
// Walk the set of root roles (roles with depth 1) associated with this literal
// and set them on.
static really_inline
char roseWalkRootRoles_i(const struct RoseEngine *t,
const struct RoseLiteral *tl, u64a end,
struct RoseContext *tctxt, char in_anchored) {
/* main entry point ensures that there is at least two root roles */
if (!tl->rootProgramOffset) {
return 1;
}
DEBUG_PRINTF("running literal root program at %u\n", tl->rootProgramOffset);
u64a som = 0;
int work_done = 0;
assert(tl->rootRoleOffset + tl->rootRoleCount <= t->rootRoleCount);
assert(tl->rootRoleCount > 1);
const u32 *rootRole = getRootRoleTable(t) + tl->rootRoleOffset;
const u32 *rootRoleEnd = rootRole + tl->rootRoleCount;
for (; rootRole < rootRoleEnd; rootRole++) {
u32 role_offset = *rootRole;
const struct RoseRole *tr = getRoleByOffset(t, role_offset);
if (!in_anchored && (tr->flags & ROSE_ROLE_PRED_ROOT)
&& !roseCheckRootBounds(t, tr, end)) {
continue;
}
if (roseHandleRole(t, tr, end, tctxt, in_anchored, &work_done)
== HWLM_TERMINATE_MATCHING) {
return 0;
}
};
if (roseRunRoleProgram_i(t, tl->rootProgramOffset, end, &som, tctxt,
in_anchored,
&work_done) == HWLM_TERMINATE_MATCHING) {
return 0;
}
// If we've actually handled any roles, we might need to apply this
// literal's squash mask to our groups as well.
@ -1450,73 +1456,20 @@ char roseWalkRootRoles_N(const struct RoseEngine *t,
return roseWalkRootRoles_i(t, tl, end, tctxt, 0);
}
static really_inline
char roseWalkRootRoles_i1(const struct RoseEngine *t,
const struct RoseLiteral *tl, u64a end,
struct RoseContext *tctxt, char in_anchored) {
/* main entry point ensures that there is exactly one root role */
int work_done = 0;
u32 role_offset = tl->rootRoleOffset;
const struct RoseRole *tr = getRoleByOffset(t, role_offset);
if (!in_anchored && (tr->flags & ROSE_ROLE_PRED_ROOT)
&& !roseCheckRootBounds(t, tr, end)) {
return 1;
}
hwlmcb_rv_t rv = roseHandleRole(t, tr, end, tctxt, in_anchored, &work_done);
if (rv == HWLM_TERMINATE_MATCHING) {
return 0;
}
// If we've actually handled any roles, we might need to apply this
// literal's squash mask to our groups as well.
if (work_done && tl->squashesGroup) {
roseSquashGroup(tctxt, tl);
}
return 1;
}
static never_inline
char roseWalkRootRoles_A1(const struct RoseEngine *t,
const struct RoseLiteral *tl, u64a end,
struct RoseContext *tctxt) {
return roseWalkRootRoles_i1(t, tl, end, tctxt, 1);
}
static never_inline
char roseWalkRootRoles_N1(const struct RoseEngine *t,
const struct RoseLiteral *tl, u64a end,
struct RoseContext *tctxt) {
return roseWalkRootRoles_i1(t, tl, end, tctxt, 0);
}
static really_inline
char roseWalkRootRoles(const struct RoseEngine *t,
const struct RoseLiteral *tl, u64a end,
struct RoseContext *tctxt, char in_anchored,
char in_anch_playback) {
DEBUG_PRINTF("literal has %u root roles\n", tl->rootRoleCount);
assert(!in_anch_playback || tl->rootRoleCount);
if (!in_anch_playback && !tl->rootRoleCount) {
assert(!in_anch_playback || tl->rootProgramOffset);
if (!in_anch_playback && !tl->rootProgramOffset) {
return 1;
}
if (in_anchored) {
if (tl->rootRoleCount == 1) {
return roseWalkRootRoles_A1(t, tl, end, tctxt);
} else {
return roseWalkRootRoles_A(t, tl, end, tctxt);
}
return roseWalkRootRoles_A(t, tl, end, tctxt);
} else {
if (tl->rootRoleCount == 1) {
return roseWalkRootRoles_N1(t, tl, end, tctxt);
} else {
return roseWalkRootRoles_N(t, tl, end, tctxt);
}
return roseWalkRootRoles_N(t, tl, end, tctxt);
}
}
@ -1617,12 +1570,11 @@ int roseAnchoredCallback(u64a end, u32 id, void *ctx) {
assert(id < t->literalCount);
const struct RoseLiteral *tl = &getLiteralTable(t)[id];
assert(tl->rootRoleCount > 0);
assert(tl->rootProgramOffset);
assert(!tl->delay_mask);
DEBUG_PRINTF("literal id=%u, minDepth=%u, groups=0x%016llx, "
"rootRoleCount=%u\n",
id, tl->minDepth, tl->groups, tl->rootRoleCount);
DEBUG_PRINTF("literal id=%u, minDepth=%u, groups=0x%016llx\n", id,
tl->minDepth, tl->groups);
if (real_end <= t->floatingMinLiteralMatchOffset) {
roseFlushLastByteHistory(t, state, real_end, tctxt);
@ -1688,8 +1640,8 @@ hwlmcb_rv_t roseProcessMatch_i(const struct RoseEngine *t, u64a end, u32 id,
assert(id < t->literalCount);
const struct RoseLiteral *tl = &getLiteralTable(t)[id];
DEBUG_PRINTF("lit id=%u, minDepth=%u, groups=0x%016llx, rootRoleCount=%u\n",
id, tl->minDepth, tl->groups, tl->rootRoleCount);
DEBUG_PRINTF("lit id=%u, minDepth=%u, groups=0x%016llx\n", id, tl->minDepth,
tl->groups);
if (do_group_check && !(tl->groups & tctxt->groups)) {
DEBUG_PRINTF("IGNORE: none of this literal's groups are set.\n");

View File

@ -262,8 +262,8 @@ hwlmcb_rv_t cleanUpDelayed(size_t length, u64a offset, struct RoseContext *tctxt
}
static really_inline
void update_depth(struct RoseContext *tctxt, const struct RoseRole *tr) {
u8 d = MAX(tctxt->depth, tr->depth + 1);
void update_depth(struct RoseContext *tctxt, u8 depth) {
u8 d = MAX(tctxt->depth, depth + 1);
assert(d >= tctxt->depth);
DEBUG_PRINTF("depth now %hhu was %hhu\n", d, tctxt->depth);
tctxt->depth = d;
@ -323,4 +323,8 @@ void roseFlushLastByteHistory(const struct RoseEngine *t, u8 *state,
scratch->sparse_iter_state);
}
hwlmcb_rv_t roseRunRoleProgram(const struct RoseEngine *t, u32 programOffset,
u64a end, u64a *som, struct RoseContext *tctxt,
int *work_done);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -2154,53 +2154,6 @@ bool hasOrphanedTops(const RoseBuildImpl &tbi) {
#endif // NDEBUG
/**
* \brief Normalise vertices so that every one has <= 1 report.
*/
static
void normaliseRoles(RoseBuildImpl &build) {
DEBUG_PRINTF("normalising\n");
RoseGraph &g = build.g;
vector<RoseVertex> work; // Vertices with > 1 report.
for (const auto &v : vertices_range(g)) {
if (g[v].reports.size() > 1) {
work.push_back(v);
}
}
DEBUG_PRINTF("%zu vertices to normalise\n", work.size());
for (const auto &v : work) {
DEBUG_PRINTF("exploding vertex %zu with %zu reports\n", g[v].idx,
g[v].reports.size());
// Make a copy of v for the trailing N-1 reports. Each of those gets
// one report and a copy of the in-edges. The first vertex retains the
// out-edges and suffix, if any are present. All the others don't need
// them.
const auto &reports = g[v].reports;
for (auto it = next(begin(reports)); it != end(reports); ++it) {
const ReportID &r = *it;
RoseVertex v2 = build.cloneVertex(v);
g[v2].reports = {r};
for (const auto &e : in_edges_range(v, g)) {
add_edge(source(e, g), v2, g[e], g);
}
// No out-edges or suffix.
g[v2].suffix.reset();
}
// Vertex v retains the first report.
g[v].reports = {*begin(reports)};
}
}
aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
dumpRoseGraph(*this, nullptr, "rose_early.dot");
@ -2315,10 +2268,6 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
dumpRoseGraph(*this, nullptr, "rose_pre_norm.dot");
// Ensure that every vertex has <= 1 report, since the Rose runtime
// requires this at present.
normaliseRoles(*this);
return buildFinalEngine(minWidth);
}

View File

@ -34,6 +34,7 @@
#include "rose_build_impl.h"
#include "rose/rose_dump.h"
#include "rose_internal.h"
#include "rose_program.h"
#include "ue2common.h"
#include "nfa/nfa_internal.h"
#include "nfagraph/ng_dump.h"
@ -95,6 +96,59 @@ const RoseRole *getRoseRole(const RoseBuildImpl &build,
return &roles[role_idx];
}
#define SKIP_CASE(name) \
case ROSE_ROLE_INSTR_##name: { \
const auto *ri = (const struct ROSE_ROLE_STRUCT_##name *)pc; \
pc += ROUNDUP_N(sizeof(*ri), ROSE_INSTR_MIN_ALIGN); \
break; \
}
template<int Opcode, class Struct>
const Struct *
findInstruction(const RoseEngine *t, const RoseRole *role) {
if (!role->programOffset) {
return nullptr;
}
const char *pc = (const char *)t + role->programOffset;
for (;;) {
u8 code = *(const u8 *)pc;
assert(code <= ROSE_ROLE_INSTR_END);
if (code == Opcode) {
return (const Struct *)pc;
}
// Skip to the next instruction.
switch (code) {
SKIP_CASE(ANCHORED_DELAY)
SKIP_CASE(CHECK_ONLY_EOD)
SKIP_CASE(CHECK_ROOT_BOUNDS)
SKIP_CASE(CHECK_LEFTFIX)
SKIP_CASE(CHECK_LOOKAROUND)
SKIP_CASE(SOM_ADJUST)
SKIP_CASE(SOM_LEFTFIX)
SKIP_CASE(TRIGGER_INFIX)
SKIP_CASE(TRIGGER_SUFFIX)
SKIP_CASE(REPORT)
SKIP_CASE(REPORT_CHAIN)
SKIP_CASE(REPORT_EOD)
SKIP_CASE(REPORT_SOM_INT)
SKIP_CASE(REPORT_SOM)
SKIP_CASE(REPORT_SOM_KNOWN)
SKIP_CASE(SET_STATE)
SKIP_CASE(SET_GROUPS)
case ROSE_ROLE_INSTR_END:
return nullptr;
default:
assert(0);
return nullptr;
}
}
return nullptr;
}
#undef SKIP_CASE
namespace {
class RoseGraphWriter {
@ -149,9 +203,12 @@ public:
if (g[v].suffix) {
os << "\\nSUFFIX (TOP " << g[v].suffix.top;
if (r) {
assert(t);
const NFA *n = (const NFA *)((const char *)t + r->suffixOffset);
os << ", Q" << n->queueIndex;
const auto *ri =
findInstruction<ROSE_ROLE_INSTR_TRIGGER_SUFFIX,
ROSE_ROLE_STRUCT_TRIGGER_SUFFIX>(t, r);
if (ri) {
os << ", Q" << ri->queue;
}
} else {
// Can't dump the queue number, but we can identify the suffix.
if (g[v].suffix.graph) {
@ -191,7 +248,12 @@ public:
os << "\\nROSE " << roseKind;
os << " (";
if (r) {
os << "Q" << r->leftfixQueue << ", ";
const auto *ri =
findInstruction<ROSE_ROLE_INSTR_CHECK_LEFTFIX,
ROSE_ROLE_STRUCT_CHECK_LEFTFIX>(t, r);
if (ri) {
os << "Q" << ri->queue << ", ";
}
}
os << "report " << g[v].left.leftfix_report << ")";
@ -555,19 +617,28 @@ void dumpRoseLookaround(const RoseBuildImpl &build, const RoseEngine *t,
for (RoseVertex v : vertices_range(g)) {
const RoseRole *role = getRoseRole(build, t, v);
if (!role || role->lookaroundIndex == MO_INVALID_IDX) {
if (!role) {
continue;
}
const auto *ri =
findInstruction<ROSE_ROLE_INSTR_CHECK_LOOKAROUND,
ROSE_ROLE_STRUCT_CHECK_LOOKAROUND>(t, role);
if (!ri) {
continue;
}
const u32 look_idx = ri->index;
const u32 look_count = ri->count;
os << "Role " << g[v].role << endl;
os << " literals: " << as_string_list(g[v].literals) << endl;
os << " lookaround: index=" << role->lookaroundIndex
<< ", count=" << role->lookaroundCount << endl;
os << " lookaround: index=" << look_idx << ", count=" << look_count
<< endl;
const s8 *look = look_base + role->lookaroundIndex;
const s8 *look_end = look + role->lookaroundCount;
const u8 *reach =
reach_base + role->lookaroundIndex * REACH_BITVECTOR_LEN;
const s8 *look = look_base + look_idx;
const s8 *look_end = look + look_count;
const u8 *reach = reach_base + look_idx * REACH_BITVECTOR_LEN;
for (; look < look_end; look++, reach += REACH_BITVECTOR_LEN) {
os << " " << std::setw(4) << std::setfill(' ') << int{*look}

View File

@ -305,6 +305,11 @@ struct OutfixInfo { /* TODO: poly */
u32 get_queue(QueueIndexFactory &qif);
u32 get_queue() const {
assert(queue != ~0U);
return queue;
}
bool is_nonempty_mpv() const {
return !puffettes.empty() || !triggered_puffettes.empty();
}
@ -329,9 +334,6 @@ struct OutfixInfo { /* TODO: poly */
std::vector<raw_puff> puffettes;
std::vector<raw_puff> triggered_puffettes;
/** Once the outfix has been built into an engine, this will point to it. */
NFA *nfa = nullptr;
RevAccInfo rev_info;
u32 maxBAWidth = 0; //!< max bi-anchored width
depth minWidth = depth::infinity();

View File

@ -2572,10 +2572,6 @@ void mergeOutfixCombo(RoseBuildImpl &tbi, const ReportManager &rm,
for (auto it = tbi.outfixes.begin(); it != tbi.outfixes.end(); ++it) {
assert(!it->is_dead());
if (it->nfa) {
assert(!it->rdfa && !it->holder && !it->haig);
continue;
}
assert(!it->chained);
if (it->rdfa) {
dfas.push_back(it->rdfa.get());
@ -2650,10 +2646,6 @@ void mergeOutfixes(RoseBuildImpl &tbi) {
vector<raw_som_dfa *> som_dfas;
for (const auto &outfix : tbi.outfixes) {
if (outfix.nfa) {
assert(!outfix.rdfa && !outfix.holder && !outfix.haig);
continue;
}
assert(!outfix.chained);
if (outfix.rdfa) {
dfas.push_back(outfix.rdfa.get());

View File

@ -629,8 +629,6 @@ RoseDedupeAuxImpl::RoseDedupeAuxImpl(const RoseBuildImpl &tbi_in)
}
for (const auto &outfix : tbi.outfixes) {
assert(!outfix.nfa); /* should not be built yet */
for (const auto &report_id : all_reports(outfix)) {
outfix_map[report_id].insert(&outfix);
}
@ -738,7 +736,6 @@ bool RoseDedupeAuxImpl::requiresDedupeSupport(
for (const auto &outfix_ptr : outfixes) {
assert(outfix_ptr);
const OutfixInfo &out = *outfix_ptr;
assert(!out.nfa); /* should not be built yet */
if (has_outfix || has_role || has_suffix) {
return true;

View File

@ -34,6 +34,7 @@
#include "rose_dump.h"
#include "rose_common.h"
#include "rose_internal.h"
#include "rose_program.h"
#include "hs_compile.h"
#include "ue2common.h"
#include "nfa/nfa_build_util.h"
@ -202,47 +203,240 @@ u32 rolesWithFlag(const RoseEngine *t, u32 flag) {
return n;
}
#define HANDLE_CASE(name) \
case ROSE_ROLE_INSTR_##name: { \
const auto *ri = (const struct ROSE_ROLE_STRUCT_##name *)pc; \
pc += ROUNDUP_N(sizeof(*ri), ROSE_INSTR_MIN_ALIGN); \
break; \
}
static
u32 rolesWithSuffixes(const RoseEngine *t) {
u32 rolesWithInstr(const RoseEngine *t,
enum RoseRoleInstructionCode find_code) {
u32 n = 0;
const RoseRole *tr = getRoleTable(t);
const RoseRole *tr_end = tr + t->roleCount;
for (; tr != tr_end; ++tr) {
if (tr->suffixOffset) {
n++;
if (!tr->programOffset) {
continue;
}
const char *pc = (const char *)t + tr->programOffset;
for (;;) {
u8 code = *(const u8 *)pc;
assert(code <= ROSE_ROLE_INSTR_END);
if (code == find_code) {
n++;
goto next_role;
}
switch (code) {
HANDLE_CASE(CHECK_ONLY_EOD)
HANDLE_CASE(CHECK_ROOT_BOUNDS)
HANDLE_CASE(CHECK_LOOKAROUND)
HANDLE_CASE(CHECK_LEFTFIX)
HANDLE_CASE(ANCHORED_DELAY)
HANDLE_CASE(SOM_ADJUST)
HANDLE_CASE(SOM_LEFTFIX)
HANDLE_CASE(TRIGGER_INFIX)
HANDLE_CASE(TRIGGER_SUFFIX)
HANDLE_CASE(REPORT)
HANDLE_CASE(REPORT_CHAIN)
HANDLE_CASE(REPORT_EOD)
HANDLE_CASE(REPORT_SOM_INT)
HANDLE_CASE(REPORT_SOM)
HANDLE_CASE(REPORT_SOM_KNOWN)
HANDLE_CASE(SET_STATE)
HANDLE_CASE(SET_GROUPS)
case ROSE_ROLE_INSTR_END:
goto next_role;
default:
assert(0);
return 0;
}
}
next_role:;
}
return n;
}
static
u32 rolesWithLookaround(const RoseEngine *t) {
u32 n = 0;
const RoseRole *tr = getRoleTable(t);
const RoseRole *tr_end = tr + t->roleCount;
#undef HANDLE_CASE
for (; tr != tr_end; ++tr) {
if (tr->lookaroundIndex != MO_INVALID_IDX) {
n++;
#define PROGRAM_CASE(name) \
case ROSE_ROLE_INSTR_##name: { \
os << " " << std::setw(4) << std::setfill('0') << (pc - pc_base) \
<< ": " #name " (" << (int)ROSE_ROLE_INSTR_##name << ")" << endl; \
const auto *ri = (const struct ROSE_ROLE_STRUCT_##name *)pc;
#define PROGRAM_NEXT_INSTRUCTION \
pc += ROUNDUP_N(sizeof(*ri), ROSE_INSTR_MIN_ALIGN); \
break; \
}
static
void dumpRoleProgram(ofstream &os, const char *pc) {
const char *pc_base = pc;
for (;;) {
u8 code = *(const u8 *)pc;
assert(code <= ROSE_ROLE_INSTR_END);
switch (code) {
PROGRAM_CASE(ANCHORED_DELAY) {
os << " depth " << u32{ri->depth} << endl;
os << " groups 0x" << std::hex << ri->groups << std::dec
<< endl;
os << " done_jump +" << ri->done_jump << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(CHECK_ONLY_EOD) {
os << " fail_jump +" << ri->fail_jump << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(CHECK_ROOT_BOUNDS) {
os << " min_bound " << ri->min_bound << endl;
os << " max_bound " << ri->max_bound << endl;
os << " fail_jump +" << ri->fail_jump << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(CHECK_LOOKAROUND) {
os << " index " << ri->index << endl;
os << " count " << ri->count << endl;
os << " fail_jump +" << ri->fail_jump << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(CHECK_LEFTFIX) {
os << " queue " << ri->queue << endl;
os << " lag " << ri->lag << endl;
os << " report " << ri->report << endl;
os << " fail_jump +" << ri->fail_jump << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SOM_ADJUST) {
os << " distance " << ri->distance << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SOM_LEFTFIX) {
os << " queue " << ri->queue << endl;
os << " lag " << ri->lag << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(TRIGGER_INFIX) {
os << " queue " << ri->queue << endl;
os << " event " << ri->event << endl;
os << " cancel " << u32{ri->cancel} << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(TRIGGER_SUFFIX) {
os << " queue " << ri->queue << endl;
os << " event " << ri->event << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT) {
os << " report " << ri->report << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_CHAIN) {
os << " report " << ri->report << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_EOD) {
os << " report " << ri->report << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_SOM_INT) {
os << " report " << ri->report << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_SOM) {
os << " report " << ri->report << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(REPORT_SOM_KNOWN) {
os << " report " << ri->report << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SET_STATE) {
os << " depth " << u32{ri->depth} << endl;
os << " index " << ri->index << endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(SET_GROUPS) {
os << " groups 0x" << std::hex << ri->groups << std::dec
<< endl;
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(END) { return; }
PROGRAM_NEXT_INSTRUCTION
default:
os << " UNKNOWN (code " << int{code} << ")" << endl;
os << " <stopping>" << endl;
return;
}
}
return n;
}
// Count roles that fire reports
static
u32 rolesWithReports(const RoseEngine *t) {
u32 n = 0;
const RoseRole *tr = getRoleTable(t);
const RoseRole *tr_end = tr + t->roleCount;
#undef PROGRAM_CASE
#undef PROGRAM_NEXT_INSTRUCTION
for (; tr != tr_end; ++tr) {
if (tr->reportId != MO_INVALID_IDX) {
n++;
static
void dumpRoseRolePrograms(const RoseEngine *t, const string &filename) {
ofstream os(filename);
const RoseRole *roles = getRoleTable(t);
const char *base = (const char *)t;
for (u32 i = 0; i < t->roleCount; i++) {
const RoseRole *role = &roles[i];
os << "Role " << i << endl;
if (!role->programOffset) {
os << " <no program>" << endl;
continue;
}
dumpRoleProgram(os, base + role->programOffset);
os << endl;
}
return n;
os.close();
}
static
void dumpRoseLitPrograms(const RoseEngine *t, const string &filename) {
ofstream os(filename);
const RoseLiteral *lits = getLiteralTable(t);
const char *base = (const char *)t;
for (u32 i = 0; i < t->literalCount; i++) {
const RoseLiteral *lit = &lits[i];
if (!lit->rootProgramOffset) {
continue;
}
os << "Literal " << i << endl;
dumpRoleProgram(os, base + lit->rootProgramOffset);
os << endl;
}
os.close();
}
static
@ -279,16 +473,6 @@ void dumpPreds(FILE *f, const RoseEngine *t) {
}
}
static
const char *startNfaRegion(const RoseEngine *t) {
return (const char *)t + t->nfaRegionBegin;
}
static
const char *endNfaRegion(const RoseEngine *t) {
return (const char *)t + t->nfaRegionEnd;
}
static
void dumpNfaNotes(ofstream &fout, const RoseEngine *t, const NFA *n) {
const u32 qindex = n->queueIndex;
@ -353,18 +537,15 @@ void dumpComponentInfo(const RoseEngine *t, const string &base) {
ss << base << "rose_components.txt";
ofstream fout(ss.str().c_str());
const char *p = startNfaRegion(t);
const char *pe = endNfaRegion(t);
fout << "Index Offset\tEngine \tStates S.State Bytes Notes\n";
while (p < pe) {
const NFA *n = (const NFA *)p;
u32 i = n->queueIndex;
for (u32 i = 0; i < t->queueCount; i++) {
const NfaInfo *nfa_info = getNfaInfoByQueue(t, i);
const NFA *n = getNfaByInfo(t, nfa_info);
fout << left << setw(6) << i << " ";
fout << left << (p - (const char *)t) << "\t"; /* offset */
fout << left << ((const char *)n - (const char *)t) << "\t"; /* offset */
fout << left << setw(16) << describe(*n) << "\t";
@ -375,8 +556,6 @@ void dumpComponentInfo(const RoseEngine *t, const string &base) {
dumpNfaNotes(fout, t, n);
fout << endl;
p += ROUNDUP_CL(n->length);
}
}
@ -416,20 +595,17 @@ void dumpExhaust(const RoseEngine *t, const string &base) {
static
void dumpNfas(const RoseEngine *t, bool dump_raw, const string &base) {
const char *p = startNfaRegion(t);
const char *pe = endNfaRegion(t);
dumpExhaust(t, base);
while (p < pe) {
const NFA *n = (const NFA *)p;
u32 q = n->queueIndex;
for (u32 i = 0; i < t->queueCount; i++) {
const NfaInfo *nfa_info = getNfaInfoByQueue(t, i);
const NFA *n = getNfaByInfo(t, nfa_info);
stringstream sstxt, ssdot, ssraw;
sstxt << base << "rose_nfa_" << q << ".txt";
ssdot << base << "rose_nfa_" << q << ".dot";
ssraw << base << "rose_nfa_" << q << ".raw";
sstxt << base << "rose_nfa_" << i << ".txt";
ssdot << base << "rose_nfa_" << i << ".dot";
ssraw << base << "rose_nfa_" << i << ".raw";
FILE *f;
@ -446,8 +622,6 @@ void dumpNfas(const RoseEngine *t, bool dump_raw, const string &base) {
fwrite(n, 1, n->length, f);
fclose(f);
}
p += ROUNDUP_CL(n->length);
}
}
@ -638,9 +812,7 @@ void roseDumpText(const RoseEngine *t, FILE *f) {
fprintf(f, " - role state table : %zu bytes\n",
t->rolesWithStateCount * sizeof(u32));
fprintf(f, " - nfa info table : %u bytes\n",
t->rootRoleOffset - t->nfaInfoOffset);
fprintf(f, " - root role table : %zu bytes\n",
t->rootRoleCount * sizeof(u32));
t->anchoredReportMapOffset - t->nfaInfoOffset);
fprintf(f, " - lookaround table : %u bytes\n",
t->predOffset - t->lookaroundTableOffset);
fprintf(f, " - lookaround reach : %u bytes\n",
@ -686,24 +858,23 @@ void roseDumpText(const RoseEngine *t, FILE *f) {
fprintf(f, "number of roles : %u\n", t->roleCount);
fprintf(f, " - with state index : %u\n", t->rolesWithStateCount);
fprintf(f, " - with leftfix nfa : %u\n",
rolesWithFlag(t, ROSE_ROLE_FLAG_ROSE));
fprintf(f, " - with suffix nfa : %u\n", rolesWithSuffixes(t));
fprintf(f, " - with lookaround : %u\n", rolesWithLookaround(t));
fprintf(f, " - with reports : %u\n", rolesWithReports(t));
rolesWithInstr(t, ROSE_ROLE_INSTR_CHECK_LEFTFIX));
fprintf(f, " - with suffix nfa : %u\n",
rolesWithInstr(t, ROSE_ROLE_INSTR_TRIGGER_SUFFIX));
fprintf(f, " - with lookaround : %u\n",
rolesWithInstr(t, ROSE_ROLE_INSTR_CHECK_LOOKAROUND));
fprintf(f, " - with reports : %u\n",
rolesWithInstr(t, ROSE_ROLE_INSTR_REPORT));
fprintf(f, " - with som reports : %u\n",
rolesWithFlag(t, ROSE_ROLE_FLAG_SOM_REPORT));
fprintf(f, " - with eod accepts : %u\n",
rolesWithFlag(t, ROSE_ROLE_FLAG_ACCEPT_EOD));
rolesWithInstr(t, ROSE_ROLE_INSTR_REPORT_SOM_INT));
fprintf(f, " - match only at end : %u\n",
rolesWithFlag(t, ROSE_ROLE_FLAG_ONLY_AT_END));
rolesWithInstr(t, ROSE_ROLE_INSTR_CHECK_ONLY_EOD));
fprintf(f, " + anchored : %u\n", t->anchoredMatches);
fprintf(f, " - no preds (root) : %u\n",
rolesWithFlag(t, ROSE_ROLE_PRED_NONE));
fprintf(f, " - simple preds : %u\n",
rolesWithFlag(t, ROSE_ROLE_PRED_SIMPLE));
fprintf(f, " - root preds : %u\n",
rolesWithFlag(t, ROSE_ROLE_PRED_ROOT));
fprintf(f, " - bound root preds : %u\n",
rolesWithInstr(t, ROSE_ROLE_INSTR_CHECK_ROOT_BOUNDS));
fprintf(f, " - 'any' preds : %u\n",
rolesWithFlag(t, ROSE_ROLE_PRED_ANY));
fprintf(f, "number of preds : %u\n", t->predCount);
@ -810,8 +981,6 @@ void roseDumpStructRaw(const RoseEngine *t, FILE *f) {
DUMP_U32(t, roleCount);
DUMP_U32(t, predOffset);
DUMP_U32(t, predCount);
DUMP_U32(t, rootRoleOffset);
DUMP_U32(t, rootRoleCount);
DUMP_U32(t, leftOffset);
DUMP_U32(t, roseCount);
DUMP_U32(t, lookaroundTableOffset);
@ -872,8 +1041,6 @@ void roseDumpStructRaw(const RoseEngine *t, FILE *f) {
DUMP_U32(t, literalBenefitsOffsets);
DUMP_U32(t, somRevCount);
DUMP_U32(t, somRevOffsetOffset);
DUMP_U32(t, nfaRegionBegin);
DUMP_U32(t, nfaRegionEnd);
DUMP_U32(t, group_weak_end);
DUMP_U32(t, floatingStreamState);
DUMP_U32(t, eodLiteralId);
@ -912,19 +1079,7 @@ void roseDumpRoleStructRaw(const RoseEngine *t, FILE *f) {
for (const RoseRole *p = tr; p < tr_end; p++) {
fprintf(f, "role[%zu] = {\n", p - tr);
DUMP_U32(p, flags);
DUMP_U32(p, predOffset);
DUMP_U64(p, groups);
DUMP_U32(p, reportId);
DUMP_U32(p, stateIndex);
DUMP_U32(p, suffixEvent);
DUMP_U8(p, depth);
DUMP_U32(p, suffixOffset);
DUMP_U32(p, leftfixReport);
DUMP_U32(p, leftfixLag);
DUMP_U32(p, leftfixQueue);
DUMP_U32(p, somAdjust);
DUMP_U32(p, lookaroundIndex);
DUMP_U32(p, lookaroundCount);
DUMP_U32(p, programOffset);
fprintf(f, "}\n");
}
}
@ -935,6 +1090,10 @@ void roseDumpComponents(const RoseEngine *t, bool dump_raw, const string &base)
dumpAnchored(t, base);
dumpRevComponentInfo(t, base);
dumpRevNfas(t, dump_raw, base);
// Role programs.
dumpRoseRolePrograms(t, base + "/rose_role_programs.txt");
dumpRoseLitPrograms(t, base + "/rose_lit_root_programs.txt");
}
void roseDumpInternals(const RoseEngine *t, const string &base) {

View File

@ -75,13 +75,7 @@ ReportID literalToReport(u32 id) {
// Structure representing a literal. Each literal may have many roles.
struct RoseLiteral {
u32 rootRoleOffset; /**< If rootRoleCount == 1, this is an offset relative
* to the rose engine to the root role associated with
* the literal.
* If rootRoleCount > 1, this is the first index into
* the rootRoleTable indicating the root roles.
*/
u32 rootRoleCount; // number of root roles
u32 rootProgramOffset; // role program to run for root roles.
u32 iterOffset; // offset of sparse iterator, relative to rose
u32 iterMapOffset; // offset of the iter mapping table, relative to rose
rose_group groups; // bitset of groups that cause this literal to fire.
@ -216,13 +210,6 @@ struct LeftNfaInfo {
rose_group squash_mask; /* & mask applied when rose nfa dies */
};
// A list of these is used to trigger prefix/infix roses.
struct RoseTrigger {
u32 queue; // queue index of leftfix
u32 event; // queue event, from MQE_*
u8 cancel_prev_top;
};
struct NfaInfo {
u32 nfaOffset;
u32 stateOffset;
@ -238,42 +225,14 @@ struct NfaInfo {
* matches */
};
#define ROSE_ROLE_FLAG_ANCHOR_TABLE (1U << 0) /**< role is triggered from
* anchored table */
#define ROSE_ROLE_FLAG_ACCEPT_EOD (1U << 2) /**< "fake" role, fires callback
* at EOD */
#define ROSE_ROLE_FLAG_ONLY_AT_END (1U << 3) /**< role can only be switched on
* at end of block */
#define ROSE_ROLE_FLAG_PRED_OF_EOD (1U << 4) /**< eod is a successor literal
* of the role */
#define ROSE_ROLE_FLAG_EOD_TABLE (1U << 5) /**< role is triggered from eod
* table */
#define ROSE_ROLE_FLAG_ROSE (1U << 6) /**< rose style prefix nfa for
* role */
#define ROSE_ROLE_FLAG_SOM_REPORT (1U << 7) /**< report id is only used to
* manipulate som */
#define ROSE_ROLE_FLAG_REPORT_START (1U << 8) /**< som som som som */
#define ROSE_ROLE_FLAG_CHAIN_REPORT (1U << 9) /**< report id is only used to
* start an outfix engine */
#define ROSE_ROLE_FLAG_SOM_ADJUST (1U << 10) /**< som value to use is offset
* from match end location */
#define ROSE_ROLE_FLAG_SOM_ROSEFIX (1U << 11) /**< som value to use is provided
* by prefix/infix */
/* We allow different types of role-predecessor relationships. These are stored
* in with the flags */
#define ROSE_ROLE_PRED_NONE (1U << 20) /**< the only pred is the root,
* [0, inf] bounds */
#define ROSE_ROLE_PRED_SIMPLE (1U << 21) /**< single [0,inf] pred, no
* offset tracking */
#define ROSE_ROLE_PRED_ROOT (1U << 22) /**< pred is root or anchored
* root, and we have bounds */
#define ROSE_ROLE_PRED_ANY (1U << 23) /**< any of our preds can match */
#define ROSE_ROLE_PRED_CLEAR_MASK (~(ROSE_ROLE_PRED_NONE \
| ROSE_ROLE_PRED_SIMPLE \
| ROSE_ROLE_PRED_ROOT \
| ROSE_ROLE_PRED_ANY))
#define ROSE_ROLE_PRED_CLEAR_MASK \
(~(ROSE_ROLE_PRED_SIMPLE | ROSE_ROLE_PRED_ANY))
#define MAX_STORED_LEFTFIX_LAG 127 /* max leftfix lag that we can store in one
* whole byte (OWB) (streaming only). Other
@ -285,28 +244,7 @@ struct NfaInfo {
// Structure representing a literal role.
struct RoseRole {
u32 flags;
u32 predOffset; // either offset of pred sparse iterator, or
// (for ROSE_ROLE_PRED_ROOT) index of single RosePred.
rose_group groups; /**< groups to enable when role is set (groups of succ
* literals) */
ReportID reportId; // report ID, or MO_INVALID_IDX
u32 stateIndex; /**< index into state multibit, or MMB_INVALID. Roles do not
* require a state bit if they are terminal */
u32 suffixEvent; // queue event, from MQE_
u8 depth; /**< depth of this vertex from root in the tree, or 255 if greater.
*/
u32 suffixOffset; /**< suffix nfa: 0 if no suffix associated with the role,
* relative to base of the rose. */
ReportID leftfixReport; // (pre|in)fix report to check, or MO_INVALID_IDX.
u32 leftfixLag; /**< distance behind match where we need to check the
* leftfix engine status */
u32 leftfixQueue; /**< queue index of the prefix/infix before role */
u32 infixTriggerOffset; /* offset to list of infix roses to trigger */
u32 somAdjust; /**< som for the role is offset from end match offset */
u32 lookaroundIndex; /**< index of lookaround offset/reach in table, or
* MO_INVALID_IDX. */
u32 lookaroundCount; /**< number of lookaround entries. */
u32 programOffset; /**< offset to program to run. */
};
// Structure representing a predecessor relationship
@ -513,8 +451,6 @@ struct RoseEngine {
u32 roleCount; // number of RoseRole entries
u32 predOffset; // offset of RosePred array (bytes)
u32 predCount; // number of RosePred entries
u32 rootRoleOffset;
u32 rootRoleCount;
u32 leftOffset;
u32 roseCount;
@ -584,8 +520,6 @@ struct RoseEngine {
id */
u32 somRevCount; /**< number of som reverse nfas */
u32 somRevOffsetOffset; /**< offset to array of offsets to som rev nfas */
u32 nfaRegionBegin; /* start of the nfa region, debugging only */
u32 nfaRegionEnd; /* end of the nfa region, debugging only */
u32 group_weak_end; /* end of weak groups, debugging only */
u32 floatingStreamState; // size in bytes
u32 eodLiteralId; // literal ID for eod ROSE_EVENT if used, otherwise 0.
@ -715,13 +649,6 @@ const struct mmbit_sparse_iter *getActiveLeftIter(const struct RoseEngine *t) {
return it;
}
static really_inline
const u32 *getRootRoleTable(const struct RoseEngine *t) {
const u32 *r = (const u32 *)((const char *)t + t->rootRoleOffset);
assert(ISALIGNED_N(r, 4));
return r;
}
static really_inline
const struct lit_benefits *getLiteralBenefitsTable(
const struct RoseEngine *t) {

167
src/rose/rose_program.h Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2015, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* \brief Rose data structures to do with role programs.
*/
#ifndef ROSE_ROSE_PROGRAM_H
#define ROSE_ROSE_PROGRAM_H
#include "rose_internal.h"
#include "ue2common.h"
/** \brief Minimum alignment for each instruction in memory. */
#define ROSE_INSTR_MIN_ALIGN 8U
/** \brief Role program instruction opcodes. */
enum RoseRoleInstructionCode {
ROSE_ROLE_INSTR_ANCHORED_DELAY, //!< Delay until after anchored matcher.
ROSE_ROLE_INSTR_CHECK_ONLY_EOD, //!< Role matches only at EOD.
ROSE_ROLE_INSTR_CHECK_ROOT_BOUNDS, //!< Bounds on distance from root.
ROSE_ROLE_INSTR_CHECK_LOOKAROUND, //!< Lookaround check.
ROSE_ROLE_INSTR_CHECK_LEFTFIX, //!< Leftfix must be in accept state.
ROSE_ROLE_INSTR_SOM_ADJUST, //!< Set SOM from a distance to EOM.
ROSE_ROLE_INSTR_SOM_LEFTFIX, //!< Acquire SOM from a leftfix engine.
ROSE_ROLE_INSTR_TRIGGER_INFIX, //!< Trigger an infix engine.
ROSE_ROLE_INSTR_TRIGGER_SUFFIX, //!< Trigger a suffix engine.
ROSE_ROLE_INSTR_REPORT, //!< Fire an ordinary report.
ROSE_ROLE_INSTR_REPORT_CHAIN, //!< Fire a chained report (MPV).
ROSE_ROLE_INSTR_REPORT_EOD, //!< Fire a callback at EOD time.
ROSE_ROLE_INSTR_REPORT_SOM_INT, //!< Manipulate SOM only.
ROSE_ROLE_INSTR_REPORT_SOM, //!< Manipulate SOM and report.
ROSE_ROLE_INSTR_REPORT_SOM_KNOWN, //!< Rose role knows its SOM offset.
ROSE_ROLE_INSTR_SET_STATE, //!< Switch a state index on.
ROSE_ROLE_INSTR_SET_GROUPS, //!< Set some literal group bits.
ROSE_ROLE_INSTR_END //!< End of program.
};
struct ROSE_ROLE_STRUCT_ANCHORED_DELAY {
u8 code; //!< From enum RoseRoleInstructionCode.
u8 depth; //!< Depth for this state.
rose_group groups; //!< Bitmask.
u32 done_jump; //!< Jump forward this many bytes if successful.
};
struct ROSE_ROLE_STRUCT_CHECK_ONLY_EOD {
u8 code; //!< From enum RoseRoleInstructionCode.
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
struct ROSE_ROLE_STRUCT_CHECK_ROOT_BOUNDS {
u8 code; //!< From enum RoseRoleInstructionCode.
u32 min_bound; //!< Min distance from zero.
u32 max_bound; //!< Max distance from zero (or ROSE_BOUND_INF).
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
struct ROSE_ROLE_STRUCT_CHECK_LOOKAROUND {
u8 code; //!< From enum RoseRoleInstructionCode.
u32 index;
u32 count;
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
struct ROSE_ROLE_STRUCT_CHECK_LEFTFIX {
u8 code; //!< From enum RoseRoleInstructionCode.
u32 queue; //!< Queue of leftfix to check.
u32 lag; //!< Lag of leftfix for this case.
ReportID report; //!< ReportID of leftfix to check.
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
struct ROSE_ROLE_STRUCT_SOM_ADJUST {
u8 code; //!< From enum RoseRoleInstructionCode.
u32 distance; //!< Distance to EOM.
};
struct ROSE_ROLE_STRUCT_SOM_LEFTFIX {
u8 code; //!< From enum RoseRoleInstructionCode.
u32 queue; //!< Queue index of leftfix providing SOM.
u32 lag; //!< Lag of leftfix for this case.
};
struct ROSE_ROLE_STRUCT_TRIGGER_INFIX {
u8 code; //!< From enum RoseRoleInstructionCode.
u8 cancel; //!< Cancels previous top event.
u32 queue; //!< Queue index of infix.
u32 event; //!< Queue event, from MQE_*.
};
struct ROSE_ROLE_STRUCT_TRIGGER_SUFFIX {
u8 code; //!< From enum RoseRoleInstructionCode.
u32 queue; //!< Queue index of suffix.
u32 event; //!< Queue event, from MQE_*.
};
struct ROSE_ROLE_STRUCT_REPORT {
u8 code; //!< From enum RoseRoleInstructionCode.
ReportID report;
};
struct ROSE_ROLE_STRUCT_REPORT_CHAIN {
u8 code; //!< From enum RoseRoleInstructionCode.
ReportID report;
};
struct ROSE_ROLE_STRUCT_REPORT_EOD {
u8 code; //!< From enum RoseRoleInstructionCode.
ReportID report;
};
struct ROSE_ROLE_STRUCT_REPORT_SOM_INT {
u8 code; //!< From enum RoseRoleInstructionCode.
ReportID report;
};
struct ROSE_ROLE_STRUCT_REPORT_SOM {
u8 code; //!< From enum RoseRoleInstructionCode.
ReportID report;
};
struct ROSE_ROLE_STRUCT_REPORT_SOM_KNOWN {
u8 code; //!< From enum RoseRoleInstructionCode.
ReportID report;
};
struct ROSE_ROLE_STRUCT_SET_STATE {
u8 code; //!< From enum RoseRoleInstructionCode.
u8 depth; //!< Depth for this state.
u32 index; //!< State index in multibit.
};
struct ROSE_ROLE_STRUCT_SET_GROUPS {
u8 code; //!< From enum RoseRoleInstructionCode.
rose_group groups; //!< Bitmask.
};
struct ROSE_ROLE_STRUCT_END {
u8 code; //!< From enum RoseRoleInstructionCode.
};
#endif // ROSE_ROSE_PROGRAM_H

View File

@ -100,8 +100,9 @@ std::set<typename C::key_type> assoc_keys(const C &container) {
/**
* \brief Return the length in bytes of the given vector of (POD) objects.
*/
template<typename T>
typename std::vector<T>::size_type byte_length(const std::vector<T> &vec) {
template <typename T, typename Alloc>
typename std::vector<T, Alloc>::size_type
byte_length(const std::vector<T, Alloc> &vec) {
static_assert(std::is_pod<T>::value, "should be pod");
return vec.size() * sizeof(T);
}
@ -110,8 +111,8 @@ typename std::vector<T>::size_type byte_length(const std::vector<T> &vec) {
* \brief Copy the given vector of POD objects to the given location in memory.
* It is safe to give this function an empty vector.
*/
template<typename T>
void *copy_bytes(void *dest, const std::vector<T> &vec) {
template<typename T, typename Alloc>
void *copy_bytes(void *dest, const std::vector<T, Alloc> &vec) {
static_assert(std::is_pod<T>::value, "should be pod");
assert(dest);