#include <string.h> /* setpos */ #define reelfunc_setpos_uintptr(ctx, ev, idx, val)\ if (*(val) < num_events) { evidx = *(val); goto loopstart; }\ else { return REEL_SETPOS_OUT_OF_BOUNDS; } #define reelfunc_setpos_uint(ctx, ev, idx, val)\ if (val < num_events) { evidx = val; goto loopstart; }\ else { return REEL_SETPOS_OUT_OF_BOUNDS; } /* num_events */ static inline void reelfunc_numevents_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval){ *lval = ctx->num_events; } /* inc */ static inline void reelfunc_inc_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ *lval += rval; } static inline void reelfunc_inc_tableptr_tableptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, reel_var *rval){ if (!(lval->table_value_type == REEL_UINT && lval->table_field == rval->table_field && lval->table_value_type == rval->table_value_type)){ ctx->error = REEL_TABLE_MISMATCH; }else{ uint64_t *dst = (uint64_t*)lval->value; const uint64_t *src = (uint64_t*)rval->value; uint64_t i; for (i = 0; i < lval->table_length; i++) dst[i] += src[i]; } } static inline void reelfunc_inc_tableitem_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, uint64_t rval){ if (lval->table_value_type != REEL_UINT){ ctx->error = REEL_TABLE_MISMATCH; }else if (lval->table_field){ uint64_t *dst = (uint64_t*)lval->value; dst[tdb_item_val(ev->items[lval->table_field - 1])] += rval; } } static inline void reelfunc_inc_tableitem_tableitem(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, reel_var *rval){ if (!(lval->table_value_type == REEL_UINT && rval->table_value_type == REEL_UINT && lval->table_field == rval->table_field)) ctx->error = REEL_TABLE_MISMATCH; else if (lval->table_field){ const uint64_t *src = (const uint64_t*)rval->value; uint64_t *dst = (uint64_t*)lval->value; uint64_t idx = tdb_item_val(ev->items[lval->table_field - 1]); dst[idx] += src[idx]; } } /* dec */ static inline void safe_dec(uint64_t *dst, uint64_t src) { if (*dst > src) *dst -= src; else *dst = 0; } static inline void reelfunc_dec_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ safe_dec(lval, rval); } static inline void reelfunc_dec_tableptr_tableptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, reel_var *rval){ if (!(lval->table_value_type == REEL_UINT && lval->table_field == rval->table_field && lval->table_value_type == rval->table_value_type)){ ctx->error = REEL_TABLE_MISMATCH; }else{ uint64_t *dst = (uint64_t*)lval->value; const uint64_t *src = (uint64_t*)rval->value; uint64_t i; for (i = 0; i < lval->table_length; i++) safe_dec(&dst[i], src[i]); } } static inline void reelfunc_dec_tableitem_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, uint64_t rval){ if (lval->table_value_type != REEL_UINT){ ctx->error = REEL_TABLE_MISMATCH; }else if (lval->table_field){ uint64_t *dst = (uint64_t*)lval->value; safe_dec(&dst[tdb_item_val(ev->items[lval->table_field - 1])], rval); } } static inline void reelfunc_dec_tableitem_tableitem(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, reel_var *rval){ if (!(lval->table_value_type == REEL_UINT && rval->table_value_type == REEL_UINT && lval->table_field == rval->table_field)) ctx->error = REEL_TABLE_MISMATCH; else if (lval->table_field){ const uint64_t *src = (const uint64_t*)rval->value; uint64_t *dst = (uint64_t*)lval->value; uint64_t idx = tdb_item_val(ev->items[lval->table_field - 1]); safe_dec(&dst[idx], src[idx]); } } /* set */ static inline void reelfunc_set_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ *lval = rval; } static inline void reelfunc_set_uintptr_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t *rval){ *lval = *rval; } static inline void reelfunc_set_itemptr_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item *lval, tdb_item rval){ *lval = rval; } static inline void reelfunc_set_itemptr_itemptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item *lval, tdb_item *rval){ *lval = *rval; } static inline void reelfunc_set_tableitem_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, uint64_t rval){ if (lval->table_value_type != REEL_UINT){ ctx->error = REEL_TABLE_MISMATCH; }else if (lval->table_field){ uint64_t *dst = (uint64_t*)lval->value; dst[tdb_item_val(ev->items[lval->table_field - 1])] = rval; } } static inline void reelfunc_set_tableitem_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *lval, uint64_t *rval){ if (lval->table_value_type != REEL_UINT){ ctx->error = REEL_TABLE_MISMATCH; }else if (lval->table_field){ uint64_t *dst = (uint64_t*)lval->value; dst[tdb_item_val(ev->items[lval->table_field - 1])] = *rval; } } static inline void reelfunc_set_uintptr_tableitem(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, reel_var *rval){ if (rval->table_value_type != REEL_UINT){ ctx->error = REEL_TABLE_MISMATCH; }else if (rval->table_field){ const uint64_t *src = (uint64_t*)rval->value; *lval = src[tdb_item_val(ev->items[rval->table_field - 1])]; }else *lval = 0; } /* unset */ static inline void reelfunc_unset_tableptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *val){ if (val->table_field){ uint64_t *dst = (uint64_t*)val->value; memset(dst, 0, val->table_length * 8); } } static inline void reelfunc_unset_tableitem(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *val){ if (val->table_field){ uint64_t *dst = (uint64_t*)val->value; dst[tdb_item_val(ev->items[val->table_field - 1])] = 0; } } static inline void reelfunc_unset_itemptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item *val){ *val = 0; } static inline void reelfunc_unset_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item *val){ *val = 0; } /* if */ static inline int reelfunc_if_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item item){ return tdb_item_val(item) != 0; } static inline int reelfunc_if_itemptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item *item){ return tdb_item_val(*item) != 0; } static inline int reelfunc_if_item_itemptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item lval, tdb_item *rval){ return lval == *rval; } static inline int reelfunc_if_itemptr_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item *lval, tdb_item rval){ return *lval == rval; } static inline int reelfunc_if_item_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, tdb_item lval, tdb_item rval){ return lval == rval; } static inline int reelfunc_if_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t val){ return val != 0; } static inline int reelfunc_if_tableitem(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, reel_var *val){ if (val->table_value_type != REEL_UINT) ctx->error = REEL_TABLE_MISMATCH; else if (val->table_field){ const uint64_t *src = (const uint64_t*)val->value; return src[tdb_item_val(ev->items[val->table_field - 1])] != 0; } return 0; } static inline int reelfunc_if_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *val){ return *val != 0; } static inline int reelfunc_if_uintptr_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t *rval){ return *lval == *rval; } static inline int reelfunc_if_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ return *lval == rval; } /* identity */ #define MAX_ID_ITEMS 6 static int reel_identity(reel_ctx *ctx, uint64_t *dst, const uint64_t args[MAX_ID_ITEMS]) { Word_t *ptr; JHSI(ptr, ctx->identities, (uint8_t*)args, MAX_ID_ITEMS * sizeof(uint64_t)) if (!*ptr){ *ptr = *dst = ++ctx->identity_counter; return 1; }else{ *dst = *ptr; return 0; } } static inline int reelfunc_id_uintptr_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t v1){ uint64_t args[MAX_ID_ITEMS] = {v1, 0, 0, 0, 0, 0}; return reel_identity(ctx, lval, args); } static inline int reelfunc_id_uintptr_item_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t v1, uint64_t v2){ uint64_t args[MAX_ID_ITEMS] = {v1, v2, 0, 0, 0, 0}; return reel_identity(ctx, lval, args); } static inline int reelfunc_id_uintptr_item_item_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t v1, uint64_t v2, uint64_t v3){ uint64_t args[MAX_ID_ITEMS] = {v1, v2, v3, 0, 0, 0}; return reel_identity(ctx, lval, args); } static inline int reelfunc_id_uintptr_item_item_item_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t v1, uint64_t v2, uint64_t v3, uint64_t v4){ uint64_t args[MAX_ID_ITEMS] = {v1, v2, v3, v4, 0, 0}; return reel_identity(ctx, lval, args); } static inline int reelfunc_id_uintptr_item_item_item_item_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t v1, uint64_t v2, uint64_t v3, uint64_t v4, uint64_t v5){ uint64_t args[MAX_ID_ITEMS] = {v1, v2, v3, v4, v5, 0}; return reel_identity(ctx, lval, args); } static inline int reelfunc_id_uintptr_item_item_item_item_item_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t v1, uint64_t v2, uint64_t v3, uint64_t v4, uint64_t v5, uint64_t v6){ uint64_t args[MAX_ID_ITEMS] = {v1, v2, v3, v4, v5, v6}; return reel_identity(ctx, lval, args); } /* time_before */ static inline int reelfunc_time_before_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ return ev->timestamp <= *lval + rval; } static inline int reelfunc_time_before_uintptr_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t *rval){ return ev->timestamp <= *lval + *rval; } /* time_after */ static inline int reelfunc_time_after_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ return ev->timestamp >= *lval + rval; } static inline int reelfunc_time_after_uintptr_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t *rval){ return ev->timestamp >= *lval + *rval; } static inline int reelfunc_time_after_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *val){ return ev->timestamp >= *val; } /* if_greater */ static inline int reelfunc_if_greater_uint_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t lval, uint64_t *rval){ return lval > *rval; } static inline int reelfunc_if_greater_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ return *lval > rval; } static inline int reelfunc_if_greater_or_equal_uint_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t lval, uint64_t *rval){ return lval >= *rval; } static inline int reelfunc_if_greater_or_equal_uintptr_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *lval, uint64_t rval){ return *lval >= rval; } /* print */ static inline void reelfunc_print_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *val){ fprintf(stderr, "debug %lu\n", *val); } static inline void reelfunc_print_itemptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *val){ fprintf(stderr, "debug %lu\n", *val); } static inline void reelfunc_print_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t val){ fprintf(stderr, "debug %lu\n", val); } static inline void reelfunc_print_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t val){ fprintf(stderr, "debug %lu\n", val); } /* tables */ static int reel_init_table(reel_var *var, const tdb *db, const char *field_name) { uintptr_t *p; if (tdb_get_field(db, field_name, &var->table_field)){ var->value = var->table_field = var->table_length = 0; return 0; } var->table_length = tdb_lexicon_size(db, var->table_field); if (!(p = calloc(1, var->table_length * sizeof(uintptr_t)))) return -1; var->value = (uintptr_t)p; return 0; } /* fork */ static reel_ctx *reel_clone(const reel_ctx *src, tdb *db, int do_reset, int do_deep_copy) { uint64_t i; reel_ctx *ctx; if (!(ctx = malloc(sizeof(reel_ctx)))) return NULL; memcpy(ctx, src, sizeof(reel_ctx)); ctx->trail_id = 0; if (db) ctx->db = db; /* handle variables */ for (i = 0; i < sizeof(ctx->vars) / sizeof(reel_var); i++){ reel_var *v = &ctx->vars[i]; if (v->table_field){ /* const tables are shared */ if (!(v->flags & REEL_FLAG_IS_CONST)){ char *p; if (!(p = calloc(v->table_length, sizeof(uintptr_t)))) goto out_of_mem; v->value = (uintptr_t)p; if (!do_reset) memcpy(p, (const char*)v->value, v->table_length * sizeof(uintptr_t)); } }else if (do_reset) /* zero scalar variables */ v->value = 0; } /* Make the new context a parent context. This may be changed later (see below). */ ctx->root = ctx; ctx->child_contexts = NULL; ctx->evaluated_contexts = NULL; if (do_deep_copy){ Word_t *ptr; Word_t key = 0; JLF(ptr, src->child_contexts, key); while (ptr){ const reel_ctx *src_child = (const reel_ctx*)*ptr; reel_ctx *dst_child = reel_clone(src_child, db, do_reset, 0); if (!dst_child) goto out_of_mem; dst_child->root = ctx; JLI(ptr, ctx->child_contexts, key); *ptr = (Word_t)dst_child; JLN(ptr, src->child_contexts, key); } } return ctx; out_of_mem: /* XXX we leak some memory here, tables and children are not freed */ free(ctx); return NULL; } static int reel_fork(reel_ctx *ctx, Word_t key) { int not_exists; J1S(not_exists, ctx->root->evaluated_contexts, key); if (!not_exists){ return 0; }else{ Word_t *ptr; JLI(ptr, ctx->root->child_contexts, key); if (!*ptr){ reel_ctx *child = reel_clone(ctx, NULL, 1, 0); if (!child){ ctx->error = REEL_FORK_FAILED; return 0; } *ptr = (Word_t)child; } ctx->child = (reel_ctx*)*ptr; return 1; } } static inline int reelfunc_fork_item(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t val){ return reel_fork(ctx, (Word_t)val); } static inline int reelfunc_fork_uint(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t val){ return reel_fork(ctx, (Word_t)val); } static inline int reelfunc_fork_uintptr(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx, uint64_t *val){ return reel_fork(ctx, (Word_t)*val); } static inline void reelfunc_fork_reset_active(reel_ctx *ctx, const tdb_event *ev, uint32_t func_idx){ Word_t tmp; J1FA(tmp, ctx->root->evaluated_contexts); } static int reel_get_forks(const reel_ctx *ctx, reel_ctx **ctxs, uint64_t *num_ctxs, uint64_t *ctxs_size) { Word_t num, key = 0; Word_t *ptr; JLC(num, ctx->child_contexts, 0, -1); if (num > *ctxs_size){ if (!(ctxs = realloc(ctxs, num * sizeof(reel_ctx*)))) return -1; *ctxs_size = num; } *num_ctxs = num; num = 0; JLF(ptr, ctx->child_contexts, key); while (ptr){ ctxs[num++] = (reel_ctx*)*ptr; JLN(ptr, ctx->child_contexts, key); } return 0; } /* utilities */ static tdb_item reel_resolve_item_literal(const tdb *db, const char *field_name, const char *value) { tdb_field field; if (tdb_get_field(db, field_name, &field)) return 0; return tdb_get_item(db, field, value, strlen(value)); } static tdb_field reel_resolve_field(const tdb *db, const char *field_name) { tdb_field field; if (tdb_get_field(db, field_name, &field)) return 0; return field; }