#include <stdlib.h>
#include <string.h>
#include "allocator.h"
#include "hs_internal.h"
#include "hs_runtime.h"
#include "scratch.h"
#include "state.h"
#include "ue2common.h"
#include "database.h"
#include "nfa/nfa_api_queue.h"
#include "rose/rose_internal.h"
#include "util/fatbit.h"
static
size_t fatbit_array_size(u32 num_entries, u32 fatbit_len) {
size_t len = 0;
len += sizeof(struct fatbit *) * num_entries;
len = ROUNDUP_N(len, alignof(struct fatbit));
len += (size_t)fatbit_len * num_entries;
return ROUNDUP_N(len, 8); }
static
hs_error_t alloc_scratch(const hs_scratch_t *proto, hs_scratch_t **scratch) {
u32 queueCount = proto->queueCount;
u32 activeQueueArraySize = proto->activeQueueArraySize;
u32 deduperCount = proto->deduper.dkey_count;
u32 deduperLogSize = proto->deduper.log_size;
u32 bStateSize = proto->bStateSize;
u32 tStateSize = proto->tStateSize;
u32 fullStateSize = proto->fullStateSize;
u32 anchored_literal_region_len = proto->anchored_literal_region_len;
u32 anchored_literal_fatbit_size = proto->anchored_literal_fatbit_size;
u32 som_store_size = proto->som_store_count * sizeof(u64a);
u32 som_attempted_store_size = proto->som_store_count * sizeof(u64a);
u32 som_now_size = proto->som_fatbit_size;
u32 som_attempted_size = proto->som_fatbit_size;
struct hs_scratch *s;
struct hs_scratch *s_tmp;
size_t queue_size = queueCount * sizeof(struct mq);
size_t qmpq_size = queueCount * sizeof(struct queue_match);
assert(anchored_literal_region_len < 8 * sizeof(s->al_log_sum));
size_t anchored_literal_region_size = fatbit_array_size(
anchored_literal_region_len, proto->anchored_literal_fatbit_size);
size_t delay_region_size =
fatbit_array_size(DELAY_SLOT_COUNT, proto->delay_fatbit_size);
size_t size = queue_size + 63
+ bStateSize + tStateSize
+ fullStateSize + 63
+ proto->handledKeyFatbitSize
+ activeQueueArraySize
+ 2 * deduperLogSize
+ 2 * deduperLogSize
+ 2 * sizeof(u64a) * deduperCount
+ anchored_literal_region_size + qmpq_size
+ delay_region_size
+ som_store_size
+ som_now_size
+ som_attempted_size
+ som_attempted_store_size + 15;
const size_t alloc_size = sizeof(struct hs_scratch) + size + 256;
s_tmp = hs_scratch_alloc(alloc_size);
hs_error_t err = hs_check_alloc(s_tmp);
if (err != HS_SUCCESS) {
hs_scratch_free(s_tmp);
*scratch = NULL;
return err;
}
memset(s_tmp, 0, alloc_size);
s = ROUNDUP_PTR(s_tmp, 64);
DEBUG_PRINTF("allocated %zu bytes at %p but realigning to %p\n", alloc_size, s_tmp, s);
DEBUG_PRINTF("sizeof %zu\n", sizeof(struct hs_scratch));
*s = *proto;
s->magic = SCRATCH_MAGIC;
s->in_use = 0;
s->scratchSize = alloc_size;
s->scratch_alloc = (char *)s_tmp;
s->fdr_conf = NULL;
char *current = (char *)s + sizeof(*s);
current = ROUNDUP_PTR(current, 8);
s->queues = (struct mq *)current;
current += queue_size;
assert(ISALIGNED_N(current, 8));
s->som_store = (u64a *)current;
current += som_store_size;
s->som_attempted_store = (u64a *)current;
current += som_attempted_store_size;
current = ROUNDUP_PTR(current, alignof(struct fatbit *));
s->delay_slots = (struct fatbit **)current;
current += sizeof(struct fatbit *) * DELAY_SLOT_COUNT;
current = ROUNDUP_PTR(current, alignof(struct fatbit));
for (u32 i = 0; i < DELAY_SLOT_COUNT; i++) {
s->delay_slots[i] = (struct fatbit *)current;
assert(ISALIGNED(s->delay_slots[i]));
current += proto->delay_fatbit_size;
}
current = ROUNDUP_PTR(current, alignof(struct fatbit *));
s->al_log = (struct fatbit **)current;
current += sizeof(struct fatbit *) * anchored_literal_region_len;
current = ROUNDUP_PTR(current, alignof(struct fatbit));
for (u32 i = 0; i < anchored_literal_region_len; i++) {
s->al_log[i] = (struct fatbit *)current;
assert(ISALIGNED(s->al_log[i]));
current += anchored_literal_fatbit_size;
}
current = ROUNDUP_PTR(current, 8);
s->catchup_pq.qm = (struct queue_match *)current;
current += qmpq_size;
s->bstate = (char *)current;
s->bStateSize = bStateSize;
current += bStateSize;
s->tstate = (char *)current;
s->tStateSize = tStateSize;
current += tStateSize;
current = ROUNDUP_PTR(current, 64);
assert(ISALIGNED_N(current, 8));
s->deduper.som_start_log[0] = (u64a *)current;
current += sizeof(u64a) * deduperCount;
s->deduper.som_start_log[1] = (u64a *)current;
current += sizeof(u64a) * deduperCount;
assert(ISALIGNED_N(current, 8));
s->aqa = (struct fatbit *)current;
current += activeQueueArraySize;
s->handled_roles = (struct fatbit *)current;
current += proto->handledKeyFatbitSize;
s->deduper.log[0] = (struct fatbit *)current;
current += deduperLogSize;
s->deduper.log[1] = (struct fatbit *)current;
current += deduperLogSize;
s->deduper.som_log[0] = (struct fatbit *)current;
current += deduperLogSize;
s->deduper.som_log[1] = (struct fatbit *)current;
current += deduperLogSize;
s->som_set_now = (struct fatbit *)current;
current += som_now_size;
s->som_attempted_set = (struct fatbit *)current;
current += som_attempted_size;
current = ROUNDUP_PTR(current, 64);
assert(ISALIGNED_CL(current));
s->fullState = (char *)current;
s->fullStateSize = fullStateSize;
current += fullStateSize;
*scratch = s;
assert((size_t)(current - (char *)s) <= alloc_size);
for (struct mq *qi = s->queues; qi != s->queues + queueCount; ++qi) {
qi->scratch = s;
}
return HS_SUCCESS;
}
HS_PUBLIC_API
hs_error_t HS_CDECL hs_alloc_scratch(const hs_database_t *db,
hs_scratch_t **scratch) {
if (!db || !scratch) {
return HS_INVALID;
}
hs_error_t rv = dbIsValid(db);
if (rv != HS_SUCCESS) {
return rv;
}
if (*scratch != NULL) {
if (!ISALIGNED_CL(*scratch)) {
return HS_INVALID;
}
if ((*scratch)->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}
if (markScratchInUse(*scratch)) {
return HS_SCRATCH_IN_USE;
}
}
const struct RoseEngine *rose = hs_get_bytecode(db);
int resize = 0;
hs_scratch_t *proto;
hs_scratch_t *proto_tmp = hs_scratch_alloc(sizeof(struct hs_scratch) + 256);
hs_error_t proto_ret = hs_check_alloc(proto_tmp);
if (proto_ret != HS_SUCCESS) {
hs_scratch_free(proto_tmp);
if (*scratch) {
hs_scratch_free((*scratch)->scratch_alloc);
}
*scratch = NULL;
return proto_ret;
}
proto = ROUNDUP_PTR(proto_tmp, 64);
if (*scratch) {
*proto = **scratch;
} else {
memset(proto, 0, sizeof(*proto));
resize = 1;
}
proto->scratch_alloc = (char *)proto_tmp;
if (rose->anchoredDistance > proto->anchored_literal_region_len) {
resize = 1;
proto->anchored_literal_region_len = rose->anchoredDistance;
}
if (rose->anchored_fatbit_size > proto->anchored_literal_fatbit_size) {
resize = 1;
proto->anchored_literal_fatbit_size = rose->anchored_fatbit_size;
}
if (rose->delay_fatbit_size > proto->delay_fatbit_size) {
resize = 1;
proto->delay_fatbit_size = rose->delay_fatbit_size;
}
if (rose->handledKeyFatbitSize > proto->handledKeyFatbitSize) {
resize = 1;
proto->handledKeyFatbitSize = rose->handledKeyFatbitSize;
}
if (rose->tStateSize > proto->tStateSize) {
resize = 1;
proto->tStateSize = rose->tStateSize;
}
u32 som_store_count = rose->somLocationCount;
if (som_store_count > proto->som_store_count) {
resize = 1;
proto->som_store_count = som_store_count;
}
if (rose->somLocationFatbitSize > proto->som_fatbit_size) {
resize = 1;
proto->som_fatbit_size = rose->somLocationFatbitSize;
}
u32 queueCount = rose->queueCount;
if (queueCount > proto->queueCount) {
resize = 1;
proto->queueCount = queueCount;
}
if (rose->activeQueueArraySize > proto->activeQueueArraySize) {
resize = 1;
proto->activeQueueArraySize = rose->activeQueueArraySize;
}
u32 bStateSize = 0;
if (rose->mode == HS_MODE_BLOCK) {
bStateSize = rose->stateOffsets.end;
} else if (rose->mode == HS_MODE_VECTORED) {
bStateSize = sizeof(struct hs_stream) + rose->stateOffsets.end;
}
if (bStateSize > proto->bStateSize) {
resize = 1;
proto->bStateSize = bStateSize;
}
u32 fullStateSize = rose->scratchStateSize;
if (fullStateSize > proto->fullStateSize) {
resize = 1;
proto->fullStateSize = fullStateSize;
}
if (rose->dkeyCount > proto->deduper.dkey_count) {
resize = 1;
proto->deduper.dkey_count = rose->dkeyCount;
proto->deduper.log_size = rose->dkeyLogSize;
}
if (resize) {
if (*scratch) {
hs_scratch_free((*scratch)->scratch_alloc);
}
hs_error_t alloc_ret = alloc_scratch(proto, scratch);
hs_scratch_free(proto_tmp);
if (alloc_ret != HS_SUCCESS) {
*scratch = NULL;
return alloc_ret;
}
} else {
hs_scratch_free(proto_tmp);
unmarkScratchInUse(*scratch);
}
assert(!(*scratch)->in_use);
return HS_SUCCESS;
}
HS_PUBLIC_API
hs_error_t HS_CDECL hs_clone_scratch(const hs_scratch_t *src,
hs_scratch_t **dest) {
if (!dest || !src || !ISALIGNED_CL(src) || src->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}
*dest = NULL;
hs_error_t ret = alloc_scratch(src, dest);
if (ret != HS_SUCCESS) {
*dest = NULL;
return ret;
}
assert(!(*dest)->in_use);
return HS_SUCCESS;
}
HS_PUBLIC_API
hs_error_t HS_CDECL hs_free_scratch(hs_scratch_t *scratch) {
if (scratch) {
if (!ISALIGNED_CL(scratch)) {
return HS_INVALID;
}
if (scratch->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}
if (markScratchInUse(scratch)) {
return HS_SCRATCH_IN_USE;
}
scratch->magic = 0;
assert(scratch->scratch_alloc);
DEBUG_PRINTF("scratch %p is really at %p : freeing\n", scratch,
scratch->scratch_alloc);
hs_scratch_free(scratch->scratch_alloc);
}
return HS_SUCCESS;
}
HS_PUBLIC_API
hs_error_t HS_CDECL hs_scratch_size(const hs_scratch_t *scratch, size_t *size) {
if (!size || !scratch || !ISALIGNED_CL(scratch) ||
scratch->magic != SCRATCH_MAGIC) {
return HS_INVALID;
}
*size = scratch->scratchSize;
return HS_SUCCESS;
}