vectorscan/src/rose/block.c
2016-03-01 11:32:11 +11:00

268 lines
9.2 KiB
C

/*
* Copyright (c) 2015-2016, 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.
*/
#include "catchup.h"
#include "init.h"
#include "match.h"
#include "nfa/nfa_api.h"
#include "nfa/nfa_internal.h"
#include "nfa/nfa_rev_api.h"
#include "nfa/mcclellan.h"
#include "util/fatbit.h"
#include "rose.h"
#include "rose_common.h"
static rose_inline
void runAnchoredTableBlock(const struct RoseEngine *t, const void *atable,
struct hs_scratch *scratch) {
const u8 *buffer = scratch->core_info.buf;
size_t length = scratch->core_info.len;
size_t alen = MIN(length, t->anchoredDistance);
const struct anchored_matcher_info *curr = atable;
DEBUG_PRINTF("BEGIN ANCHORED (over %zu/%zu)\n", alen, length);
do {
const struct NFA *nfa
= (const struct NFA *)((const char *)curr + sizeof(*curr));
assert(t->anchoredDistance > curr->anchoredMinDistance);
if (length >= curr->anchoredMinDistance) {
size_t local_alen = alen - curr->anchoredMinDistance;
const u8 *local_buffer = buffer + curr->anchoredMinDistance;
DEBUG_PRINTF("--anchored nfa (+%u)\n", curr->anchoredMinDistance);
assert(isMcClellanType(nfa->type));
if (nfa->type == MCCLELLAN_NFA_8) {
nfaExecMcClellan8_B(nfa, curr->anchoredMinDistance,
local_buffer, local_alen,
roseAnchoredCallback, &scratch->tctxt);
} else {
nfaExecMcClellan16_B(nfa, curr->anchoredMinDistance,
local_buffer, local_alen,
roseAnchoredCallback, &scratch->tctxt);
}
}
if (!curr->next_offset) {
break;
}
curr = (const void *)((const char *)curr + curr->next_offset);
} while (1);
}
static really_inline
void init_state_for_block(const struct RoseEngine *t, char *state) {
assert(t);
assert(state);
DEBUG_PRINTF("init for Rose %p with %u state indices\n", t,
t->rolesWithStateCount);
// Rose is guaranteed 8-aligned state
assert(ISALIGNED_N(state, 8));
init_state(t, state);
}
static really_inline
void init_outfixes_for_block(const struct RoseEngine *t,
struct hs_scratch *scratch, char *state,
char is_small_block) {
/* active leaf array has been cleared by the init scatter */
if (t->initMpvNfa != MO_INVALID_IDX) {
assert(t->initMpvNfa == 0);
const struct NFA *nfa = getNfaByQueue(t, 0);
DEBUG_PRINTF("testing minwidth %u > len %zu\n", nfa->minWidth,
scratch->core_info.len);
size_t len = nfaRevAccelCheck(nfa, scratch->core_info.buf,
scratch->core_info.len);
if (len) {
u8 *activeArray = getActiveLeafArray(t, state);
const u32 activeArraySize = t->activeArrayCount;
const u32 qCount = t->queueCount;
mmbit_set(activeArray, activeArraySize, 0);
fatbit_set(scratch->aqa, qCount, 0);
struct mq *q = scratch->queues;
initQueue(q, 0, t, scratch);
q->length = len; /* adjust for rev_accel */
nfaQueueInitState(nfa, q);
pushQueueAt(q, 0, MQE_START, 0);
pushQueueAt(q, 1, MQE_TOP, 0);
}
}
if (is_small_block && !t->hasOutfixesInSmallBlock) {
DEBUG_PRINTF("all outfixes in small block table\n");
return;
}
if (t->outfixBeginQueue != t->outfixEndQueue) {
blockInitSufPQ(t, state, scratch, is_small_block);
}
}
static really_inline
void init_for_block(const struct RoseEngine *t, struct hs_scratch *scratch,
RoseCallback callback, RoseCallbackSom som_callback,
char *state, char is_small_block) {
init_state_for_block(t, state);
struct RoseContext *tctxt = &scratch->tctxt;
tctxt->groups = t->initialGroups;
tctxt->lit_offset_adjust = 1; // index after last byte
tctxt->delayLastEndOffset = 0;
tctxt->lastEndOffset = 0;
tctxt->filledDelayedSlots = 0;
tctxt->cb = callback;
tctxt->cb_som = som_callback;
tctxt->lastMatchOffset = 0;
tctxt->minMatchOffset = 0;
tctxt->minNonMpvMatchOffset = 0;
tctxt->next_mpv_offset = 0;
tctxt->curr_anchored_loc = MMB_INVALID;
tctxt->curr_row_offset = 0;
scratch->am_log_sum = 0; /* clear the anchored logs */
scratch->al_log_sum = 0;
fatbit_clear(scratch->aqa);
scratch->catchup_pq.qm_size = 0;
init_outfixes_for_block(t, scratch, state, is_small_block);
}
void roseBlockExec_i(const struct RoseEngine *t, struct hs_scratch *scratch,
RoseCallback callback, RoseCallbackSom som_callback) {
assert(t);
assert(scratch);
assert(scratch->core_info.buf);
assert(mmbit_sparse_iter_state_size(t->rolesWithStateCount)
< MAX_SPARSE_ITER_STATES);
const size_t length = scratch->core_info.len;
// We have optimizations for small block scans: we run a single coalesced
// HWLM scan instead of running the anchored and floating matchers. Some
// outfixes are disabled as well (for SEP scans of single-byte literals,
// which are also run in the HWLM scan).
const char is_small_block =
(length < ROSE_SMALL_BLOCK_LEN && t->sbmatcherOffset);
char *state = scratch->core_info.state;
init_for_block(t, scratch, callback, som_callback, state,
is_small_block);
struct RoseContext *tctxt = &scratch->tctxt;
if (is_small_block) {
const void *sbtable = getSBLiteralMatcher(t);
assert(sbtable);
size_t sblen = MIN(length, t->smallBlockDistance);
DEBUG_PRINTF("BEGIN SMALL BLOCK (over %zu/%zu)\n", sblen, length);
DEBUG_PRINTF("-- %016llx\n", tctxt->groups);
hwlmExec(sbtable, scratch->core_info.buf, sblen, 0, roseCallback,
tctxt, tctxt->groups);
goto exit;
}
const void *atable = getALiteralMatcher(t);
if (atable) {
if (t->amatcherMaxBiAnchoredWidth != ROSE_BOUND_INF
&& length > t->amatcherMaxBiAnchoredWidth) {
goto skip_atable;
}
if (length < t->amatcherMinWidth) {
goto skip_atable;
}
runAnchoredTableBlock(t, atable, scratch);
if (can_stop_matching(scratch)) {
goto exit;
}
resetAnchoredLog(t, scratch);
skip_atable:;
}
const struct HWLM *ftable = getFLiteralMatcher(t);
if (ftable) {
DEBUG_PRINTF("ftable fd=%u fmd %u\n", t->floatingDistance,
t->floatingMinDistance);
if (t->noFloatingRoots && !roseHasInFlightMatches(t, state, scratch)) {
DEBUG_PRINTF("skip FLOATING: no inflight matches\n");
goto exit;
}
if (t->fmatcherMaxBiAnchoredWidth != ROSE_BOUND_INF
&& length > t->fmatcherMaxBiAnchoredWidth) {
goto exit;
}
if (length < t->fmatcherMinWidth) {
goto exit;
}
const u8 *buffer = scratch->core_info.buf;
size_t flen = length;
if (t->floatingDistance != ROSE_BOUND_INF) {
flen = MIN(t->floatingDistance, length);
}
if (flen <= t->floatingMinDistance) {
goto exit;
}
DEBUG_PRINTF("BEGIN FLOATING (over %zu/%zu)\n", flen, length);
DEBUG_PRINTF("-- %016llx\n", tctxt->groups);
hwlmExec(ftable, buffer, flen, t->floatingMinDistance,
roseCallback, tctxt, tctxt->groups);
}
exit:;
if (cleanUpDelayed(t, scratch, length, 0) == HWLM_TERMINATE_MATCHING) {
return;
}
assert(!can_stop_matching(scratch));
roseCatchUpTo(t, scratch, length, 0);
}