/* * SPL - The SPL Programming Language * Copyright (C) 2004, 2005 Clifford Wolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * rccheck.c: Checking the reference counters */ #include "spl.h" static inline int rcc_abs(int v) { return v < 0 ? v * -1 : v; } static int rcc_node(int rcc_pass, struct spl_node *node, int *rc_list, int *rc_count) { struct spl_node_sub *s; int size = 1; if ( !node ) return 0; switch ( rcc_pass ) { case 0: /* init and get size for rc_list */ if (node->dump_tag == 1) return 0; node->dump_tag = 1; break; case 1: /* assign numbers */ if (node->dump_tag != 1) return 0; node->dump_tag = ++(*rc_count) + 16; break; case 2: /* store reference counters */ rc_list[rcc_abs(node->dump_tag)-16]++; if (node->dump_tag < 0) return 0; node->dump_tag *= -1; break; case 3: /* check reference counters */ if (!node->dump_tag) return 0; if ( rc_list[rcc_abs(node->dump_tag)-16] != node->ref_counter ) spl_report(SPL_REPORT_RUNTIME, 0, "Refcount-Check: %p: should be %d but is %d.\n", node, rc_list[rcc_abs(node->dump_tag)-16], node->ref_counter); node->dump_tag = 0; break; } size += rcc_node(rcc_pass, node->ctx, rc_list, rc_count); size += rcc_node(rcc_pass, node->cls, rc_list, rc_count); for (s = node->subs_begin; s; s = s->next) size += rcc_node(rcc_pass, s->node, rc_list, rc_count); return size; } static int rcc_task(int rcc_pass, struct spl_task *task, int *rc_list, int *rc_count) { int size = 1; size += rcc_node(rcc_pass, task->ctx, rc_list, rc_count); struct spl_node_stack *s = task->stack; while (s) { size += rcc_node(rcc_pass, s->node, rc_list, rc_count); s = s->next; } return size; } static int rcc_vm(int rcc_pass, struct spl_vm *vm, int *rc_list, int *rc_count) { int size = 1; size += rcc_node(rcc_pass, vm->root, rc_list, rc_count); struct spl_task *t = vm->task_list; while (t) { size += rcc_task(rcc_pass, t, rc_list, rc_count); t = t->next; } return size; } void spl_rccheck(struct spl_vm *vm) { int size = rcc_vm(0, vm, 0, 0); int rc_list[size], rc_count = 0; for (int i=0; i