limex: rework accept handling

Rather that iterating over NFAAccept structures and testing individual
bits in the state structure, iterate over the state vector and index
into accept structures.

Adds report list support to this path, unified with the report lists
used for exception handling.
This commit is contained in:
Justin Viiret 2016-08-30 14:24:23 +10:00 committed by Matthew Barr
parent 3dcfea19e0
commit 77fe1ef6e5
8 changed files with 374 additions and 219 deletions

View File

@ -46,6 +46,7 @@
#define INITIAL_FN JOIN(moNfaInitial, SIZE) #define INITIAL_FN JOIN(moNfaInitial, SIZE)
#define TOP_FN JOIN(moNfaTop, SIZE) #define TOP_FN JOIN(moNfaTop, SIZE)
#define TOPN_FN JOIN(moNfaTopN, SIZE) #define TOPN_FN JOIN(moNfaTopN, SIZE)
#define PROCESS_ACCEPTS_IMPL_FN JOIN(moProcessAcceptsImpl, SIZE)
#define PROCESS_ACCEPTS_FN JOIN(moProcessAccepts, SIZE) #define PROCESS_ACCEPTS_FN JOIN(moProcessAccepts, SIZE)
#define PROCESS_ACCEPTS_NOSQUASH_FN JOIN(moProcessAcceptsNoSquash, SIZE) #define PROCESS_ACCEPTS_NOSQUASH_FN JOIN(moProcessAcceptsNoSquash, SIZE)
#define CONTEXT_T JOIN(NFAContext, SIZE) #define CONTEXT_T JOIN(NFAContext, SIZE)
@ -60,6 +61,20 @@
#define SQUASH_UNTUG_BR_FN JOIN(lazyTug, SIZE) #define SQUASH_UNTUG_BR_FN JOIN(lazyTug, SIZE)
#define GET_NFA_REPEAT_INFO_FN JOIN(getNfaRepeatInfo, SIZE) #define GET_NFA_REPEAT_INFO_FN JOIN(getNfaRepeatInfo, SIZE)
#if defined(ARCH_64_BIT) && (SIZE >= 64)
#define CHUNK_T u64a
#define FIND_AND_CLEAR_FN findAndClearLSB_64
#define POPCOUNT_FN popcount64
#define RANK_IN_MASK_FN rank_in_mask64
#else
#define CHUNK_T u32
#define FIND_AND_CLEAR_FN findAndClearLSB_32
#define POPCOUNT_FN popcount32
#define RANK_IN_MASK_FN rank_in_mask32
#endif
#define NUM_STATE_CHUNKS (sizeof(STATE_T) / sizeof(CHUNK_T))
static really_inline static really_inline
void SQUASH_UNTUG_BR_FN(const IMPL_NFA_T *limex, void SQUASH_UNTUG_BR_FN(const IMPL_NFA_T *limex,
const union RepeatControl *repeat_ctrl, const union RepeatControl *repeat_ctrl,
@ -98,63 +113,84 @@ void SQUASH_UNTUG_BR_FN(const IMPL_NFA_T *limex,
} }
} }
static never_inline static really_inline
char PROCESS_ACCEPTS_FN(const IMPL_NFA_T *limex, STATE_T *s, char PROCESS_ACCEPTS_IMPL_FN(const IMPL_NFA_T *limex, const STATE_T *s,
const struct NFAAccept *acceptTable, u32 acceptCount, STATE_T *squash, const ENG_STATE_T *squashMasks,
u64a offset, NfaCallback callback, void *context) { const STATE_T *acceptMask,
const struct NFAAccept *acceptTable, u64a offset,
NfaCallback callback, void *context) {
assert(s); assert(s);
assert(limex); assert(limex);
assert(callback); assert(callback);
assert(acceptCount);
const STATE_T accept_mask = *acceptMask;
STATE_T accepts = AND_STATE(*s, accept_mask);
// Caller must ensure that we have at least one accept state on.
assert(ISNONZERO_STATE(accepts));
CHUNK_T chunks[NUM_STATE_CHUNKS];
memcpy(chunks, &accepts, sizeof(accepts));
CHUNK_T mask_chunks[NUM_STATE_CHUNKS];
memcpy(mask_chunks, &accept_mask, sizeof(accept_mask));
u32 base_index = 0; // Cumulative sum of mask popcount up to current chunk.
for (u32 i = 0; i < NUM_STATE_CHUNKS; i++) {
CHUNK_T chunk = chunks[i];
while (chunk != 0) {
u32 bit = FIND_AND_CLEAR_FN(&chunk);
u32 local_idx = RANK_IN_MASK_FN(mask_chunks[i], bit);
u32 idx = local_idx + base_index;
const struct NFAAccept *a = &acceptTable[idx];
DEBUG_PRINTF("state %u: firing report list=%u, offset=%llu\n",
bit + i * (u32)sizeof(chunk) * 8, a->reports, offset);
int rv = limexRunAccept((const char *)limex, a, callback, context,
offset);
if (unlikely(rv == MO_HALT_MATCHING)) {
return 1;
}
if (squash != NULL && a->squash != MO_INVALID_IDX) {
assert(squashMasks);
assert(a->squash < limex->squashCount);
const ENG_STATE_T *sq = &squashMasks[a->squash];
DEBUG_PRINTF("squash mask %u @ %p\n", a->squash, sq);
*squash = AND_STATE(*squash, LOAD_FROM_ENG(sq));
}
}
base_index += POPCOUNT_FN(mask_chunks[i]);
}
return 0;
}
static never_inline
char PROCESS_ACCEPTS_FN(const IMPL_NFA_T *limex, STATE_T *s,
const STATE_T *acceptMask,
const struct NFAAccept *acceptTable, u64a offset,
NfaCallback callback, void *context) {
// We have squash masks we might have to apply after firing reports. // We have squash masks we might have to apply after firing reports.
STATE_T squash = ONES_STATE; STATE_T squash = ONES_STATE;
const ENG_STATE_T *squashMasks = (const ENG_STATE_T *) const ENG_STATE_T *squashMasks = (const ENG_STATE_T *)
((const char *)limex + limex->squashOffset); ((const char *)limex + limex->squashOffset);
for (u32 i = 0; i < acceptCount; i++) { return PROCESS_ACCEPTS_IMPL_FN(limex, s, &squash, squashMasks, acceptMask,
const struct NFAAccept *a = &acceptTable[i]; acceptTable, offset, callback, context);
if (TESTBIT_STATE(*s, a->state)) {
DEBUG_PRINTF("state %u is on, firing report id=%u, offset=%llu\n",
a->state, a->externalId, offset);
int rv = callback(0, offset, a->externalId, context);
if (unlikely(rv == MO_HALT_MATCHING)) {
return 1;
}
if (a->squash != MO_INVALID_IDX) {
assert(a->squash < limex->squashCount);
const ENG_STATE_T *sq = &squashMasks[a->squash];
DEBUG_PRINTF("squash mask %u @ %p\n", a->squash, sq);
squash = AND_STATE(squash, LOAD_FROM_ENG(sq));
}
}
}
*s = AND_STATE(*s, squash); *s = AND_STATE(*s, squash);
return 0;
} }
static never_inline static never_inline
char PROCESS_ACCEPTS_NOSQUASH_FN(const STATE_T *s, char PROCESS_ACCEPTS_NOSQUASH_FN(const IMPL_NFA_T *limex, const STATE_T *s,
const STATE_T *acceptMask,
const struct NFAAccept *acceptTable, const struct NFAAccept *acceptTable,
u32 acceptCount, u64a offset, u64a offset, NfaCallback callback,
NfaCallback callback, void *context) { void *context) {
assert(s); STATE_T *squash = NULL;
assert(callback); const ENG_STATE_T *squashMasks = NULL;
assert(acceptCount);
for (u32 i = 0; i < acceptCount; i++) { return PROCESS_ACCEPTS_IMPL_FN(limex, s, squash, squashMasks, acceptMask,
const struct NFAAccept *a = &acceptTable[i]; acceptTable, offset, callback, context);
if (TESTBIT_STATE(*s, a->state)) {
DEBUG_PRINTF("state %u is on, firing report id=%u, offset=%llu\n",
a->state, a->externalId, offset);
int rv = callback(0, offset, a->externalId, context);
if (unlikely(rv == MO_HALT_MATCHING)) {
return 1;
}
}
}
return 0;
} }
// Run EOD accepts. Note that repeat_ctrl and repeat_state may be NULL if this // Run EOD accepts. Note that repeat_ctrl and repeat_state may be NULL if this
@ -179,8 +215,8 @@ char TESTEOD_FN(const IMPL_NFA_T *limex, const STATE_T *s,
if (unlikely(ISNONZERO_STATE(foundAccepts))) { if (unlikely(ISNONZERO_STATE(foundAccepts))) {
const struct NFAAccept *acceptEodTable = getAcceptEodTable(limex); const struct NFAAccept *acceptEodTable = getAcceptEodTable(limex);
if (PROCESS_ACCEPTS_NOSQUASH_FN(&foundAccepts, acceptEodTable, if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &foundAccepts, &acceptEodMask,
limex->acceptEodCount, offset, callback, acceptEodTable, offset, callback,
context)) { context)) {
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} }
@ -206,8 +242,8 @@ char REPORTCURRENT_FN(const IMPL_NFA_T *limex, const struct mq *q) {
const struct NFAAccept *acceptTable = getAcceptTable(limex); const struct NFAAccept *acceptTable = getAcceptTable(limex);
u64a offset = q_cur_offset(q); u64a offset = q_cur_offset(q);
if (PROCESS_ACCEPTS_NOSQUASH_FN(&foundAccepts, acceptTable, if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &foundAccepts, &acceptMask,
limex->acceptCount, offset, q->cb, acceptTable, offset, q->cb,
q->context)) { q->context)) {
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} }
@ -307,37 +343,45 @@ char LIMEX_INACCEPT_FN(const IMPL_NFA_T *limex, STATE_T state,
u64a offset, ReportID report) { u64a offset, ReportID report) {
assert(limex); assert(limex);
const STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept); const STATE_T accept_mask = LOAD_FROM_ENG(&limex->accept);
STATE_T accstate = AND_STATE(state, acceptMask); STATE_T accepts = AND_STATE(state, accept_mask);
// Are we in an accept state? // Are we in an accept state?
if (ISZERO_STATE(accstate)) { if (ISZERO_STATE(accepts)) {
DEBUG_PRINTF("no accept states are on\n"); DEBUG_PRINTF("no accept states are on\n");
return 0; return 0;
} }
SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &accstate); SQUASH_UNTUG_BR_FN(limex, repeat_ctrl, repeat_state, offset, &accepts);
DEBUG_PRINTF("looking for report %u\n", report); DEBUG_PRINTF("looking for report %u\n", report);
#ifdef DEBUG
DEBUG_PRINTF("accept states that are on: ");
for (u32 i = 0; i < sizeof(STATE_T) * 8; i++) {
if (TESTBIT_STATE(accstate, i)) printf("%u ", i);
}
printf("\n");
#endif
// Does one of our states match the given report ID?
const struct NFAAccept *acceptTable = getAcceptTable(limex); const struct NFAAccept *acceptTable = getAcceptTable(limex);
for (u32 i = 0; i < limex->acceptCount; i++) {
const struct NFAAccept *a = &acceptTable[i]; CHUNK_T chunks[NUM_STATE_CHUNKS];
DEBUG_PRINTF("checking idx=%u, externalId=%u\n", a->state, memcpy(chunks, &accepts, sizeof(accepts));
a->externalId);
if (a->externalId == report && TESTBIT_STATE(accstate, a->state)) { CHUNK_T mask_chunks[NUM_STATE_CHUNKS];
DEBUG_PRINTF("report is on!\n"); memcpy(mask_chunks, &accept_mask, sizeof(accept_mask));
return 1;
u32 base_index = 0; // Cumulative sum of mask popcount up to current chunk.
for (u32 i = 0; i < NUM_STATE_CHUNKS; i++) {
CHUNK_T chunk = chunks[i];
while (chunk != 0) {
u32 bit = FIND_AND_CLEAR_FN(&chunk);
u32 local_idx = RANK_IN_MASK_FN(mask_chunks[i], bit);
u32 idx = local_idx + base_index;
assert(idx < limex->acceptCount);
const struct NFAAccept *a = &acceptTable[idx];
DEBUG_PRINTF("state %u is on, report list at %u\n",
bit + i * (u32)sizeof(chunk) * 8, a->reports);
if (limexAcceptHasReport((const char *)limex, a, report)) {
DEBUG_PRINTF("report %u is on\n", report);
return 1;
}
} }
base_index += POPCOUNT_FN(mask_chunks[i]);
} }
return 0; return 0;
@ -381,7 +425,14 @@ char LIMEX_INANYACCEPT_FN(const IMPL_NFA_T *limex, STATE_T state,
#undef TESTBIT_STATE #undef TESTBIT_STATE
#undef ISNONZERO_STATE #undef ISNONZERO_STATE
#undef ISZERO_STATE #undef ISZERO_STATE
#undef PROCESS_ACCEPTS_IMPL_FN
#undef PROCESS_ACCEPTS_FN #undef PROCESS_ACCEPTS_FN
#undef PROCESS_ACCEPTS_NOSQUASH_FN #undef PROCESS_ACCEPTS_NOSQUASH_FN
#undef SQUASH_UNTUG_BR_FN #undef SQUASH_UNTUG_BR_FN
#undef GET_NFA_REPEAT_INFO_FN #undef GET_NFA_REPEAT_INFO_FN
#undef CHUNK_T
#undef FIND_AND_CLEAR_FN
#undef POPCOUNT_FN
#undef RANK_IN_MASK_FN
#undef NUM_STATE_CHUNKS

View File

@ -992,14 +992,105 @@ void buildAccel(const build_info &args, NFAStateSet &accelMask,
} }
static static
void buildAccepts(const build_info &args, NFAStateSet &acceptMask, u32 addSquashMask(const build_info &args, const NFAVertex &v,
NFAStateSet &acceptEodMask, vector<NFAAccept> &accepts, vector<NFAStateSet> &squash) {
vector<NFAAccept> &acceptsEod, vector<NFAStateSet> &squash) { auto sit = args.reportSquashMap.find(v);
if (sit == args.reportSquashMap.end()) {
return MO_INVALID_IDX;
}
// This state has a squash mask. Paw through the existing vector to
// see if we've already seen it, otherwise add a new one.
auto it = find(squash.begin(), squash.end(), sit->second);
if (it != squash.end()) {
return verify_u32(distance(squash.begin(), it));
}
u32 idx = verify_u32(squash.size());
squash.push_back(sit->second);
return idx;
}
static
u32 addReports(const flat_set<ReportID> &r, vector<ReportID> &reports,
unordered_map<vector<ReportID>, u32> &reportListCache) {
assert(!r.empty());
vector<ReportID> my_reports(begin(r), end(r));
my_reports.push_back(MO_INVALID_IDX); // sentinel
auto cache_it = reportListCache.find(my_reports);
if (cache_it != end(reportListCache)) {
u32 offset = cache_it->second;
DEBUG_PRINTF("reusing cached report list at %u\n", offset);
return offset;
}
auto it = search(begin(reports), end(reports), begin(my_reports),
end(my_reports));
if (it != end(reports)) {
u32 offset = verify_u32(distance(begin(reports), it));
DEBUG_PRINTF("reusing found report list at %u\n", offset);
return offset;
}
u32 offset = verify_u32(reports.size());
insert(&reports, reports.end(), my_reports);
reportListCache.emplace(move(my_reports), offset);
return offset;
}
static
void buildAcceptsList(const build_info &args,
unordered_map<vector<ReportID>, u32> &reports_cache,
vector<NFAVertex> &verts, vector<NFAAccept> &accepts,
vector<ReportID> &reports, vector<NFAStateSet> &squash) {
if (verts.empty()) {
return;
}
DEBUG_PRINTF("building accept lists for %zu states\n", verts.size());
auto cmp_state_id = [&args](NFAVertex a, NFAVertex b) {
u32 a_state = args.state_ids.at(a);
u32 b_state = args.state_ids.at(b);
assert(a_state != b_state || a == b);
return a_state < b_state;
};
sort(begin(verts), end(verts), cmp_state_id);
const NGHolder &h = args.h;
for (const auto &v : verts) {
DEBUG_PRINTF("state=%u, reports: [%s]\n", args.state_ids.at(v),
as_string_list(h[v].reports).c_str());
NFAAccept a;
memset(&a, 0, sizeof(a));
assert(!h[v].reports.empty());
if (h[v].reports.size() == 1) {
a.single_report = 1;
a.reports = *h[v].reports.begin();
} else {
a.single_report = 0;
a.reports = addReports(h[v].reports, reports, reports_cache);
}
a.squash = addSquashMask(args, v, squash);
accepts.push_back(move(a));
}
}
static
void buildAccepts(const build_info &args,
unordered_map<vector<ReportID>, u32> &reports_cache,
NFAStateSet &acceptMask, NFAStateSet &acceptEodMask,
vector<NFAAccept> &accepts, vector<NFAAccept> &acceptsEod,
vector<ReportID> &reports, vector<NFAStateSet> &squash) {
const NGHolder &h = args.h; const NGHolder &h = args.h;
acceptMask.resize(args.num_states); acceptMask.resize(args.num_states);
acceptEodMask.resize(args.num_states); acceptEodMask.resize(args.num_states);
vector<NFAVertex> verts_accept, verts_accept_eod;
for (auto v : vertices_range(h)) { for (auto v : vertices_range(h)) {
u32 state_id = args.state_ids.at(v); u32 state_id = args.state_ids.at(v);
@ -1007,41 +1098,20 @@ void buildAccepts(const build_info &args, NFAStateSet &acceptMask,
continue; continue;
} }
u32 squashMaskOffset = MO_INVALID_IDX;
auto sit = args.reportSquashMap.find(v);
if (sit != args.reportSquashMap.end()) {
// This state has a squash mask. Paw through the existing vector to
// see if we've already seen it, otherwise add a new one.
auto it = find(squash.begin(), squash.end(), sit->second);
if (it != squash.end()) {
squashMaskOffset = verify_u32(distance(squash.begin(), it));
} else {
squashMaskOffset = verify_u32(squash.size());
squash.push_back(sit->second);
}
}
// Add an accept (or acceptEod) per report ID.
vector<NFAAccept> *accepts_out;
if (edge(v, h.accept, h).second) { if (edge(v, h.accept, h).second) {
acceptMask.set(state_id); acceptMask.set(state_id);
accepts_out = &accepts; verts_accept.push_back(v);
} else { } else {
assert(edge(v, h.acceptEod, h).second); assert(edge(v, h.acceptEod, h).second);
acceptEodMask.set(state_id); acceptEodMask.set(state_id);
accepts_out = &acceptsEod; verts_accept_eod.push_back(v);
}
for (auto report : h[v].reports) {
accepts_out->push_back(NFAAccept());
NFAAccept &a = accepts_out->back();
a.state = state_id;
a.externalId = report;
a.squash = squashMaskOffset;
DEBUG_PRINTF("Accept: state=%u, externalId=%u\n", state_id, report);
} }
} }
buildAcceptsList(args, reports_cache, verts_accept, accepts, reports,
squash);
buildAcceptsList(args, reports_cache, verts_accept_eod, acceptsEod, reports,
squash);
} }
static static
@ -1314,36 +1384,12 @@ struct ExceptionProto {
} }
}; };
static
u32 getReportListIndex(const flat_set<ReportID> &reports,
vector<ReportID> &exceptionReports,
map<vector<ReportID>, u32> &reportListCache) {
if (reports.empty()) {
return MO_INVALID_IDX;
}
const vector<ReportID> r(reports.begin(), reports.end());
auto it = reportListCache.find(r);
if (it != reportListCache.end()) {
u32 idx = it->second;
assert(idx < exceptionReports.size());
assert(equal(r.begin(), r.end(), exceptionReports.begin() + idx));
return idx;
}
u32 idx = verify_u32(exceptionReports.size());
reportListCache[r] = idx;
exceptionReports.insert(exceptionReports.end(), r.begin(), r.end());
exceptionReports.push_back(MO_INVALID_IDX); // terminator
return idx;
}
static static
u32 buildExceptionMap(const build_info &args, u32 buildExceptionMap(const build_info &args,
unordered_map<vector<ReportID>, u32> &reports_cache,
const ue2::unordered_set<NFAEdge> &exceptional, const ue2::unordered_set<NFAEdge> &exceptional,
map<ExceptionProto, vector<u32> > &exceptionMap, map<ExceptionProto, vector<u32>> &exceptionMap,
vector<ReportID> &exceptionReports) { vector<ReportID> &reportList) {
const NGHolder &h = args.h; const NGHolder &h = args.h;
const u32 num_states = args.num_states; const u32 num_states = args.num_states;
u32 exceptionCount = 0; u32 exceptionCount = 0;
@ -1361,10 +1407,6 @@ u32 buildExceptionMap(const build_info &args,
} }
} }
// We track report lists that have already been written into the global
// list in case we can reuse them.
map<vector<ReportID>, u32> reportListCache;
for (auto v : vertices_range(h)) { for (auto v : vertices_range(h)) {
const u32 i = args.state_ids.at(v); const u32 i = args.state_ids.at(v);
@ -1383,8 +1425,12 @@ u32 buildExceptionMap(const build_info &args,
DEBUG_PRINTF("state %u is exceptional due to accept " DEBUG_PRINTF("state %u is exceptional due to accept "
"(%zu reports)\n", i, reports.size()); "(%zu reports)\n", i, reports.size());
e.reports_index = if (reports.empty()) {
getReportListIndex(reports, exceptionReports, reportListCache); e.reports_index = MO_INVALID_IDX;
} else {
e.reports_index =
addReports(reports, reportList, reports_cache);
}
// We may be applying a report squash too. // We may be applying a report squash too.
auto mi = args.reportSquashMap.find(v); auto mi = args.reportSquashMap.find(v);
@ -1810,9 +1856,10 @@ struct Factory {
} }
static static
void writeExceptions(const map<ExceptionProto, vector<u32> > &exceptionMap, void writeExceptions(const map<ExceptionProto, vector<u32>> &exceptionMap,
const vector<u32> &repeatOffsets, const vector<u32> &repeatOffsets, implNFA_t *limex,
implNFA_t *limex, const u32 exceptionsOffset) { const u32 exceptionsOffset,
const u32 reportListOffset) {
DEBUG_PRINTF("exceptionsOffset=%u\n", exceptionsOffset); DEBUG_PRINTF("exceptionsOffset=%u\n", exceptionsOffset);
exception_t *etable = (exception_t *)((char *)limex + exceptionsOffset); exception_t *etable = (exception_t *)((char *)limex + exceptionsOffset);
@ -1839,7 +1886,12 @@ struct Factory {
exception_t &e = etable[ecount]; exception_t &e = etable[ecount];
maskSetBits(e.squash, proto.squash_states); maskSetBits(e.squash, proto.squash_states);
maskSetBits(e.successors, proto.succ_states); maskSetBits(e.successors, proto.succ_states);
e.reports = proto.reports_index; if (proto.reports_index == MO_INVALID_IDX) {
e.reports = MO_INVALID_IDX;
} else {
e.reports = reportListOffset +
proto.reports_index * sizeof(ReportID);
}
e.hasSquash = verify_u8(proto.squash); e.hasSquash = verify_u8(proto.squash);
e.trigger = verify_u8(proto.trigger); e.trigger = verify_u8(proto.trigger);
u32 repeat_offset = proto.repeat_index == MO_INVALID_IDX u32 repeat_offset = proto.repeat_index == MO_INVALID_IDX
@ -1958,7 +2010,9 @@ struct Factory {
const vector<NFAAccept> &acceptsEod, const vector<NFAAccept> &acceptsEod,
const vector<NFAStateSet> &squash, implNFA_t *limex, const vector<NFAStateSet> &squash, implNFA_t *limex,
const u32 acceptsOffset, const u32 acceptsEodOffset, const u32 acceptsOffset, const u32 acceptsEodOffset,
const u32 squashOffset) { const u32 squashOffset, const u32 reportListOffset) {
char *limex_base = (char *)limex;
DEBUG_PRINTF("acceptsOffset=%u, acceptsEodOffset=%u, squashOffset=%u\n", DEBUG_PRINTF("acceptsOffset=%u, acceptsEodOffset=%u, squashOffset=%u\n",
acceptsOffset, acceptsEodOffset, squashOffset); acceptsOffset, acceptsEodOffset, squashOffset);
@ -1966,27 +2020,38 @@ struct Factory {
maskSetBits(limex->accept, acceptMask); maskSetBits(limex->accept, acceptMask);
maskSetBits(limex->acceptAtEOD, acceptEodMask); maskSetBits(limex->acceptAtEOD, acceptEodMask);
// Transforms the index into the report list into an offset relative to
// the base of the limex.
auto report_offset_fn = [&](NFAAccept a) {
if (!a.single_report) {
a.reports = reportListOffset + a.reports * sizeof(ReportID);
}
return a;
};
// Write accept table. // Write accept table.
limex->acceptOffset = acceptsOffset; limex->acceptOffset = acceptsOffset;
limex->acceptCount = verify_u32(accepts.size()); limex->acceptCount = verify_u32(accepts.size());
DEBUG_PRINTF("NFA has %zu accepts\n", accepts.size()); DEBUG_PRINTF("NFA has %zu accepts\n", accepts.size());
NFAAccept *acceptsTable = (NFAAccept *)((char *)limex + acceptsOffset); NFAAccept *acceptsTable = (NFAAccept *)(limex_base + acceptsOffset);
assert(ISALIGNED(acceptsTable)); assert(ISALIGNED(acceptsTable));
copy(accepts.begin(), accepts.end(), acceptsTable); transform(accepts.begin(), accepts.end(), acceptsTable,
report_offset_fn);
// Write eod accept table. // Write eod accept table.
limex->acceptEodOffset = acceptsEodOffset; limex->acceptEodOffset = acceptsEodOffset;
limex->acceptEodCount = verify_u32(acceptsEod.size()); limex->acceptEodCount = verify_u32(acceptsEod.size());
DEBUG_PRINTF("NFA has %zu EOD accepts\n", acceptsEod.size()); DEBUG_PRINTF("NFA has %zu EOD accepts\n", acceptsEod.size());
NFAAccept *acceptsEodTable = (NFAAccept *)((char *)limex + acceptsEodOffset); NFAAccept *acceptsEodTable = (NFAAccept *)(limex_base + acceptsEodOffset);
assert(ISALIGNED(acceptsEodTable)); assert(ISALIGNED(acceptsEodTable));
copy(acceptsEod.begin(), acceptsEod.end(), acceptsEodTable); transform(acceptsEod.begin(), acceptsEod.end(), acceptsEodTable,
report_offset_fn);
// Write squash mask table. // Write squash mask table.
limex->squashCount = verify_u32(squash.size()); limex->squashCount = verify_u32(squash.size());
limex->squashOffset = squashOffset; limex->squashOffset = squashOffset;
DEBUG_PRINTF("NFA has %zu report squash masks\n", squash.size()); DEBUG_PRINTF("NFA has %zu report squash masks\n", squash.size());
tableRow_t *mask = (tableRow_t *)((char *)limex + squashOffset); tableRow_t *mask = (tableRow_t *)(limex_base + squashOffset);
assert(ISALIGNED(mask)); assert(ISALIGNED(mask));
for (size_t i = 0, end = squash.size(); i < end; i++) { for (size_t i = 0, end = squash.size(); i < end; i++) {
maskSetBits(mask[i], squash[i]); maskSetBits(mask[i], squash[i]);
@ -2023,15 +2088,12 @@ struct Factory {
} }
static static
void writeExceptionReports(const vector<ReportID> &reports, void writeReportList(const vector<ReportID> &reports, implNFA_t *limex,
implNFA_t *limex, const u32 reportListOffset) {
const u32 exceptionReportsOffset) { DEBUG_PRINTF("reportListOffset=%u\n", reportListOffset);
DEBUG_PRINTF("exceptionReportsOffset=%u\n", exceptionReportsOffset); assert(ISALIGNED_N((char *)limex + reportListOffset,
limex->exReportOffset = exceptionReportsOffset;
assert(ISALIGNED_N((char *)limex + exceptionReportsOffset,
alignof(ReportID))); alignof(ReportID)));
copy_bytes((char *)limex + exceptionReportsOffset, reports); copy_bytes((char *)limex + reportListOffset, reports);
} }
static static
@ -2050,6 +2112,10 @@ struct Factory {
repeatSize += repeats[i].second; repeatSize += repeats[i].second;
} }
// We track report lists that have already been written into the global
// list in case we can reuse them.
unordered_map<vector<ReportID>, u32> reports_cache;
ue2::unordered_set<NFAEdge> exceptional; ue2::unordered_set<NFAEdge> exceptional;
u32 shiftCount = findBestNumOfVarShifts(args); u32 shiftCount = findBestNumOfVarShifts(args);
assert(shiftCount); assert(shiftCount);
@ -2057,9 +2123,10 @@ struct Factory {
findExceptionalTransitions(args, exceptional, maxShift); findExceptionalTransitions(args, exceptional, maxShift);
map<ExceptionProto, vector<u32> > exceptionMap; map<ExceptionProto, vector<u32> > exceptionMap;
vector<ReportID> exceptionReports; vector<ReportID> reportList;
u32 exceptionCount = buildExceptionMap(args, exceptional, exceptionMap,
exceptionReports); u32 exceptionCount = buildExceptionMap(args, reports_cache, exceptional,
exceptionMap, reportList);
assert(exceptionCount <= args.num_states); assert(exceptionCount <= args.num_states);
@ -2076,8 +2143,8 @@ struct Factory {
NFAStateSet acceptMask, acceptEodMask; NFAStateSet acceptMask, acceptEodMask;
vector<NFAAccept> accepts, acceptsEod; vector<NFAAccept> accepts, acceptsEod;
vector<NFAStateSet> squash; vector<NFAStateSet> squash;
buildAccepts(args, acceptMask, acceptEodMask, accepts, acceptsEod, buildAccepts(args, reports_cache, acceptMask, acceptEodMask, accepts,
squash); acceptsEod, reportList, squash);
// Build all our accel info. // Build all our accel info.
NFAStateSet accelMask, accelFriendsMask; NFAStateSet accelMask, accelFriendsMask;
@ -2118,8 +2185,8 @@ struct Factory {
const u32 exceptionsOffset = offset; const u32 exceptionsOffset = offset;
offset += sizeof(exception_t) * exceptionCount; offset += sizeof(exception_t) * exceptionCount;
const u32 exceptionReportsOffset = offset; const u32 reportListOffset = offset;
offset += sizeof(ReportID) * exceptionReports.size(); offset += sizeof(ReportID) * reportList.size();
const u32 repeatOffsetsOffset = offset; const u32 repeatOffsetsOffset = offset;
offset += sizeof(u32) * args.repeats.size(); offset += sizeof(u32) * args.repeats.size();
@ -2146,7 +2213,8 @@ struct Factory {
limex, accelTableOffset, accelAuxOffset); limex, accelTableOffset, accelAuxOffset);
writeAccepts(acceptMask, acceptEodMask, accepts, acceptsEod, squash, writeAccepts(acceptMask, acceptEodMask, accepts, acceptsEod, squash,
limex, acceptsOffset, acceptsEodOffset, squashOffset); limex, acceptsOffset, acceptsEodOffset, squashOffset,
reportListOffset);
limex->shiftCount = shiftCount; limex->shiftCount = shiftCount;
writeShiftMasks(args, limex); writeShiftMasks(args, limex);
@ -2154,14 +2222,15 @@ struct Factory {
// Determine the state required for our state vector. // Determine the state required for our state vector.
findStateSize(args, limex); findStateSize(args, limex);
writeExceptionReports(exceptionReports, limex, exceptionReportsOffset); writeReportList(reportList, limex, reportListOffset);
// Repeat structures and offset table. // Repeat structures and offset table.
vector<u32> repeatOffsets; vector<u32> repeatOffsets;
writeRepeats(repeats, repeatOffsets, limex, repeatOffsetsOffset, writeRepeats(repeats, repeatOffsets, limex, repeatOffsetsOffset,
repeatsOffset); repeatsOffset);
writeExceptions(exceptionMap, repeatOffsets, limex, exceptionsOffset); writeExceptions(exceptionMap, repeatOffsets, limex, exceptionsOffset,
reportListOffset);
writeLimexMasks(args, limex); writeLimexMasks(args, limex);

View File

@ -180,26 +180,40 @@ void dumpAccel(const limex_type *limex, FILE *f) {
} }
} }
static
void dumpAcceptList(const char *limex_base, const struct NFAAccept *accepts,
u32 acceptCount, FILE *f) {
for (u32 i = 0; i < acceptCount; i++) {
const NFAAccept &a = accepts[i];
if (a.single_report) {
fprintf(f, " idx %u fires single report %u\n", i, a.reports);
continue;
}
fprintf(f, " idx %u fires report list %u:", i, a.reports);
const ReportID *report = (const ReportID *)(limex_base + a.reports);
for (; *report != MO_INVALID_IDX; report++) {
fprintf(f, " %u", *report);
}
fprintf(f, "\n");
}
}
template<typename limex_type> template<typename limex_type>
static static
void dumpAccepts(const limex_type *limex, FILE *f) { void dumpAccepts(const limex_type *limex, FILE *f) {
u32 acceptCount = limex->acceptCount; const char *limex_base = (const char *)limex;
u32 acceptEodCount = limex->acceptEodCount;
const u32 acceptCount = limex->acceptCount;
const u32 acceptEodCount = limex->acceptEodCount;
fprintf(f, "\n%u accepts.\n", acceptCount); fprintf(f, "\n%u accepts.\n", acceptCount);
const struct NFAAccept *accepts const auto *accepts =
= (const struct NFAAccept *)((const char *)limex + limex->acceptOffset); (const struct NFAAccept *)(limex_base + limex->acceptOffset);
for (u32 i = 0; i < acceptCount; i++) { dumpAcceptList(limex_base, accepts, acceptCount, f);
fprintf(f, " state %u fires report %u\n", accepts[i].state,
accepts[i].externalId);
}
fprintf(f, "\n%u accepts at EOD.\n", acceptEodCount); fprintf(f, "\n%u accepts at EOD.\n", acceptEodCount);
accepts = (const struct NFAAccept *)((const char *)limex const auto *accepts_eod =
+ limex->acceptEodOffset); (const struct NFAAccept *)(limex_base + limex->acceptEodOffset);
for (u32 i = 0; i < acceptEodCount; i++) { dumpAcceptList(limex_base, accepts_eod, acceptEodCount, f);
fprintf(f, " state %u fires report %u\n", accepts[i].state,
accepts[i].externalId);
}
fprintf(f, "\n"); fprintf(f, "\n");
} }
@ -226,20 +240,15 @@ getExceptionTable(const limex_type *limex) {
((const char *)limex + limex->exceptionOffset); ((const char *)limex + limex->exceptionOffset);
} }
template<typename limex_type>
static
const ReportID *getReportList(const limex_type *limex) {
return (const ReportID *)((const char *)limex + limex->exReportOffset);
}
template<typename limex_type> template<typename limex_type>
static static
void dumpLimexExceptions(const limex_type *limex, FILE *f) { void dumpLimexExceptions(const limex_type *limex, FILE *f) {
const typename limex_traits<limex_type>::exception_type *e = const typename limex_traits<limex_type>::exception_type *e =
getExceptionTable(limex); getExceptionTable(limex);
const ReportID *reports = getReportList(limex);
const u32 size = limex_traits<limex_type>::size; const u32 size = limex_traits<limex_type>::size;
const char *limex_base = (const char *)limex;
fprintf(f, "\n"); fprintf(f, "\n");
for (u32 i = 0; i < limex->exceptionCount; i++) { for (u32 i = 0; i < limex->exceptionCount; i++) {
fprintf(f, "exception %u: hasSquash=%u, reports offset=%u\n", fprintf(f, "exception %u: hasSquash=%u, reports offset=%u\n",
@ -255,7 +264,7 @@ void dumpLimexExceptions(const limex_type *limex, FILE *f) {
if (e[i].reports == MO_INVALID_IDX) { if (e[i].reports == MO_INVALID_IDX) {
fprintf(f, " <none>\n"); fprintf(f, " <none>\n");
} else { } else {
const ReportID *r = reports + e[i].reports; const ReportID *r = (const ReportID *)(limex_base + e[i].reports);
while (*r != MO_INVALID_IDX) { while (*r != MO_INVALID_IDX) {
fprintf(f, " %u", *r++); fprintf(f, " %u", *r++);
} }

View File

@ -95,7 +95,6 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
STATE_T *local_succ, STATE_T *local_succ,
#endif #endif
const struct IMPL_NFA_T *limex, const struct IMPL_NFA_T *limex,
const ReportID *exReports,
u64a offset, u64a offset,
struct CONTEXT_T *ctx, struct CONTEXT_T *ctx,
struct proto_cache *new_cache, struct proto_cache *new_cache,
@ -161,7 +160,8 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
// Some exceptions fire accepts. // Some exceptions fire accepts.
if (e->reports != MO_INVALID_IDX) { if (e->reports != MO_INVALID_IDX) {
if (flags & CALLBACK_OUTPUT) { if (flags & CALLBACK_OUTPUT) {
const ReportID *reports = exReports + e->reports; const ReportID *reports =
(const ReportID *)((const char *)limex + e->reports);
if (unlikely(limexRunReports(reports, ctx->callback, if (unlikely(limexRunReports(reports, ctx->callback,
ctx->context, offset) ctx->context, offset)
== MO_HALT_MATCHING)) { == MO_HALT_MATCHING)) {
@ -210,8 +210,7 @@ int RUN_EXCEPTION_FN(const EXCEPTION_T *e, STATE_ARG,
static really_inline static really_inline
int PE_FN(STATE_ARG, ESTATE_ARG, u32 diffmask, STATE_T *succ, int PE_FN(STATE_ARG, ESTATE_ARG, u32 diffmask, STATE_T *succ,
const struct IMPL_NFA_T *limex, const EXCEPTION_T *exceptions, const struct IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
const ReportID *exReports, u64a offset, struct CONTEXT_T *ctx, u64a offset, struct CONTEXT_T *ctx, char in_rev, char flags) {
char in_rev, char flags) {
assert(diffmask > 0); // guaranteed by caller macro assert(diffmask > 0); // guaranteed by caller macro
if (EQ_STATE(estate, ctx->cached_estate)) { if (EQ_STATE(estate, ctx->cached_estate)) {
@ -271,8 +270,8 @@ int PE_FN(STATE_ARG, ESTATE_ARG, u32 diffmask, STATE_T *succ,
#ifndef BIG_MODEL #ifndef BIG_MODEL
&local_succ, &local_succ,
#endif #endif
limex, exReports, offset, ctx, &new_cache, limex, offset, ctx, &new_cache, &cacheable,
&cacheable, in_rev, flags)) { in_rev, flags)) {
return PE_RV_HALT; return PE_RV_HALT;
} }
} while (word); } while (word);
@ -326,7 +325,9 @@ int PE_FN(STATE_ARG, ESTATE_ARG, u32 diffmask, STATE_T *succ,
#undef STATE_ARG_NAME #undef STATE_ARG_NAME
#undef STATE_ARG_P #undef STATE_ARG_P
#undef IMPL_NFA_T
#undef CHUNK_T #undef CHUNK_T
#undef FIND_AND_CLEAR_FN #undef FIND_AND_CLEAR_FN
#undef IMPL_NFA_T #undef POPCOUNT_FN
#undef GET_NFA_REPEAT_INFO_FN #undef RANK_IN_MASK_FN

View File

@ -132,7 +132,6 @@ struct LimExNFA##size { \
u32 acceptEodOffset; /* rel. to start of LimExNFA */ \ u32 acceptEodOffset; /* rel. to start of LimExNFA */ \
u32 exceptionCount; \ u32 exceptionCount; \
u32 exceptionOffset; /* rel. to start of LimExNFA */ \ u32 exceptionOffset; /* rel. to start of LimExNFA */ \
u32 exReportOffset; /* rel. to start of LimExNFA */ \
u32 repeatCount; \ u32 repeatCount; \
u32 repeatOffset; \ u32 repeatOffset; \
u32 squashOffset; /* rel. to start of LimExNFA; for accept squashing */ \ u32 squashOffset; /* rel. to start of LimExNFA; for accept squashing */ \
@ -184,9 +183,16 @@ struct NFARepeatInfo {
}; };
struct NFAAccept { struct NFAAccept {
u32 state; //!< state ID of triggering state u8 single_report; //!< If true, 'reports' is report id.
ReportID externalId; //!< report ID to raise
u32 squash; //!< offset into masks, or MO_INVALID_IDX /**
* \brief If single report is true, this is the report id to fire.
* Otherwise, it is the offset (relative to the start of the LimExNFA
* structure) of a list of reports, terminated with MO_INVALID_IDX.
*/
u32 reports;
u32 squash; //!< Offset into squash masks, or MO_INVALID_IDX.
}; };
#endif #endif

View File

@ -73,8 +73,7 @@
static really_inline static really_inline
int processExceptional32(u32 s, u32 estate, UNUSED u32 diffmask, u32 *succ, int processExceptional32(u32 s, u32 estate, UNUSED u32 diffmask, u32 *succ,
const struct LimExNFA32 *limex, const struct LimExNFA32 *limex,
const struct NFAException32 *exceptions, const struct NFAException32 *exceptions, u64a offset,
const ReportID *exReports, u64a offset,
struct NFAContext32 *ctx, char in_rev, char flags) { struct NFAContext32 *ctx, char in_rev, char flags) {
assert(estate != 0); // guaranteed by calling macro assert(estate != 0); // guaranteed by calling macro
@ -104,8 +103,8 @@ int processExceptional32(u32 s, u32 estate, UNUSED u32 diffmask, u32 *succ,
u32 bit = findAndClearLSB_32(&estate); u32 bit = findAndClearLSB_32(&estate);
u32 idx = rank_in_mask32(limex->exceptionMask, bit); u32 idx = rank_in_mask32(limex->exceptionMask, bit);
const struct NFAException32 *e = &exceptions[idx]; const struct NFAException32 *e = &exceptions[idx];
if (!runException32(e, s, succ, &local_succ, limex, exReports, offset, if (!runException32(e, s, succ, &local_succ, limex, offset, ctx,
ctx, &new_cache, &cacheable, in_rev, flags)) { &new_cache, &cacheable, in_rev, flags)) {
return PE_RV_HALT; return PE_RV_HALT;
} }
} while (estate != 0); } while (estate != 0);

View File

@ -103,14 +103,42 @@ int limexRunReports(const ReportID *reports, NfaCallback callback,
return MO_CONTINUE_MATCHING; // continue return MO_CONTINUE_MATCHING; // continue
} }
static really_inline
int limexRunAccept(const char *limex_base, const struct NFAAccept *accept,
NfaCallback callback, void *context, u64a offset) {
if (accept->single_report) {
const ReportID report = accept->reports;
DEBUG_PRINTF("firing single report for id %u at offset %llu\n", report,
offset);
return callback(0, offset, report, context);
}
const ReportID *reports = (const ReportID *)(limex_base + accept->reports);
return limexRunReports(reports, callback, context, offset);
}
static really_inline
int limexAcceptHasReport(const char *limex_base, const struct NFAAccept *accept,
ReportID report) {
if (accept->single_report) {
return accept->reports == report;
}
const ReportID *reports = (const ReportID *)(limex_base + accept->reports);
assert(*reports != MO_INVALID_IDX);
do {
if (*reports == report) {
return 1;
}
reports++;
} while (*reports != MO_INVALID_IDX);
return 0;
}
/** \brief Return a (correctly typed) pointer to the exception table. */ /** \brief Return a (correctly typed) pointer to the exception table. */
#define getExceptionTable(exc_type, lim) \ #define getExceptionTable(exc_type, lim) \
((const exc_type *)((const char *)(lim) + (lim)->exceptionOffset)) ((const exc_type *)((const char *)(lim) + (lim)->exceptionOffset))
/** \brief Return a pointer to the exceptional reports list. */
#define getExReports(lim) \
((const ReportID *)((const char *)(lim) + (lim)->exReportOffset))
/** \brief Return a pointer to the ordinary accepts table. */ /** \brief Return a pointer to the ordinary accepts table. */
#define getAcceptTable(lim) \ #define getAcceptTable(lim) \
((const struct NFAAccept *)((const char *)(lim) + (lim)->acceptOffset)) ((const struct NFAAccept *)((const char *)(lim) + (lim)->acceptOffset))

View File

@ -103,8 +103,7 @@
// continue, 1 if an accept was fired and the user instructed us to halt. // continue, 1 if an accept was fired and the user instructed us to halt.
static really_inline static really_inline
char RUN_EXCEPTIONS_FN(const IMPL_NFA_T *limex, const EXCEPTION_T *exceptions, char RUN_EXCEPTIONS_FN(const IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
const ReportID *exReports, STATE_T s, STATE_T s, const STATE_T emask, size_t i, u64a offset,
const STATE_T emask, size_t i, u64a offset,
STATE_T *succ, u64a *final_loc, struct CONTEXT_T *ctx, STATE_T *succ, u64a *final_loc, struct CONTEXT_T *ctx,
const char flags, const char in_rev, const char flags, const char in_rev,
const char first_match) { const char first_match) {
@ -131,7 +130,7 @@ char RUN_EXCEPTIONS_FN(const IMPL_NFA_T *limex, const EXCEPTION_T *exceptions,
char localflags = (!i && !in_rev) ? NO_OUTPUT | FIRST_BYTE : flags; char localflags = (!i && !in_rev) ? NO_OUTPUT | FIRST_BYTE : flags;
int rv = JOIN(processExceptional, SIZE)( int rv = JOIN(processExceptional, SIZE)(
pass_state, pass_estate, diffmask, succ, limex, exceptions, exReports, pass_state, pass_estate, diffmask, succ, limex, exceptions,
callback_offset, ctx, in_rev, localflags); callback_offset, ctx, in_rev, localflags);
if (rv == PE_RV_HALT) { if (rv == PE_RV_HALT) {
return 1; // Halt matching. return 1; // Halt matching.
@ -207,7 +206,6 @@ char STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
const union AccelAux *accelAux = const union AccelAux *accelAux =
(const union AccelAux *)((const char *)limex + limex->accelAuxOffset); (const union AccelAux *)((const char *)limex + limex->accelAuxOffset);
const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex); const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
const ReportID *exReports = getExReports(limex);
STATE_T s = ctx->s; STATE_T s = ctx->s;
/* assert(ISALIGNED_16(exceptions)); */ /* assert(ISALIGNED_16(exceptions)); */
@ -235,9 +233,8 @@ without_accel:
STATE_T succ; STATE_T succ;
NFA_EXEC_GET_LIM_SUCC(limex, s, succ); NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, s, EXCEPTION_MASK, if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
i, offset, &succ, final_loc, ctx, flags, 0, &succ, final_loc, ctx, flags, 0, first_match)) {
first_match)) {
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} }
@ -286,9 +283,8 @@ with_accel:
STATE_T succ; STATE_T succ;
NFA_EXEC_GET_LIM_SUCC(limex, s, succ); NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, s, EXCEPTION_MASK, if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
i, offset, &succ, final_loc, ctx, flags, 0, &succ, final_loc, ctx, flags, 0, first_match)) {
first_match)) {
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} }
@ -300,8 +296,6 @@ with_accel:
if ((first_match || (flags & CALLBACK_OUTPUT)) && limex->acceptCount) { if ((first_match || (flags & CALLBACK_OUTPUT)) && limex->acceptCount) {
STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept); STATE_T acceptMask = LOAD_FROM_ENG(&limex->accept);
const struct NFAAccept *acceptTable = getAcceptTable(limex); const struct NFAAccept *acceptTable = getAcceptTable(limex);
const u32 acceptCount = limex->acceptCount;
STATE_T foundAccepts = AND_STATE(s, acceptMask); STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) { if (unlikely(ISNONZERO_STATE(foundAccepts))) {
if (first_match) { if (first_match) {
@ -309,8 +303,8 @@ with_accel:
assert(final_loc); assert(final_loc);
*final_loc = length; *final_loc = length;
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} else if (PROCESS_ACCEPTS_FN(limex, &ctx->s, acceptTable, } else if (PROCESS_ACCEPTS_FN(limex, &ctx->s, &acceptMask,
acceptCount, offset + length, acceptTable, offset + length,
ctx->callback, ctx->context)) { ctx->callback, ctx->context)) {
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} }
@ -331,7 +325,6 @@ char REV_STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask); const STATE_T exceptionMask = LOAD_FROM_ENG(&limex->exceptionMask);
#endif #endif
const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex); const EXCEPTION_T *exceptions = getExceptionTable(EXCEPTION_T, limex);
const ReportID *exReports = getExReports(limex);
STATE_T s = ctx->s; STATE_T s = ctx->s;
/* assert(ISALIGNED_16(exceptions)); */ /* assert(ISALIGNED_16(exceptions)); */
@ -351,9 +344,8 @@ char REV_STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
STATE_T succ; STATE_T succ;
NFA_EXEC_GET_LIM_SUCC(limex, s, succ); NFA_EXEC_GET_LIM_SUCC(limex, s, succ);
if (RUN_EXCEPTIONS_FN(limex, exceptions, exReports, s, if (RUN_EXCEPTIONS_FN(limex, exceptions, s, EXCEPTION_MASK, i, offset,
EXCEPTION_MASK, i, offset, &succ, final_loc, ctx, &succ, final_loc, ctx, flags, 1, 0)) {
flags, 1, 0)) {
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} }
@ -369,8 +361,8 @@ char REV_STREAM_FN(const IMPL_NFA_T *limex, const u8 *input, size_t length,
if (acceptCount) { if (acceptCount) {
STATE_T foundAccepts = AND_STATE(s, acceptMask); STATE_T foundAccepts = AND_STATE(s, acceptMask);
if (unlikely(ISNONZERO_STATE(foundAccepts))) { if (unlikely(ISNONZERO_STATE(foundAccepts))) {
if (PROCESS_ACCEPTS_NOSQUASH_FN(&ctx->s, acceptTable, acceptCount, if (PROCESS_ACCEPTS_NOSQUASH_FN(limex, &ctx->s, &acceptMask,
offset, ctx->callback, acceptTable, offset, ctx->callback,
ctx->context)) { ctx->context)) {
return MO_HALT_MATCHING; return MO_HALT_MATCHING;
} }