mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-09-29 19:24:25 +03:00
rose/hwlm: limit literals to eight bytes
Rework HWLM to work over literals of eight bytes ("medium length"), doing confirm in the Rose interpreter.
This commit is contained in:
committed by
Matthew Barr
parent
5c9c540424
commit
07a6b6510c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016, Intel Corporation
|
||||
* Copyright (c) 2015-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -1409,6 +1409,68 @@ int roseCheckLongLiteral(const struct RoseEngine *t,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static rose_inline
|
||||
int roseCheckMediumLiteral(const struct RoseEngine *t,
|
||||
const struct hs_scratch *scratch, u64a end,
|
||||
u32 lit_offset, u32 lit_length, char nocase) {
|
||||
const struct core_info *ci = &scratch->core_info;
|
||||
const u8 *lit = getByOffset(t, lit_offset);
|
||||
|
||||
DEBUG_PRINTF("check lit at %llu, length %u\n", end, lit_length);
|
||||
DEBUG_PRINTF("base buf_offset=%llu\n", ci->buf_offset);
|
||||
|
||||
if (end < lit_length) {
|
||||
DEBUG_PRINTF("too short!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If any portion of the literal matched in the current buffer, check it.
|
||||
if (end > ci->buf_offset) {
|
||||
u32 scan_len = MIN(end - ci->buf_offset, lit_length);
|
||||
u64a scan_start = end - ci->buf_offset - scan_len;
|
||||
DEBUG_PRINTF("checking suffix (%u bytes) in buf[%llu:%llu]\n", scan_len,
|
||||
scan_start, end);
|
||||
if (cmpForward(ci->buf + scan_start, lit + lit_length - scan_len,
|
||||
scan_len, nocase)) {
|
||||
DEBUG_PRINTF("cmp of suffix failed\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If the entirety of the literal was in the current block, we are done.
|
||||
if (end - lit_length >= ci->buf_offset) {
|
||||
DEBUG_PRINTF("literal confirmed in current block\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// We still have a prefix which we must test against the history buffer.
|
||||
assert(t->mode != HS_MODE_BLOCK);
|
||||
|
||||
u64a lit_start_offset = end - lit_length;
|
||||
u32 prefix_len = MIN(lit_length, ci->buf_offset - lit_start_offset);
|
||||
u32 hist_rewind = ci->buf_offset - lit_start_offset;
|
||||
DEBUG_PRINTF("hlen=%zu, hist_rewind=%u\n", ci->hlen, hist_rewind);
|
||||
|
||||
// History length check required for confirm in the EOD and delayed
|
||||
// rebuild paths.
|
||||
if (hist_rewind > ci->hlen) {
|
||||
DEBUG_PRINTF("not enough history\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("check prefix len=%u from hist (len %zu, rewind %u)\n",
|
||||
prefix_len, ci->hlen, hist_rewind);
|
||||
assert(hist_rewind <= ci->hlen);
|
||||
if (cmpForward(ci->hbuf + ci->hlen - hist_rewind, lit, prefix_len,
|
||||
nocase)) {
|
||||
DEBUG_PRINTF("cmp of prefix failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("cmp succeeded\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
void updateSeqPoint(struct RoseContext *tctxt, u64a offset,
|
||||
const char from_mpv) {
|
||||
@@ -2060,8 +2122,10 @@ hwlmcb_rv_t roseRunProgram_i(const struct RoseEngine *t,
|
||||
const char nocase = 0;
|
||||
if (!roseCheckLongLiteral(t, scratch, end, ri->lit_offset,
|
||||
ri->lit_length, nocase)) {
|
||||
DEBUG_PRINTF("halt: failed long lit check\n");
|
||||
return HWLM_CONTINUE_MATCHING;
|
||||
DEBUG_PRINTF("failed long lit check\n");
|
||||
assert(ri->fail_jump); // must progress
|
||||
pc += ri->fail_jump;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
@@ -2070,8 +2134,34 @@ hwlmcb_rv_t roseRunProgram_i(const struct RoseEngine *t,
|
||||
const char nocase = 1;
|
||||
if (!roseCheckLongLiteral(t, scratch, end, ri->lit_offset,
|
||||
ri->lit_length, nocase)) {
|
||||
DEBUG_PRINTF("halt: failed nocase long lit check\n");
|
||||
return HWLM_CONTINUE_MATCHING;
|
||||
DEBUG_PRINTF("failed nocase long lit check\n");
|
||||
assert(ri->fail_jump); // must progress
|
||||
pc += ri->fail_jump;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
|
||||
PROGRAM_CASE(CHECK_MED_LIT) {
|
||||
const char nocase = 0;
|
||||
if (!roseCheckMediumLiteral(t, scratch, end, ri->lit_offset,
|
||||
ri->lit_length, nocase)) {
|
||||
DEBUG_PRINTF("failed lit check\n");
|
||||
assert(ri->fail_jump); // must progress
|
||||
pc += ri->fail_jump;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
|
||||
PROGRAM_CASE(CHECK_MED_LIT_NOCASE) {
|
||||
const char nocase = 1;
|
||||
if (!roseCheckMediumLiteral(t, scratch, end, ri->lit_offset,
|
||||
ri->lit_length, nocase)) {
|
||||
DEBUG_PRINTF("failed long lit check\n");
|
||||
assert(ri->fail_jump); // must progress
|
||||
pc += ri->fail_jump;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
|
@@ -4353,13 +4353,18 @@ static
|
||||
void makeCheckLiteralInstruction(const RoseBuildImpl &build,
|
||||
const build_context &bc, u32 final_id,
|
||||
RoseProgram &program) {
|
||||
assert(bc.longLitLengthThreshold > 0);
|
||||
|
||||
DEBUG_PRINTF("final_id %u, long lit threshold %zu\n", final_id,
|
||||
bc.longLitLengthThreshold);
|
||||
|
||||
const auto &lits = build.final_id_to_literal.at(final_id);
|
||||
if (lits.size() != 1) {
|
||||
// Long literals should not share a final_id.
|
||||
// final_id sharing is only allowed for literals that are short enough
|
||||
// to not require any additional confirm work.
|
||||
assert(all_of(begin(lits), end(lits), [&](u32 lit_id) {
|
||||
const rose_literal_id &lit = build.literals.right.at(lit_id);
|
||||
return lit.table != ROSE_FLOATING ||
|
||||
lit.s.length() <= bc.longLitLengthThreshold;
|
||||
return lit.s.length() <= ROSE_SHORT_LITERAL_LEN_MAX;
|
||||
}));
|
||||
return;
|
||||
}
|
||||
@@ -4370,11 +4375,9 @@ void makeCheckLiteralInstruction(const RoseBuildImpl &build,
|
||||
}
|
||||
|
||||
const rose_literal_id &lit = build.literals.right.at(lit_id);
|
||||
if (lit.table != ROSE_FLOATING) {
|
||||
return;
|
||||
}
|
||||
assert(bc.longLitLengthThreshold > 0);
|
||||
if (lit.s.length() <= bc.longLitLengthThreshold) {
|
||||
|
||||
if (lit.s.length() <= ROSE_SHORT_LITERAL_LEN_MAX) {
|
||||
DEBUG_PRINTF("lit short enough to not need confirm\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4383,11 +4386,34 @@ void makeCheckLiteralInstruction(const RoseBuildImpl &build,
|
||||
throw ResourceLimitError();
|
||||
}
|
||||
|
||||
if (lit.s.length() <= bc.longLitLengthThreshold) {
|
||||
DEBUG_PRINTF("is a medium-length literal\n");
|
||||
const auto *end_inst = program.end_instruction();
|
||||
unique_ptr<RoseInstruction> ri;
|
||||
if (lit.s.any_nocase()) {
|
||||
ri = make_unique<RoseInstrCheckMedLitNocase>(lit.s.get_string(),
|
||||
end_inst);
|
||||
} else {
|
||||
ri = make_unique<RoseInstrCheckMedLit>(lit.s.get_string(),
|
||||
end_inst);
|
||||
}
|
||||
program.add_before_end(move(ri));
|
||||
return;
|
||||
}
|
||||
|
||||
// Long literal support should only really be used for the floating table
|
||||
// in streaming mode.
|
||||
assert(lit.table == ROSE_FLOATING && build.cc.streaming);
|
||||
|
||||
DEBUG_PRINTF("is a long literal\n");
|
||||
|
||||
const auto *end_inst = program.end_instruction();
|
||||
unique_ptr<RoseInstruction> ri;
|
||||
if (lit.s.any_nocase()) {
|
||||
ri = make_unique<RoseInstrCheckLongLitNocase>(lit.s.get_string());
|
||||
ri = make_unique<RoseInstrCheckLongLitNocase>(lit.s.get_string(),
|
||||
end_inst);
|
||||
} else {
|
||||
ri = make_unique<RoseInstrCheckLongLit>(lit.s.get_string());
|
||||
ri = make_unique<RoseInstrCheckLongLit>(lit.s.get_string(), end_inst);
|
||||
}
|
||||
program.add_before_end(move(ri));
|
||||
}
|
||||
@@ -4522,6 +4548,7 @@ u32 buildDelayRebuildProgram(RoseBuildImpl &build, build_context &bc,
|
||||
}
|
||||
|
||||
RoseProgram program;
|
||||
makeCheckLiteralInstruction(build, bc, final_id, program);
|
||||
makeCheckLitMaskInstruction(build, bc, final_id, program);
|
||||
makePushDelayedInstructions(build, final_id, program);
|
||||
assert(!program.empty());
|
||||
@@ -4951,7 +4978,7 @@ u32 buildEagerQueueIter(const set<u32> &eager, u32 leftfixBeginQueue,
|
||||
|
||||
static
|
||||
void allocateFinalIdToSet(RoseBuildImpl &build, const set<u32> &lits,
|
||||
size_t longLitLengthThreshold, u32 *next_final_id) {
|
||||
u32 *next_final_id) {
|
||||
const auto &g = build.g;
|
||||
auto &literal_info = build.literal_info;
|
||||
auto &final_id_to_literal = build.final_id_to_literal;
|
||||
@@ -4961,8 +4988,6 @@ void allocateFinalIdToSet(RoseBuildImpl &build, const set<u32> &lits,
|
||||
* ids and squash the same roles and have the same group squashing
|
||||
* behaviour. Benefits literals cannot be merged. */
|
||||
|
||||
assert(longLitLengthThreshold > 0);
|
||||
|
||||
for (u32 int_id : lits) {
|
||||
rose_literal_info &curr_info = literal_info[int_id];
|
||||
const rose_literal_id &lit = build.literals.right.at(int_id);
|
||||
@@ -4974,10 +4999,10 @@ void allocateFinalIdToSet(RoseBuildImpl &build, const set<u32> &lits,
|
||||
goto assign_new_id;
|
||||
}
|
||||
|
||||
// Long literals (that require CHECK_LONG_LIT instructions) cannot be
|
||||
// merged.
|
||||
if (lit.s.length() > longLitLengthThreshold) {
|
||||
DEBUG_PRINTF("id %u is a long literal\n", int_id);
|
||||
// Literals that need confirmation with CHECK_LONG_LIT or CHECK_MED_LIT
|
||||
// cannot be merged.
|
||||
if (lit.s.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
|
||||
DEBUG_PRINTF("id %u needs lit confirm\n", int_id);
|
||||
goto assign_new_id;
|
||||
}
|
||||
|
||||
@@ -5001,7 +5026,7 @@ void allocateFinalIdToSet(RoseBuildImpl &build, const set<u32> &lits,
|
||||
const auto &cand_info = literal_info[cand_id];
|
||||
const auto &cand_lit = build.literals.right.at(cand_id);
|
||||
|
||||
if (cand_lit.s.length() > longLitLengthThreshold) {
|
||||
if (cand_lit.s.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -5071,8 +5096,7 @@ bool isUsedLiteral(const RoseBuildImpl &build, u32 lit_id) {
|
||||
|
||||
/** \brief Allocate final literal IDs for all literals. */
|
||||
static
|
||||
void allocateFinalLiteralId(RoseBuildImpl &build,
|
||||
size_t longLitLengthThreshold) {
|
||||
void allocateFinalLiteralId(RoseBuildImpl &build) {
|
||||
set<u32> anch;
|
||||
set<u32> norm;
|
||||
set<u32> delay;
|
||||
@@ -5106,15 +5130,15 @@ void allocateFinalLiteralId(RoseBuildImpl &build,
|
||||
}
|
||||
|
||||
/* normal lits */
|
||||
allocateFinalIdToSet(build, norm, longLitLengthThreshold, &next_final_id);
|
||||
allocateFinalIdToSet(build, norm, &next_final_id);
|
||||
|
||||
/* next anchored stuff */
|
||||
build.anchored_base_id = next_final_id;
|
||||
allocateFinalIdToSet(build, anch, longLitLengthThreshold, &next_final_id);
|
||||
allocateFinalIdToSet(build, anch, &next_final_id);
|
||||
|
||||
/* delayed ids come last */
|
||||
build.delay_base_id = next_final_id;
|
||||
allocateFinalIdToSet(build, delay, longLitLengthThreshold, &next_final_id);
|
||||
allocateFinalIdToSet(build, delay, &next_final_id);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -5188,10 +5212,11 @@ size_t calcLongLitThreshold(const RoseBuildImpl &build,
|
||||
const size_t historyRequired) {
|
||||
const auto &cc = build.cc;
|
||||
|
||||
// In block mode, we should only use the long literal support for literals
|
||||
// that cannot be handled by HWLM.
|
||||
// In block mode, we don't have history, so we don't need long literal
|
||||
// support and can just use "medium-length" literal confirm. TODO: we could
|
||||
// specialize further and have a block mode literal confirm instruction.
|
||||
if (!cc.streaming) {
|
||||
return HWLM_LITERAL_MAX_LEN;
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
size_t longLitLengthThreshold = ROSE_LONG_LITERAL_THRESHOLD_MIN;
|
||||
@@ -5227,7 +5252,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
|
||||
historyRequired);
|
||||
DEBUG_PRINTF("longLitLengthThreshold=%zu\n", longLitLengthThreshold);
|
||||
|
||||
allocateFinalLiteralId(*this, longLitLengthThreshold);
|
||||
allocateFinalLiteralId(*this);
|
||||
|
||||
auto anchored_dfas = buildAnchoredDfas(*this);
|
||||
|
||||
|
@@ -123,7 +123,7 @@ void RoseBuildImpl::handleMixedSensitivity(void) {
|
||||
// with a CHECK_LONG_LIT instruction and need unique final_ids.
|
||||
// TODO: we could allow explosion for literals where the prefixes
|
||||
// covered by CHECK_LONG_LIT are identical.
|
||||
if (lit.s.length() <= ROSE_LONG_LITERAL_THRESHOLD_MIN &&
|
||||
if (lit.s.length() <= ROSE_SHORT_LITERAL_LEN_MAX &&
|
||||
limited_explosion(lit.s)) {
|
||||
DEBUG_PRINTF("need to explode existing string '%s'\n",
|
||||
dumpString(lit.s).c_str());
|
||||
|
@@ -35,7 +35,7 @@
|
||||
#include "rose/rose_dump.h"
|
||||
#include "rose_internal.h"
|
||||
#include "ue2common.h"
|
||||
#include "hwlm/hwlm_build.h"
|
||||
#include "hwlm/hwlm_literal.h"
|
||||
#include "nfa/castlecompile.h"
|
||||
#include "nfa/nfa_internal.h"
|
||||
#include "nfagraph/ng_dump.h"
|
||||
@@ -505,24 +505,22 @@ void dumpRoseTestLiterals(const RoseBuildImpl &build, const string &base) {
|
||||
size_t longLitLengthThreshold =
|
||||
calcLongLitThreshold(build, historyRequired);
|
||||
|
||||
auto lits = fillHamsterLiteralList(build, ROSE_ANCHORED,
|
||||
longLitLengthThreshold);
|
||||
dumpTestLiterals(base + "rose_anchored_test_literals.txt", lits);
|
||||
auto mp = makeMatcherProto(build, ROSE_ANCHORED, longLitLengthThreshold);
|
||||
dumpTestLiterals(base + "rose_anchored_test_literals.txt", mp.lits);
|
||||
|
||||
lits = fillHamsterLiteralList(build, ROSE_FLOATING, longLitLengthThreshold);
|
||||
dumpTestLiterals(base + "rose_float_test_literals.txt", lits);
|
||||
mp = makeMatcherProto(build, ROSE_FLOATING, longLitLengthThreshold);
|
||||
dumpTestLiterals(base + "rose_float_test_literals.txt", mp.lits);
|
||||
|
||||
lits = fillHamsterLiteralList(build, ROSE_EOD_ANCHORED,
|
||||
build.ematcher_region_size);
|
||||
dumpTestLiterals(base + "rose_eod_test_literals.txt", lits);
|
||||
mp = makeMatcherProto(build, ROSE_EOD_ANCHORED, build.ematcher_region_size);
|
||||
dumpTestLiterals(base + "rose_eod_test_literals.txt", mp.lits);
|
||||
|
||||
if (!build.cc.streaming) {
|
||||
lits = fillHamsterLiteralList(build, ROSE_FLOATING,
|
||||
mp = makeMatcherProto(build, ROSE_FLOATING, ROSE_SMALL_BLOCK_LEN,
|
||||
ROSE_SMALL_BLOCK_LEN);
|
||||
auto mp2 = makeMatcherProto(build, ROSE_ANCHORED_SMALL_BLOCK,
|
||||
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
|
||||
auto lits2 = fillHamsterLiteralList(build, ROSE_ANCHORED_SMALL_BLOCK,
|
||||
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
|
||||
lits.insert(end(lits), begin(lits2), end(lits2));
|
||||
dumpTestLiterals(base + "rose_smallblock_test_literals.txt", lits);
|
||||
mp.lits.insert(end(mp.lits), begin(mp2.lits), end(mp2.lits));
|
||||
dumpTestLiterals(base + "rose_smallblock_test_literals.txt", mp.lits);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016, Intel Corporation
|
||||
* Copyright (c) 2015-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -58,6 +58,17 @@ namespace ue2 {
|
||||
|
||||
#define ROSE_LONG_LITERAL_THRESHOLD_MIN 33
|
||||
|
||||
/**
|
||||
* \brief The largest allowable "short" literal fragment which can be given to
|
||||
* a literal matcher directly.
|
||||
*
|
||||
* Literals longer than this will be truncated to their suffix and confirmed in
|
||||
* the Rose interpreter, either as "medium length" literals which can be
|
||||
* confirmed from history, or "long literals" which make use of the streaming
|
||||
* table support.
|
||||
*/
|
||||
#define ROSE_SHORT_LITERAL_LEN_MAX 8
|
||||
|
||||
struct BoundaryReports;
|
||||
struct CastleProto;
|
||||
struct CompileContext;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* Copyright (c) 2016-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -491,8 +491,14 @@ bool isNoRunsLiteral(const RoseBuildImpl &build, const u32 id,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (build.literals.right.at(id).s.length() > max_len) {
|
||||
DEBUG_PRINTF("requires literal check\n");
|
||||
size_t len = build.literals.right.at(id).s.length();
|
||||
if (len > max_len) {
|
||||
DEBUG_PRINTF("long literal, requires confirm\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len > ROSE_SHORT_LITERAL_LEN_MAX) {
|
||||
DEBUG_PRINTF("medium-length literal, requires confirm\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -626,10 +632,10 @@ u64a literalMinReportOffset(const RoseBuildImpl &build,
|
||||
return lit_min_offset;
|
||||
}
|
||||
|
||||
vector<hwlmLiteral> fillHamsterLiteralList(const RoseBuildImpl &build,
|
||||
rose_literal_table table,
|
||||
size_t max_len, u32 max_offset) {
|
||||
vector<hwlmLiteral> lits;
|
||||
MatcherProto makeMatcherProto(const RoseBuildImpl &build,
|
||||
rose_literal_table table, size_t max_len,
|
||||
u32 max_offset) {
|
||||
MatcherProto mp;
|
||||
|
||||
for (const auto &e : build.literals.right) {
|
||||
const u32 id = e.first;
|
||||
@@ -652,7 +658,8 @@ vector<hwlmLiteral> fillHamsterLiteralList(const RoseBuildImpl &build,
|
||||
/* Note: requires_benefits are handled in the literal entries */
|
||||
const ue2_literal &lit = e.second.s;
|
||||
|
||||
DEBUG_PRINTF("lit='%s'\n", escapeString(lit).c_str());
|
||||
DEBUG_PRINTF("lit='%s' (len %zu)\n", escapeString(lit).c_str(),
|
||||
lit.length());
|
||||
|
||||
if (max_offset != ROSE_BOUND_INF) {
|
||||
u64a min_report = literalMinReportOffset(build, e.second, info);
|
||||
@@ -665,14 +672,22 @@ vector<hwlmLiteral> fillHamsterLiteralList(const RoseBuildImpl &build,
|
||||
|
||||
const vector<u8> &msk = e.second.msk;
|
||||
const vector<u8> &cmp = e.second.cmp;
|
||||
|
||||
bool noruns = isNoRunsLiteral(build, id, info, max_len);
|
||||
|
||||
size_t lit_hist_len = 0;
|
||||
if (build.cc.streaming) {
|
||||
lit_hist_len = max(msk.size(), min(lit.length(), max_len));
|
||||
lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
|
||||
}
|
||||
DEBUG_PRINTF("lit requires %zu bytes of history\n", lit_hist_len);
|
||||
assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
|
||||
|
||||
if (info.requires_explode) {
|
||||
DEBUG_PRINTF("exploding lit\n");
|
||||
|
||||
// We do not require_explode for long literals.
|
||||
assert(lit.length() <= max_len);
|
||||
// We do not require_explode for literals that need confirm
|
||||
// (long/medium length literals).
|
||||
assert(lit.length() <= ROSE_SHORT_LITERAL_LEN_MAX);
|
||||
|
||||
case_iter cit = caseIterateBegin(lit);
|
||||
case_iter cite = caseIterateEnd();
|
||||
@@ -690,8 +705,9 @@ vector<hwlmLiteral> fillHamsterLiteralList(const RoseBuildImpl &build,
|
||||
continue;
|
||||
}
|
||||
|
||||
lits.emplace_back(move(s), nocase, noruns, final_id, groups,
|
||||
msk, cmp);
|
||||
mp.history_required = max(mp.history_required, lit_hist_len);
|
||||
mp.lits.emplace_back(move(s), nocase, noruns, final_id, groups,
|
||||
msk, cmp);
|
||||
}
|
||||
} else {
|
||||
string s = lit.get_string();
|
||||
@@ -702,11 +718,13 @@ vector<hwlmLiteral> fillHamsterLiteralList(const RoseBuildImpl &build,
|
||||
final_id, escapeString(s).c_str(), (int)nocase, noruns,
|
||||
dumpMask(msk).c_str(), dumpMask(cmp).c_str());
|
||||
|
||||
if (s.length() > max_len) {
|
||||
DEBUG_PRINTF("truncating to tail of length %zu\n", max_len);
|
||||
s.erase(0, s.length() - max_len);
|
||||
if (s.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
|
||||
DEBUG_PRINTF("truncating to tail of length %zu\n",
|
||||
size_t{ROSE_SHORT_LITERAL_LEN_MAX});
|
||||
s.erase(0, s.length() - ROSE_SHORT_LITERAL_LEN_MAX);
|
||||
// We shouldn't have set a threshold below 8 chars.
|
||||
assert(msk.size() <= max_len);
|
||||
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
|
||||
assert(!noruns);
|
||||
}
|
||||
|
||||
if (!maskIsConsistent(s, nocase, msk, cmp)) {
|
||||
@@ -714,12 +732,13 @@ vector<hwlmLiteral> fillHamsterLiteralList(const RoseBuildImpl &build,
|
||||
continue;
|
||||
}
|
||||
|
||||
lits.emplace_back(move(s), nocase, noruns, final_id, groups, msk,
|
||||
cmp);
|
||||
mp.history_required = max(mp.history_required, lit_hist_len);
|
||||
mp.lits.emplace_back(move(s), nocase, noruns, final_id, groups, msk,
|
||||
cmp);
|
||||
}
|
||||
}
|
||||
|
||||
return lits;
|
||||
return mp;
|
||||
}
|
||||
|
||||
aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
|
||||
@@ -730,49 +749,31 @@ aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
|
||||
*fsize = 0;
|
||||
*fgroups = 0;
|
||||
|
||||
auto fl = fillHamsterLiteralList(build, ROSE_FLOATING,
|
||||
longLitLengthThreshold);
|
||||
if (fl.empty()) {
|
||||
auto mp = makeMatcherProto(build, ROSE_FLOATING, longLitLengthThreshold);
|
||||
if (mp.lits.empty()) {
|
||||
DEBUG_PRINTF("empty floating matcher\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (const hwlmLiteral &hlit : fl) {
|
||||
*fgroups |= hlit.groups;
|
||||
for (const hwlmLiteral &lit : mp.lits) {
|
||||
*fgroups |= lit.groups;
|
||||
}
|
||||
|
||||
hwlmStreamingControl ctl;
|
||||
hwlmStreamingControl *ctlp;
|
||||
if (build.cc.streaming) {
|
||||
ctl.history_max = build.cc.grey.maxHistoryAvailable;
|
||||
ctl.history_min = MAX(*historyRequired,
|
||||
build.cc.grey.minHistoryAvailable);
|
||||
DEBUG_PRINTF("streaming control, history max=%zu, min=%zu\n",
|
||||
ctl.history_max, ctl.history_min);
|
||||
ctlp = &ctl;
|
||||
} else {
|
||||
ctlp = nullptr; // Null for non-streaming.
|
||||
}
|
||||
|
||||
aligned_unique_ptr<HWLM> ftable =
|
||||
hwlmBuild(fl, ctlp, false, build.cc, build.getInitialGroups());
|
||||
if (!ftable) {
|
||||
auto hwlm = hwlmBuild(mp.lits, false, build.cc, build.getInitialGroups());
|
||||
if (!hwlm) {
|
||||
throw CompileError("Unable to generate bytecode.");
|
||||
}
|
||||
|
||||
if (build.cc.streaming) {
|
||||
DEBUG_PRINTF("literal_history_required=%zu\n",
|
||||
ctl.literal_history_required);
|
||||
assert(ctl.literal_history_required <=
|
||||
build.cc.grey.maxHistoryAvailable);
|
||||
*historyRequired = max(*historyRequired,
|
||||
ctl.literal_history_required);
|
||||
DEBUG_PRINTF("history_required=%zu\n", mp.history_required);
|
||||
assert(mp.history_required <= build.cc.grey.maxHistoryAvailable);
|
||||
*historyRequired = max(*historyRequired, mp.history_required);
|
||||
}
|
||||
|
||||
*fsize = hwlmSize(ftable.get());
|
||||
*fsize = hwlmSize(hwlm.get());
|
||||
assert(*fsize);
|
||||
DEBUG_PRINTF("built floating literal table size %zu bytes\n", *fsize);
|
||||
return ftable;
|
||||
return hwlm;
|
||||
}
|
||||
|
||||
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
||||
@@ -791,38 +792,38 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto lits = fillHamsterLiteralList(
|
||||
build, ROSE_FLOATING, ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
|
||||
if (lits.empty()) {
|
||||
auto mp = makeMatcherProto(build, ROSE_FLOATING, ROSE_SMALL_BLOCK_LEN,
|
||||
ROSE_SMALL_BLOCK_LEN);
|
||||
if (mp.lits.empty()) {
|
||||
DEBUG_PRINTF("no floating table\n");
|
||||
return nullptr;
|
||||
} else if (lits.size() == 1) {
|
||||
} else if (mp.lits.size() == 1) {
|
||||
DEBUG_PRINTF("single floating literal, noodle will be fast enough\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto anchored_lits =
|
||||
fillHamsterLiteralList(build, ROSE_ANCHORED_SMALL_BLOCK,
|
||||
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
|
||||
if (anchored_lits.empty()) {
|
||||
auto mp_anchored =
|
||||
makeMatcherProto(build, ROSE_ANCHORED_SMALL_BLOCK, ROSE_SMALL_BLOCK_LEN,
|
||||
ROSE_SMALL_BLOCK_LEN);
|
||||
if (mp_anchored.lits.empty()) {
|
||||
DEBUG_PRINTF("no small-block anchored literals\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lits.insert(lits.end(), anchored_lits.begin(), anchored_lits.end());
|
||||
mp.lits.insert(mp.lits.end(), mp_anchored.lits.begin(),
|
||||
mp_anchored.lits.end());
|
||||
|
||||
// None of our literals should be longer than the small block limit.
|
||||
assert(all_of(begin(lits), end(lits), [](const hwlmLiteral &lit) {
|
||||
assert(all_of(begin(mp.lits), end(mp.lits), [](const hwlmLiteral &lit) {
|
||||
return lit.s.length() <= ROSE_SMALL_BLOCK_LEN;
|
||||
}));
|
||||
|
||||
if (lits.empty()) {
|
||||
if (mp.lits.empty()) {
|
||||
DEBUG_PRINTF("no literals shorter than small block len\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aligned_unique_ptr<HWLM> hwlm =
|
||||
hwlmBuild(lits, nullptr, true, build.cc, build.getInitialGroups());
|
||||
auto hwlm = hwlmBuild(mp.lits, true, build.cc, build.getInitialGroups());
|
||||
if (!hwlm) {
|
||||
throw CompileError("Unable to generate bytecode.");
|
||||
}
|
||||
@@ -837,10 +838,10 @@ aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build,
|
||||
size_t *esize) {
|
||||
*esize = 0;
|
||||
|
||||
auto el = fillHamsterLiteralList(build, ROSE_EOD_ANCHORED,
|
||||
build.ematcher_region_size);
|
||||
auto mp =
|
||||
makeMatcherProto(build, ROSE_EOD_ANCHORED, build.ematcher_region_size);
|
||||
|
||||
if (el.empty()) {
|
||||
if (mp.lits.empty()) {
|
||||
DEBUG_PRINTF("no eod anchored literals\n");
|
||||
assert(!build.ematcher_region_size);
|
||||
return nullptr;
|
||||
@@ -848,17 +849,15 @@ aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build,
|
||||
|
||||
assert(build.ematcher_region_size);
|
||||
|
||||
hwlmStreamingControl *ctlp = nullptr; // not a streaming case
|
||||
aligned_unique_ptr<HWLM> etable =
|
||||
hwlmBuild(el, ctlp, true, build.cc, build.getInitialGroups());
|
||||
if (!etable) {
|
||||
auto hwlm = hwlmBuild(mp.lits, true, build.cc, build.getInitialGroups());
|
||||
if (!hwlm) {
|
||||
throw CompileError("Unable to generate bytecode.");
|
||||
}
|
||||
|
||||
*esize = hwlmSize(etable.get());
|
||||
*esize = hwlmSize(hwlm.get());
|
||||
assert(*esize);
|
||||
DEBUG_PRINTF("built eod-anchored literal table size %zu bytes\n", *esize);
|
||||
return etable;
|
||||
return hwlm;
|
||||
}
|
||||
|
||||
} // namespace ue2
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* Copyright (c) 2016-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -44,15 +44,21 @@ namespace ue2 {
|
||||
|
||||
struct hwlmLiteral;
|
||||
|
||||
struct MatcherProto {
|
||||
std::vector<hwlmLiteral> lits;
|
||||
size_t history_required = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Build up a vector of literals for the given table.
|
||||
* \brief Build up a vector of literals (and associated other data) for the
|
||||
* given table.
|
||||
*
|
||||
* If max_offset is specified (and not ROSE_BOUND_INF), then literals that can
|
||||
* only lead to a pattern match after max_offset may be excluded.
|
||||
*/
|
||||
std::vector<hwlmLiteral> fillHamsterLiteralList(const RoseBuildImpl &build,
|
||||
rose_literal_table table, size_t max_len,
|
||||
u32 max_offset = ROSE_BOUND_INF);
|
||||
MatcherProto makeMatcherProto(const RoseBuildImpl &build,
|
||||
rose_literal_table table, size_t max_len,
|
||||
u32 max_offset = ROSE_BOUND_INF);
|
||||
|
||||
aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
|
||||
size_t longLitLengthThreshold,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016, Intel Corporation
|
||||
* Copyright (c) 2015-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "rose_build_impl.h"
|
||||
|
||||
#include "hwlm/hwlm_build.h"
|
||||
#include "hwlm/hwlm_literal.h"
|
||||
#include "nfa/castlecompile.h"
|
||||
#include "nfa/goughcompile.h"
|
||||
#include "nfa/mcclellancompile_util.h"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* Copyright (c) 2016-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -502,6 +502,7 @@ void RoseInstrCheckLongLit::write(void *dest, RoseEngineBlob &blob,
|
||||
assert(!literal.empty());
|
||||
inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
|
||||
inst->lit_length = verify_u32(literal.size());
|
||||
inst->fail_jump = calc_jump(offset_map, this, target);
|
||||
}
|
||||
|
||||
void RoseInstrCheckLongLitNocase::write(void *dest, RoseEngineBlob &blob,
|
||||
@@ -511,6 +512,27 @@ void RoseInstrCheckLongLitNocase::write(void *dest, RoseEngineBlob &blob,
|
||||
assert(!literal.empty());
|
||||
inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
|
||||
inst->lit_length = verify_u32(literal.size());
|
||||
inst->fail_jump = calc_jump(offset_map, this, target);
|
||||
}
|
||||
|
||||
void RoseInstrCheckMedLit::write(void *dest, RoseEngineBlob &blob,
|
||||
const OffsetMap &offset_map) const {
|
||||
RoseInstrBase::write(dest, blob, offset_map);
|
||||
auto *inst = static_cast<impl_type *>(dest);
|
||||
assert(!literal.empty());
|
||||
inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
|
||||
inst->lit_length = verify_u32(literal.size());
|
||||
inst->fail_jump = calc_jump(offset_map, this, target);
|
||||
}
|
||||
|
||||
void RoseInstrCheckMedLitNocase::write(void *dest, RoseEngineBlob &blob,
|
||||
const OffsetMap &offset_map) const {
|
||||
RoseInstrBase::write(dest, blob, offset_map);
|
||||
auto *inst = static_cast<impl_type *>(dest);
|
||||
assert(!literal.empty());
|
||||
inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
|
||||
inst->lit_length = verify_u32(literal.size());
|
||||
inst->fail_jump = calc_jump(offset_map, this, target);
|
||||
}
|
||||
|
||||
static
|
||||
|
@@ -1723,17 +1723,19 @@ public:
|
||||
};
|
||||
|
||||
class RoseInstrCheckLongLit
|
||||
: public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_LONG_LIT,
|
||||
: public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT,
|
||||
ROSE_STRUCT_CHECK_LONG_LIT,
|
||||
RoseInstrCheckLongLit> {
|
||||
public:
|
||||
std::string literal;
|
||||
const RoseInstruction *target;
|
||||
|
||||
explicit RoseInstrCheckLongLit(std::string literal_in)
|
||||
: literal(std::move(literal_in)) {}
|
||||
RoseInstrCheckLongLit(std::string literal_in,
|
||||
const RoseInstruction *target_in)
|
||||
: literal(std::move(literal_in)), target(target_in) {}
|
||||
|
||||
bool operator==(const RoseInstrCheckLongLit &ri) const {
|
||||
return literal == ri.literal;
|
||||
return literal == ri.literal && target == ri.target;
|
||||
}
|
||||
|
||||
size_t hash() const override {
|
||||
@@ -1743,26 +1745,29 @@ public:
|
||||
void write(void *dest, RoseEngineBlob &blob,
|
||||
const OffsetMap &offset_map) const override;
|
||||
|
||||
bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &,
|
||||
const OffsetMap &) const {
|
||||
return literal == ri.literal;
|
||||
bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets,
|
||||
const OffsetMap &other_offsets) const {
|
||||
return literal == ri.literal &&
|
||||
offsets.at(target) == other_offsets.at(ri.target);
|
||||
}
|
||||
};
|
||||
|
||||
class RoseInstrCheckLongLitNocase
|
||||
: public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
|
||||
: public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
|
||||
ROSE_STRUCT_CHECK_LONG_LIT_NOCASE,
|
||||
RoseInstrCheckLongLitNocase> {
|
||||
public:
|
||||
std::string literal;
|
||||
const RoseInstruction *target;
|
||||
|
||||
explicit RoseInstrCheckLongLitNocase(std::string literal_in)
|
||||
: literal(std::move(literal_in)) {
|
||||
RoseInstrCheckLongLitNocase(std::string literal_in,
|
||||
const RoseInstruction *target_in)
|
||||
: literal(std::move(literal_in)), target(target_in) {
|
||||
upperString(literal);
|
||||
}
|
||||
|
||||
bool operator==(const RoseInstrCheckLongLitNocase &ri) const {
|
||||
return literal == ri.literal;
|
||||
return literal == ri.literal && target == ri.target;
|
||||
}
|
||||
|
||||
size_t hash() const override {
|
||||
@@ -1772,9 +1777,74 @@ public:
|
||||
void write(void *dest, RoseEngineBlob &blob,
|
||||
const OffsetMap &offset_map) const override;
|
||||
|
||||
bool equiv_to(const RoseInstrCheckLongLitNocase &ri, const OffsetMap &,
|
||||
const OffsetMap &) const {
|
||||
return literal == ri.literal;
|
||||
bool equiv_to(const RoseInstrCheckLongLitNocase &ri,
|
||||
const OffsetMap &offsets,
|
||||
const OffsetMap &other_offsets) const {
|
||||
return literal == ri.literal &&
|
||||
offsets.at(target) == other_offsets.at(ri.target);
|
||||
}
|
||||
};
|
||||
|
||||
class RoseInstrCheckMedLit
|
||||
: public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_MED_LIT,
|
||||
ROSE_STRUCT_CHECK_MED_LIT,
|
||||
RoseInstrCheckMedLit> {
|
||||
public:
|
||||
std::string literal;
|
||||
const RoseInstruction *target;
|
||||
|
||||
explicit RoseInstrCheckMedLit(std::string literal_in,
|
||||
const RoseInstruction *target_in)
|
||||
: literal(std::move(literal_in)), target(target_in) {}
|
||||
|
||||
bool operator==(const RoseInstrCheckMedLit &ri) const {
|
||||
return literal == ri.literal && target == ri.target;
|
||||
}
|
||||
|
||||
size_t hash() const override {
|
||||
return hash_all(static_cast<int>(opcode), literal);
|
||||
}
|
||||
|
||||
void write(void *dest, RoseEngineBlob &blob,
|
||||
const OffsetMap &offset_map) const override;
|
||||
|
||||
bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets,
|
||||
const OffsetMap &other_offsets) const {
|
||||
return literal == ri.literal &&
|
||||
offsets.at(target) == other_offsets.at(ri.target);
|
||||
}
|
||||
};
|
||||
|
||||
class RoseInstrCheckMedLitNocase
|
||||
: public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_MED_LIT_NOCASE,
|
||||
ROSE_STRUCT_CHECK_MED_LIT_NOCASE,
|
||||
RoseInstrCheckMedLitNocase> {
|
||||
public:
|
||||
std::string literal;
|
||||
const RoseInstruction *target;
|
||||
|
||||
explicit RoseInstrCheckMedLitNocase(std::string literal_in,
|
||||
const RoseInstruction *target_in)
|
||||
: literal(std::move(literal_in)), target(target_in) {
|
||||
upperString(literal);
|
||||
}
|
||||
|
||||
bool operator==(const RoseInstrCheckMedLitNocase &ri) const {
|
||||
return literal == ri.literal && target == ri.target;
|
||||
}
|
||||
|
||||
size_t hash() const override {
|
||||
return hash_all(static_cast<int>(opcode), literal);
|
||||
}
|
||||
|
||||
void write(void *dest, RoseEngineBlob &blob,
|
||||
const OffsetMap &offset_map) const override;
|
||||
|
||||
bool equiv_to(const RoseInstrCheckMedLitNocase &ri,
|
||||
const OffsetMap &offsets,
|
||||
const OffsetMap &other_offsets) const {
|
||||
return literal == ri.literal &&
|
||||
offsets.at(target) == other_offsets.at(ri.target);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016, Intel Corporation
|
||||
* Copyright (c) 2015-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -617,6 +617,7 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) {
|
||||
const char *lit = (const char *)t + ri->lit_offset;
|
||||
os << " literal: \""
|
||||
<< escapeString(string(lit, ri->lit_length)) << "\"" << endl;
|
||||
os << " fail_jump " << offset + ri->fail_jump << endl;
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
|
||||
@@ -626,6 +627,27 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) {
|
||||
const char *lit = (const char *)t + ri->lit_offset;
|
||||
os << " literal: \""
|
||||
<< escapeString(string(lit, ri->lit_length)) << "\"" << endl;
|
||||
os << " fail_jump " << offset + ri->fail_jump << endl;
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
|
||||
PROGRAM_CASE(CHECK_MED_LIT) {
|
||||
os << " lit_offset " << ri->lit_offset << endl;
|
||||
os << " lit_length " << ri->lit_length << endl;
|
||||
const char *lit = (const char *)t + ri->lit_offset;
|
||||
os << " literal: \""
|
||||
<< escapeString(string(lit, ri->lit_length)) << "\"" << endl;
|
||||
os << " fail_jump " << offset + ri->fail_jump << endl;
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
|
||||
PROGRAM_CASE(CHECK_MED_LIT_NOCASE) {
|
||||
os << " lit_offset " << ri->lit_offset << endl;
|
||||
os << " lit_length " << ri->lit_length << endl;
|
||||
const char *lit = (const char *)t + ri->lit_offset;
|
||||
os << " literal: \""
|
||||
<< escapeString(string(lit, ri->lit_length)) << "\"" << endl;
|
||||
os << " fail_jump " << offset + ri->fail_jump << endl;
|
||||
}
|
||||
PROGRAM_NEXT_INSTRUCTION
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016, Intel Corporation
|
||||
* Copyright (c) 2015-2017, Intel Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -129,7 +129,19 @@ enum RoseInstructionCode {
|
||||
*/
|
||||
ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
|
||||
|
||||
LAST_ROSE_INSTRUCTION = ROSE_INSTR_CHECK_LONG_LIT_NOCASE //!< Sentinel.
|
||||
/**
|
||||
* \brief Confirm a case-sensitive "medium length" literal at the current
|
||||
* offset. In streaming mode, this will check history if needed.
|
||||
*/
|
||||
ROSE_INSTR_CHECK_MED_LIT,
|
||||
|
||||
/**
|
||||
* \brief Confirm a case-insensitive "medium length" literal at the current
|
||||
* offset. In streaming mode, this will check history if needed.
|
||||
*/
|
||||
ROSE_INSTR_CHECK_MED_LIT_NOCASE,
|
||||
|
||||
LAST_ROSE_INSTRUCTION = ROSE_INSTR_CHECK_MED_LIT_NOCASE //!< Sentinel.
|
||||
};
|
||||
|
||||
struct ROSE_STRUCT_END {
|
||||
@@ -477,18 +489,32 @@ struct ROSE_STRUCT_MATCHER_EOD {
|
||||
u8 code; //!< From enum RoseInstructionCode.
|
||||
};
|
||||
|
||||
/** Note: check failure will halt program. */
|
||||
struct ROSE_STRUCT_CHECK_LONG_LIT {
|
||||
u8 code; //!< From enum RoseInstructionCode.
|
||||
u32 lit_offset; //!< Offset of literal string.
|
||||
u32 lit_length; //!< Length of literal string.
|
||||
u32 fail_jump; //!< Jump forward this many bytes on failure.
|
||||
};
|
||||
|
||||
/** Note: check failure will halt program. */
|
||||
struct ROSE_STRUCT_CHECK_LONG_LIT_NOCASE {
|
||||
u8 code; //!< From enum RoseInstructionCode.
|
||||
u32 lit_offset; //!< Offset of literal string.
|
||||
u32 lit_length; //!< Length of literal string.
|
||||
u32 fail_jump; //!< Jump forward this many bytes on failure.
|
||||
};
|
||||
|
||||
struct ROSE_STRUCT_CHECK_MED_LIT {
|
||||
u8 code; //!< From enum RoseInstructionCode.
|
||||
u32 lit_offset; //!< Offset of literal string.
|
||||
u32 lit_length; //!< Length of literal string.
|
||||
u32 fail_jump; //!< Jump forward this many bytes on failure.
|
||||
};
|
||||
|
||||
struct ROSE_STRUCT_CHECK_MED_LIT_NOCASE {
|
||||
u8 code; //!< From enum RoseInstructionCode.
|
||||
u32 lit_offset; //!< Offset of literal string.
|
||||
u32 lit_length; //!< Length of literal string.
|
||||
u32 fail_jump; //!< Jump forward this many bytes on failure.
|
||||
};
|
||||
|
||||
#endif // ROSE_ROSE_PROGRAM_H
|
||||
|
Reference in New Issue
Block a user