Filter: Stacks moved to thread-local storage if available.
This commit is contained in:
parent
6479e403ef
commit
1757a6fce5
3 changed files with 74 additions and 72 deletions
|
@ -137,7 +137,7 @@ break;
|
||||||
FID_INTERPRET
|
FID_INTERPRET
|
||||||
case INST_NAME():
|
case INST_NAME():
|
||||||
#define whati (&(what->i_]]INST_NAME()[[))
|
#define whati (&(what->i_]]INST_NAME()[[))
|
||||||
m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (vstk.cnt < INST_INVAL()) runtime("Stack underflow"); vstk.cnt -= INST_INVAL(); ]])
|
m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]])
|
||||||
m4_undivert(108)
|
m4_undivert(108)
|
||||||
#undef whati
|
#undef whati
|
||||||
break;
|
break;
|
||||||
|
@ -206,12 +206,12 @@ FID_ALL()')
|
||||||
|
|
||||||
m4_define(LINEX, `FID_INTERPRET_BODY
|
m4_define(LINEX, `FID_INTERPRET_BODY
|
||||||
do {
|
do {
|
||||||
estk.item[estk.cnt].pos = 0;
|
fstk->estk[fstk->ecnt].pos = 0;
|
||||||
estk.item[estk.cnt].line = $1;
|
fstk->estk[fstk->ecnt].line = $1;
|
||||||
estk.item[estk.cnt].ventry = vstk.cnt;
|
fstk->estk[fstk->ecnt].ventry = fstk->vcnt;
|
||||||
estk.item[estk.cnt].vbase = estk.item[estk.cnt-1].vbase;
|
fstk->estk[fstk->ecnt].vbase = fstk->estk[fstk->ecnt-1].vbase;
|
||||||
estk.item[estk.cnt].emask = 0;
|
fstk->estk[fstk->ecnt].emask = 0;
|
||||||
estk.cnt++;
|
fstk->ecnt++;
|
||||||
} while (0)m4_dnl
|
} while (0)m4_dnl
|
||||||
FID_ALL()')
|
FID_ALL()')
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ do { if (whati->fl$1) {
|
||||||
} } while(0)m4_dnl
|
} } while(0)m4_dnl
|
||||||
FID_ALL()')
|
FID_ALL()')
|
||||||
|
|
||||||
m4_define(RESULT_OK, `FID_INTERPRET_BODY()vstk.cnt++FID_ALL()')
|
m4_define(RESULT_OK, `FID_INTERPRET_BODY()fstk->vcnt++FID_ALL()')
|
||||||
m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
|
m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
|
||||||
m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()')
|
m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; RESULT_OK; } while (0)FID_ALL()')
|
||||||
|
|
||||||
|
|
|
@ -156,12 +156,12 @@
|
||||||
what->count = len;
|
what->count = len;
|
||||||
FID_ALL
|
FID_ALL
|
||||||
|
|
||||||
if (vstk.cnt < whati->count) /* TODO: make this check systematic */
|
if (fstk->vcnt < whati->count) /* TODO: make this check systematic */
|
||||||
runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count);
|
runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count);
|
||||||
|
|
||||||
struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item));
|
struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item));
|
||||||
for (uint i=0; i<whati->count; i++) {
|
for (uint i=0; i<whati->count; i++) {
|
||||||
#define pv vstk.val[vstk.cnt - whati->count + i]
|
#define pv fstk->vstk[fstk->vcnt - whati->count + i]
|
||||||
switch (pv.type) {
|
switch (pv.type) {
|
||||||
case T_PATH_MASK_ITEM:
|
case T_PATH_MASK_ITEM:
|
||||||
pm->item[i] = pv.val.pmi;
|
pm->item[i] = pv.val.pmi;
|
||||||
|
@ -177,7 +177,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vstk.cnt -= whati->count;
|
fstk->vcnt -= whati->count;
|
||||||
pm->len = whati->count;
|
pm->len = whati->count;
|
||||||
|
|
||||||
RESULT(T_PATH_MASK, path_mask, pm);
|
RESULT(T_PATH_MASK, path_mask, pm);
|
||||||
|
@ -276,12 +276,12 @@
|
||||||
runtime( "Assigning to variable of incompatible type" );
|
runtime( "Assigning to variable of incompatible type" );
|
||||||
}
|
}
|
||||||
|
|
||||||
vstk.val[curline.vbase + sym->offset] = v1;
|
fstk->vstk[curline.vbase + sym->offset] = v1;
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_VAR_GET, 0, 1) {
|
INST(FI_VAR_GET, 0, 1) {
|
||||||
SYMBOL(1);
|
SYMBOL(1);
|
||||||
res = vstk.val[curline.vbase + sym->offset];
|
res = fstk->vstk[curline.vbase + sym->offset];
|
||||||
RESULT_OK;
|
RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,16 +747,16 @@
|
||||||
INST(FI_RETURN, 1, 1) {
|
INST(FI_RETURN, 1, 1) {
|
||||||
/* Acquire the return value */
|
/* Acquire the return value */
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
uint retpos = vstk.cnt;
|
uint retpos = fstk->vcnt;
|
||||||
|
|
||||||
/* Drop every sub-block including ourselves */
|
/* Drop every sub-block including ourselves */
|
||||||
while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN))
|
while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN))
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Now we are at the caller frame; if no such, try to convert to accept/reject. */
|
/* Now we are at the caller frame; if no such, try to convert to accept/reject. */
|
||||||
if (!estk.cnt)
|
if (!fstk->ecnt)
|
||||||
if (vstk.val[retpos].type == T_BOOL)
|
if (fstk->vstk[retpos].type == T_BOOL)
|
||||||
if (vstk.val[retpos].val.i)
|
if (fstk->vstk[retpos].val.i)
|
||||||
|
|
||||||
return F_ACCEPT;
|
return F_ACCEPT;
|
||||||
else
|
else
|
||||||
|
@ -765,10 +765,10 @@
|
||||||
runtime("Can't return non-bool from non-function");
|
runtime("Can't return non-bool from non-function");
|
||||||
|
|
||||||
/* Set the value stack position, overwriting the former implicit void */
|
/* Set the value stack position, overwriting the former implicit void */
|
||||||
vstk.cnt = estk.item[estk.cnt].ventry - 1;
|
fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1;
|
||||||
|
|
||||||
/* Copy the return value */
|
/* Copy the return value */
|
||||||
RESULT_VAL(vstk.val[retpos]);
|
RESULT_VAL(fstk->vstk[retpos]);
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_CALL, 0, 1) {
|
INST(FI_CALL, 0, 1) {
|
||||||
|
@ -787,8 +787,8 @@
|
||||||
curline.vbase = curline.ventry;
|
curline.vbase = curline.ventry;
|
||||||
|
|
||||||
/* Storage for local variables */
|
/* Storage for local variables */
|
||||||
memset(&(vstk.val[vstk.cnt]), 0, sizeof(struct f_val) * sym->function->vars);
|
memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars);
|
||||||
vstk.cnt += sym->function->vars;
|
fstk->vcnt += sym->function->vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_DROP_RESULT, 1, 0) {
|
INST(FI_DROP_RESULT, 1, 0) {
|
||||||
|
|
102
filter/filter.c
102
filter/filter.c
|
@ -50,8 +50,37 @@
|
||||||
#include "filter/f-inst.h"
|
#include "filter/f-inst.h"
|
||||||
#include "filter/data.h"
|
#include "filter/data.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Exception bits */
|
||||||
|
enum f_exception {
|
||||||
|
FE_RETURN = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct filter_stack {
|
||||||
|
/* Value stack for execution */
|
||||||
|
#define F_VAL_STACK_MAX 4096
|
||||||
|
uint vcnt; /* Current value stack size; 0 for empty */
|
||||||
|
uint ecnt; /* Current execute stack size; 0 for empty */
|
||||||
|
|
||||||
|
struct f_val vstk[F_VAL_STACK_MAX]; /* The stack itself */
|
||||||
|
|
||||||
|
/* Instruction stack for execution */
|
||||||
|
#define F_EXEC_STACK_MAX 4096
|
||||||
|
struct {
|
||||||
|
const struct f_line *line; /* The line that is being executed */
|
||||||
|
uint pos; /* Instruction index in the line */
|
||||||
|
uint ventry; /* Value stack depth on entry */
|
||||||
|
uint vbase; /* Where to index variable positions from */
|
||||||
|
enum f_exception emask; /* Exception mask */
|
||||||
|
} estk[F_EXEC_STACK_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
/* Internal filter state, to be allocated on stack when executing filters */
|
/* Internal filter state, to be allocated on stack when executing filters */
|
||||||
struct filter_state {
|
struct filter_state {
|
||||||
|
/* Stacks needed for execution */
|
||||||
|
struct filter_stack *stack;
|
||||||
|
|
||||||
/* The route we are processing. This may be NULL to indicate no route available. */
|
/* The route we are processing. This may be NULL to indicate no route available. */
|
||||||
struct rte **rte;
|
struct rte **rte;
|
||||||
|
|
||||||
|
@ -67,9 +96,10 @@ struct filter_state {
|
||||||
|
|
||||||
#if HAVE_THREAD_LOCAL
|
#if HAVE_THREAD_LOCAL
|
||||||
_Thread_local static struct filter_state filter_state;
|
_Thread_local static struct filter_state filter_state;
|
||||||
#define FS_INIT(...) filter_state = (struct filter_state) { __VA_ARGS__ }
|
_Thread_local static struct filter_stack filter_stack;
|
||||||
|
#define FS_INIT(...) filter_state = (struct filter_state) { .stack = &filter_stack, __VA_ARGS__ }
|
||||||
#else
|
#else
|
||||||
#define FS_INIT(...) struct filter_state filter_state = { __VA_ARGS__ }
|
#define FS_INIT(...) struct filter_state filter_state = { .stack = alloca(sizeof(struct filter_stack)), __VA_ARGS__ };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void (*bt_assert_hook)(int result, const struct f_line_item *assert);
|
void (*bt_assert_hook)(int result, const struct f_line_item *assert);
|
||||||
|
@ -145,61 +175,33 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
|
||||||
/* No arguments allowed */
|
/* No arguments allowed */
|
||||||
ASSERT(line->args == 0);
|
ASSERT(line->args == 0);
|
||||||
|
|
||||||
#define F_VAL_STACK_MAX 4096
|
/* Initialize the filter stack */
|
||||||
/* Value stack for execution */
|
struct filter_stack *fstk = fs->stack;
|
||||||
struct f_val_stack {
|
|
||||||
uint cnt; /* Current stack size; 0 for empty */
|
|
||||||
struct f_val val[F_VAL_STACK_MAX]; /* The stack itself */
|
|
||||||
} vstk;
|
|
||||||
|
|
||||||
/* The stack itself is intentionally kept as-is for performance reasons.
|
fstk->vcnt = line->vars;
|
||||||
* Do NOT rewrite this to initialization by struct literal. It's slow.
|
memset(fstk->vstk, 0, sizeof(struct f_val) * line->vars);
|
||||||
*
|
|
||||||
* Reserving space for local variables. */
|
|
||||||
|
|
||||||
vstk.cnt = line->vars;
|
|
||||||
memset(vstk.val, 0, sizeof(struct f_val) * line->vars);
|
|
||||||
|
|
||||||
#define F_EXEC_STACK_MAX 4096
|
|
||||||
|
|
||||||
/* Exception bits */
|
|
||||||
enum f_exception {
|
|
||||||
FE_RETURN = 0x1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Instruction stack for execution */
|
|
||||||
struct f_exec_stack {
|
|
||||||
struct {
|
|
||||||
const struct f_line *line; /* The line that is being executed */
|
|
||||||
uint pos; /* Instruction index in the line */
|
|
||||||
uint ventry; /* Value stack depth on entry */
|
|
||||||
uint vbase; /* Where to index variable positions from */
|
|
||||||
enum f_exception emask; /* Exception mask */
|
|
||||||
} item[F_EXEC_STACK_MAX];
|
|
||||||
uint cnt; /* Current stack size; 0 for empty */
|
|
||||||
} estk;
|
|
||||||
|
|
||||||
/* The same as with the value stack. Not resetting the stack for performance reasons. */
|
/* The same as with the value stack. Not resetting the stack for performance reasons. */
|
||||||
estk.cnt = 1;
|
fstk->ecnt = 1;
|
||||||
estk.item[0].line = line;
|
fstk->estk[0].line = line;
|
||||||
estk.item[0].pos = 0;
|
fstk->estk[0].pos = 0;
|
||||||
|
|
||||||
#define curline estk.item[estk.cnt-1]
|
#define curline fstk->estk[fstk->ecnt-1]
|
||||||
|
|
||||||
#if DEBUGGING
|
#if DEBUGGING
|
||||||
debug("Interpreting line.");
|
debug("Interpreting line.");
|
||||||
f_dump_line(line, 1);
|
f_dump_line(line, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (estk.cnt > 0) {
|
while (fstk->ecnt > 0) {
|
||||||
while (curline.pos < curline.line->len) {
|
while (curline.pos < curline.line->len) {
|
||||||
const struct f_line_item *what = &(curline.line->items[curline.pos++]);
|
const struct f_line_item *what = &(curline.line->items[curline.pos++]);
|
||||||
|
|
||||||
switch (what->fi_code) {
|
switch (what->fi_code) {
|
||||||
#define res vstk.val[vstk.cnt]
|
#define res fstk->vstk[fstk->vcnt]
|
||||||
#define v1 vstk.val[vstk.cnt]
|
#define v1 fstk->vstk[fstk->vcnt]
|
||||||
#define v2 vstk.val[vstk.cnt + 1]
|
#define v2 fstk->vstk[fstk->vcnt + 1]
|
||||||
#define v3 vstk.val[vstk.cnt + 2]
|
#define v3 fstk->vstk[fstk->vcnt + 2]
|
||||||
|
|
||||||
#define runtime(fmt, ...) do { \
|
#define runtime(fmt, ...) do { \
|
||||||
if (!(fs->flags & FF_SILENT)) \
|
if (!(fs->flags & FF_SILENT)) \
|
||||||
|
@ -222,12 +224,12 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of current line. Drop local variables before exiting. */
|
/* End of current line. Drop local variables before exiting. */
|
||||||
vstk.cnt -= curline.line->vars;
|
fstk->vcnt -= curline.line->vars;
|
||||||
vstk.cnt -= curline.line->args;
|
fstk->vcnt -= curline.line->args;
|
||||||
estk.cnt--;
|
fstk->ecnt--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vstk.cnt == 0) {
|
if (fstk->vcnt == 0) {
|
||||||
if (val) {
|
if (val) {
|
||||||
log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack");
|
log_rl(&rl_runtime_err, L_ERR "filters: No value left on stack");
|
||||||
return F_ERROR;
|
return F_ERROR;
|
||||||
|
@ -235,12 +237,12 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
|
||||||
return F_NOP;
|
return F_NOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val && (vstk.cnt == 1)) {
|
if (val && (fstk->vcnt == 1)) {
|
||||||
*val = vstk.val[0];
|
*val = fstk->vstk[0];
|
||||||
return F_NOP;
|
return F_NOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", vstk.cnt);
|
log_rl(&rl_runtime_err, L_ERR "Too many items left on stack: %u", fstk->vcnt);
|
||||||
return F_ERROR;
|
return F_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue