#include <stdio.h>
#include <string.h>
#include "alloc.h"
#include "out.h"
#include "lut.h"
#include "tree.h"
#include "ptree.h"
#include "itree.h"
#include "ipath.h"
#include "iexpr.h"
#include "stats.h"
#include "eval.h"
#include "config.h"
#define IEXPRSZ 1024
static struct stats *Niexpr;
static struct iexpr {
struct node *np;
struct iexpr *next;
int count;
} *Cache[IEXPRSZ];
void
iexpr_init(void)
{
Niexpr = stats_new_counter("iexpr.niexpr", "iexpr cache entries", 1);
}
static unsigned
iexpr_hash(struct node *np)
{
if (np == NULL)
return (1);
switch (np->t) {
case T_GLOBID:
return ((uintptr_t)np->u.globid.s);
case T_ASSIGN:
case T_CONDIF:
case T_CONDELSE:
case T_NE:
case T_EQ:
case T_LT:
case T_LE:
case T_GT:
case T_GE:
case T_BITAND:
case T_BITOR:
case T_BITXOR:
case T_BITNOT:
case T_LSHIFT:
case T_RSHIFT:
case T_LIST:
case T_AND:
case T_OR:
case T_NOT:
case T_ADD:
case T_SUB:
case T_MUL:
case T_DIV:
case T_MOD:
return ((int)np->t *
(iexpr_hash(np->u.expr.left) +
iexpr_hash(np->u.expr.right)));
case T_NAME:
return ((uintptr_t)np->u.name.s);
case T_EVENT:
return (iexpr_hash(np->u.event.ename) +
iexpr_hash(np->u.event.epname));
case T_FUNC:
return ((uintptr_t)np->u.func.s +
iexpr_hash(np->u.func.arglist));
case T_QUOTE:
return ((uintptr_t)np->u.quote.s);
case T_NUM:
case T_TIMEVAL:
return ((int)np->u.ull);
default:
outfl(O_DIE, np->file, np->line,
"iexpr_hash: unexpected node type: %s",
ptree_nodetype2str(np->t));
}
return (1);
}
static int
iexpr_cmp(struct node *np1, struct node *np2)
{
int diff;
if (np1 == np2)
return (0);
if (np1 == NULL)
return (1);
if (np2 == NULL)
return (-1);
if (np1->t != np2->t)
return (np2->t - np1->t);
switch (np1->t) {
case T_GLOBID:
return (np2->u.globid.s - np1->u.globid.s);
case T_ASSIGN:
case T_CONDIF:
case T_CONDELSE:
case T_NE:
case T_EQ:
case T_LT:
case T_LE:
case T_GT:
case T_GE:
case T_BITAND:
case T_BITOR:
case T_BITXOR:
case T_BITNOT:
case T_LSHIFT:
case T_RSHIFT:
case T_LIST:
case T_AND:
case T_OR:
case T_NOT:
case T_ADD:
case T_SUB:
case T_MUL:
case T_DIV:
case T_MOD:
diff = iexpr_cmp(np1->u.expr.left, np2->u.expr.left);
if (diff != 0)
return (diff);
return (iexpr_cmp(np1->u.expr.right, np2->u.expr.right));
case T_NAME:
if (np2->u.name.s != np1->u.name.s)
return (np2->u.name.s - np1->u.name.s);
diff = iexpr_cmp(np1->u.name.child, np2->u.name.child);
if (diff != 0)
return (diff);
return (iexpr_cmp(np1->u.name.next, np2->u.name.next));
case T_EVENT:
diff = iexpr_cmp(np1->u.event.ename, np2->u.event.ename);
if (diff != 0)
return (diff);
return (iexpr_cmp(np1->u.event.epname, np2->u.event.epname));
case T_FUNC:
if (np1->u.func.s != np2->u.func.s)
return (np2->u.func.s - np1->u.func.s);
return (iexpr_cmp(np1->u.func.arglist, np2->u.func.arglist));
case T_QUOTE:
return (np2->u.quote.s - np1->u.quote.s);
case T_NUM:
case T_TIMEVAL:
if (np2->u.ull > np1->u.ull)
return (1);
else if (np1->u.ull > np2->u.ull)
return (-1);
else
return (0);
default:
outfl(O_DIE, np1->file, np1->line,
"iexpr_cmp: unexpected node type: %s",
ptree_nodetype2str(np1->t));
}
return (0);
}
struct node *
iexpr(struct node *np)
{
unsigned idx = iexpr_hash(np) % IEXPRSZ;
struct iexpr *bucketp = Cache[idx];
struct iexpr *cp;
for (cp = bucketp; cp != NULL; cp = cp->next)
if (iexpr_cmp(cp->np, np) == 0) {
tree_free(np);
cp->count++;
return (cp->np);
}
cp = MALLOC(sizeof (*cp));
cp->np = np;
cp->next = bucketp;
cp->count = 1;
Cache[idx] = cp;
stats_counter_bump(Niexpr);
return (np);
}
void
iexpr_free(struct node *np)
{
unsigned idx = iexpr_hash(np) % IEXPRSZ;
struct iexpr *cp;
struct iexpr *prevcp = NULL;
for (cp = Cache[idx]; cp != NULL; cp = cp->next) {
if (iexpr_cmp(cp->np, np) == 0) {
cp->count--;
if (cp->count == 0) {
tree_free(cp->np);
if (prevcp == NULL)
Cache[idx] = cp->next;
else
prevcp->next = cp->next;
FREE(cp);
}
return;
}
prevcp = cp;
}
}
int
iexpr_cached(struct node *np)
{
struct iexpr *cp = Cache[iexpr_hash(np) % IEXPRSZ];
for (; cp != NULL; cp = cp->next)
if (iexpr_cmp(cp->np, np) == 0) {
return (1);
}
return (0);
}
void
iexpr_fini(void)
{
int i;
for (i = 0; i < IEXPRSZ; i++) {
struct iexpr *cp;
struct iexpr *ncp;
for (cp = Cache[i]; cp != NULL; cp = ncp) {
tree_free(cp->np);
ncp = cp->next;
FREE(cp);
}
Cache[i] = NULL;
}
}