#include "declarations.h"
#include "dsl_cmd.h"
#include "dsl_shr.h"
#include "dsl_gc.h"



void dsl_gc_cmd(struct dsl_ctx *c) {
	unsigned long i;

	const struct dsl_cmd *s;

	/* This runs once when command structures needs cleanup, usually after
	   thread completes */
	s = c->script;

	for(i = 0; ; i++) {
		switch(s[i].c) {
			case DSL_COMMAND_NONE:
				return;
			case DSL_COMMAND_ABS:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_abs *) s[i].p)->c_d,
					((struct dsl_cmd_abs *) s[i].p)->d);

				break;
			case DSL_COMMAND_ADD:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_add *) s[i].p)->c_s,
					((struct dsl_cmd_add *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_add *) s[i].p)->c_d,
					((struct dsl_cmd_add *) s[i].p)->d);

				break;
			case DSL_COMMAND_CALL:
				(void) dsl_gc_cmd_call((struct dsl_cmd_call *) s[i].p, c);

				break;
			case DSL_COMMAND_CMP:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_cmp *) s[i].p)->c_s,
					((struct dsl_cmd_cmp *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_cmp *) s[i].p)->c_d,
					((struct dsl_cmd_cmp *) s[i].p)->d);

				break;
			case DSL_COMMAND_DEC:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_dec *) s[i].p)->c_d,
					((struct dsl_cmd_dec *) s[i].p)->d);

				break;
			case DSL_COMMAND_DIV:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_div *) s[i].p)->c_s,
					((struct dsl_cmd_div *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_div *) s[i].p)->c_d,
					((struct dsl_cmd_div *) s[i].p)->d);

				break;
			case DSL_COMMAND_END:
				(void) dsl_gc_cmd_end((struct dsl_cmd_end *) s[i].p, c);

				break;
			case DSL_COMMAND_FUNC:
				(void) dsl_gc_cmd_func((struct dsl_cmd_func *) s[i].p, c);

				break;
			case DSL_COMMAND_INC:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_inc *) s[i].p)->c_d,
					((struct dsl_cmd_inc *) s[i].p)->d);

				break;
			case DSL_COMMAND_MOD:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_mod *) s[i].p)->c_s,
					((struct dsl_cmd_mod *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_mod *) s[i].p)->c_d,
					((struct dsl_cmd_mod *) s[i].p)->d);

				break;
			case DSL_COMMAND_MOV:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_mov *) s[i].p)->c_s,
					((struct dsl_cmd_mov *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_mov *) s[i].p)->c_d,
					((struct dsl_cmd_mov *) s[i].p)->d);

				break;
			case DSL_COMMAND_DELIVER:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_deliver *) s[i].p)->c_s,
					((struct dsl_cmd_deliver *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_deliver *) s[i].p)->c_d,
					((struct dsl_cmd_deliver *) s[i].p)->d);

				break;
			case DSL_COMMAND_FETCH:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_fetch *) s[i].p)->c_s,
					((struct dsl_cmd_fetch *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_fetch *) s[i].p)->c_d,
					((struct dsl_cmd_fetch *) s[i].p)->d);

				break;
			case DSL_COMMAND_MUL:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_mul *) s[i].p)->c_s,
					((struct dsl_cmd_mul *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_mul *) s[i].p)->c_d,
					((struct dsl_cmd_mul *) s[i].p)->d);

				break;
			case DSL_COMMAND_NEG:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_neg *) s[i].p)->c_d,
					((struct dsl_cmd_neg *) s[i].p)->d);

				break;
			case DSL_COMMAND_POW:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_pow *) s[i].p)->c_s,
					((struct dsl_cmd_pow *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_pow *) s[i].p)->c_d,
					((struct dsl_cmd_pow *) s[i].p)->d);

				break;
			case DSL_COMMAND_RAND:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_rand *) s[i].p)->c_s,
					((struct dsl_cmd_rand *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_rand *) s[i].p)->c_d,
					((struct dsl_cmd_rand *) s[i].p)->d);

				break;
			case DSL_COMMAND_RET:
				(void) dsl_gc_cmd_ret((struct dsl_cmd_ret *) s[i].p, c);

				break;
			case DSL_COMMAND_SUB:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_sub *) s[i].p)->c_s,
					((struct dsl_cmd_sub *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_sub *) s[i].p)->c_d,
					((struct dsl_cmd_sub *) s[i].p)->d);

				break;
			case DSL_COMMAND_JA:
				/* Falls through */
			case DSL_COMMAND_JAE:
				/* Falls through */
			case DSL_COMMAND_JB:
				/* Falls through */
			case DSL_COMMAND_JBE:
				/* Falls through */
			case DSL_COMMAND_JE:
				/* Falls through */
			case DSL_COMMAND_JNE:
				/* Falls through */
			case DSL_COMMAND_JS:
				/* Falls through */
			case DSL_COMMAND_JNS:
				/* Falls through */
			case DSL_COMMAND_JZ:
				/* Falls through */
			case DSL_COMMAND_JNZ:
				/* Falls through */
			case DSL_COMMAND_JMP:
				(void) dsl_gc_cmd_jmp((struct dsl_cmd_jmp *) s[i].p, c);

				break;
#if ! defined(PROG_DISABLE_EXTENDED)
			case DSL_COMMAND_ISFINITE:
				/* Falls through */
			case DSL_COMMAND_ISINF:
				/* Falls through */
			case DSL_COMMAND_ISNAN:
				/* Falls through */
			case DSL_COMMAND_ISNORMAL:
				/* Falls through */
			case DSL_COMMAND_SIGNBIT:
				/* Falls through */
			case DSL_COMMAND_NAN:
				/* Falls through */
			case DSL_COMMAND_CEIL:
				/* Falls through */
			case DSL_COMMAND_FLOOR:
				/* Falls through */
			case DSL_COMMAND_NEARBYINT:
				/* Falls through */
			case DSL_COMMAND_RINT:
				/* Falls through */
			case DSL_COMMAND_ROUND:
				/* Falls through */
			case DSL_COMMAND_TRUNC:
				/* Falls through */
			case DSL_COMMAND_SQRT:
				/* Falls through */
			case DSL_COMMAND_CBRT:
				/* Falls through */
			case DSL_COMMAND_EXP:
				/* Falls through */
			case DSL_COMMAND_EXP2:
				/* Falls through */
			case DSL_COMMAND_EXPM1:
				/* Falls through */
			case DSL_COMMAND_LOG:
				/* Falls through */
			case DSL_COMMAND_LOG2:
				/* Falls through */
			case DSL_COMMAND_LOG10:
				/* Falls through */
			case DSL_COMMAND_LOG1P:
				/* Falls through */
			case DSL_COMMAND_LOGB:
				/* Falls through */
			case DSL_COMMAND_ILOGB:
				/* Falls through */
			case DSL_COMMAND_COS:
				/* Falls through */
			case DSL_COMMAND_COSH:
				/* Falls through */
			case DSL_COMMAND_ACOS:
				/* Falls through */
			case DSL_COMMAND_ACOSH:
				/* Falls through */
			case DSL_COMMAND_SIN:
				/* Falls through */
			case DSL_COMMAND_SINH:
				/* Falls through */
			case DSL_COMMAND_ASIN:
				/* Falls through */
			case DSL_COMMAND_ASINH:
				/* Falls through */
			case DSL_COMMAND_TAN:
				/* Falls through */
			case DSL_COMMAND_TANH:
				/* Falls through */
			case DSL_COMMAND_ATAN:
				/* Falls through */
			case DSL_COMMAND_ATANH:
				/* Falls through */
			case DSL_COMMAND_TGAMMA:
				/* Falls through */
			case DSL_COMMAND_LGAMMA:
				/* Falls through */
			case DSL_COMMAND_J0:
				/* Falls through */
			case DSL_COMMAND_J1:
				/* Falls through */
			case DSL_COMMAND_Y0:
				/* Falls through */
			case DSL_COMMAND_Y1:
				/* Falls through */
			case DSL_COMMAND_ERF:
				/* Falls through */
			case DSL_COMMAND_ERFC:
				/* Falls through */
			case DSL_COMMAND_GDENS:
				/* Falls through */
			case DSL_COMMAND_GDIST:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math2 *) s[i].p)->c_s,
					((struct dsl_cmd_math2 *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math2 *) s[i].p)->c_d,
					((struct dsl_cmd_math2 *) s[i].p)->d);

				break;
			case DSL_COMMAND_COPYSIGN:
				/* Falls through */
			case DSL_COMMAND_NEXTAFTER:
				/* Falls through */
			case DSL_COMMAND_NEXTTOWARD:
				/* Falls through */
			case DSL_COMMAND_REMAINDER:
				/* Falls through */
			case DSL_COMMAND_DIM:
				/* Falls through */
			case DSL_COMMAND_MAX:
				/* Falls through */
			case DSL_COMMAND_MIN:
				/* Falls through */
			case DSL_COMMAND_HYPOT:
				/* Falls through */
			case DSL_COMMAND_LDEXP:
				/* Falls through */
			case DSL_COMMAND_SCALBN:
				/* Falls through */
			case DSL_COMMAND_ATAN2:
				/* Falls through */
			case DSL_COMMAND_JN:
				/* Falls through */
			case DSL_COMMAND_YN:
				/* Falls through */
			case DSL_COMMAND_GRAND:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math3 *) s[i].p)->c_a,
					((struct dsl_cmd_math3 *) s[i].p)->s_a);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math3 *) s[i].p)->c_b,
					((struct dsl_cmd_math3 *) s[i].p)->s_b);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math3 *) s[i].p)->c_d,
					((struct dsl_cmd_math3 *) s[i].p)->d);

				break;
			case DSL_COMMAND_MODF:
				/* Falls through */
			case DSL_COMMAND_FREXP:
				/* Falls through */
			case DSL_COMMAND_FMA:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math4 *) s[i].p)->c_a,
					((struct dsl_cmd_math4 *) s[i].p)->s_a);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math4 *) s[i].p)->c_b,
					((struct dsl_cmd_math4 *) s[i].p)->s_b);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math4 *) s[i].p)->c_c,
					((struct dsl_cmd_math4 *) s[i].p)->s_c);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_math4 *) s[i].p)->c_d,
					((struct dsl_cmd_math4 *) s[i].p)->d);

				break;
			case DSL_COMMAND_CRC32:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_crc32 *) s[i].p)->c_s,
					((struct dsl_cmd_crc32 *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_crc32 *) s[i].p)->c_d,
					((struct dsl_cmd_crc32 *) s[i].p)->d);

				break;
			case DSL_COMMAND_CRC64:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_crc64 *) s[i].p)->c_s,
					((struct dsl_cmd_crc64 *) s[i].p)->s);

				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_crc64 *) s[i].p)->c_d,
					((struct dsl_cmd_crc64 *) s[i].p)->d);

				break;
#endif
			case DSL_COMMAND_DUMP:
				/* Subsystem test inside case so this is supported
				   but defunct */
#if ! defined(PROG_DISABLE_OUTPUT)
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_dump *) s[i].p)->c_v,
					((struct dsl_cmd_dump *) s[i].p)->v);
#endif
				break;
			case DSL_COMMAND_STON:
				/* Falls through */
			case DSL_COMMAND_PTON:
				/* Falls through */
			case DSL_COMMAND_HTON:
				/* Falls through */
			case DSL_COMMAND_NTOS:
				/* Falls through */
			case DSL_COMMAND_NTOP:
				/* Falls through */
			case DSL_COMMAND_NTOH:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_conv *) s[i].p)->c_d,
					((struct dsl_cmd_conv *) s[i].p)->d);

				break;
			case DSL_COMMAND_TOI8:
				/* Falls through */
			case DSL_COMMAND_TOI16:
				/* Falls through */
			case DSL_COMMAND_TOI32:
				/* Falls through */
			case DSL_COMMAND_TOI64:
				/* Falls through */
#if defined(__SIZEOF_INT128__)
			case DSL_COMMAND_TOI128:
				/* Falls through */
#endif
			case DSL_COMMAND_TOIOFFS:
				/* Falls through */
			case DSL_COMMAND_TOISIZE:
				/* Falls through */
			case DSL_COMMAND_TOU8:
				/* Falls through */
			case DSL_COMMAND_TOU16:
				/* Falls through */
			case DSL_COMMAND_TOU32:
				/* Falls through */
			case DSL_COMMAND_TOU64:
				/* Falls through */
#if defined(__SIZEOF_INT128__)
			case DSL_COMMAND_TOU128:
				/* Falls through */
#endif
			case DSL_COMMAND_TOUOFFS:
				/* Falls through */
			case DSL_COMMAND_TOUSIZE:
				/* Falls through */
			case DSL_COMMAND_TOCHAR:
				/* Falls through */
			case DSL_COMMAND_TOSHORT:
				/* Falls through */
			case DSL_COMMAND_TOINT:
				/* Falls through */
			case DSL_COMMAND_TOLONG:
				/* Falls through */
			case DSL_COMMAND_TOUCHAR:
				/* Falls through */
			case DSL_COMMAND_TOUSHORT:
				/* Falls through */
			case DSL_COMMAND_TOUINT:
				/* Falls through */
			case DSL_COMMAND_TOULONG:
				/* Falls through */
			case DSL_COMMAND_TOFLOAT:
				/* Falls through */
			case DSL_COMMAND_TODOUBLE:
				(void) dsl_gc_cmd_op(c->id,
					((struct dsl_cmd_type *) s[i].p)->c_d,
					((struct dsl_cmd_type *) s[i].p)->d);

				break;
			default:
				break;
		}
	}
}

static void dsl_gc_cmd_call(struct dsl_cmd_call *s, struct dsl_ctx *c) {
	if(s->c == DSL_PARAM_TYPE_VARIABLE) {
		(void) dsl_gc_cmd_op(c->id,
			((struct dsl_cmd_call_v *) s->p)->c_c,
			((struct dsl_cmd_call_v *) s->p)->cache);
	}
// XXX	_call_param_v->cache[c->id] = NULL;
}

static void dsl_gc_cmd_end(struct dsl_cmd_end *s, struct dsl_ctx *c) {
	if(s->c == DSL_PARAM_TYPE_VARIABLE) {
		(void) dsl_gc_cmd_op(c->id,
			((struct dsl_cmd_end_v *) s->p)->c_c,
			((struct dsl_cmd_end_v *) s->p)->cache);
	}
}

static void dsl_gc_cmd_func(struct dsl_cmd_func *s, struct dsl_ctx *c) {
	unsigned int i;

	if(s->c == DSL_PARAM_TYPE_VARIABLE) {
		(void) dsl_gc_cmd_op(c->id,
			((struct dsl_cmd_func_v *) s->lib)->c_a,
			((struct dsl_cmd_func_v *) s->lib)->cache_a);
	}

	if(s->d == DSL_PARAM_TYPE_VARIABLE) {
		(void) dsl_gc_cmd_op(c->id,
			((struct dsl_cmd_func_v *) s->sym)->c_b,
			((struct dsl_cmd_func_v *) s->sym)->cache_b);
	}

	if(s->q == NULL) {
		return;
	}

	for(i = 0; ; i++) {
		if(s->q[i].c == DSL_PARAM_TYPE_NONE) {
			break;
		}

		if(s->q[i].c == DSL_PARAM_TYPE_VARIABLE) {
			if(((struct dsl_cmd_func_param_v *) s->q[i].p)->c_c == 0) {
				continue;
			}

			(void) dsl_gc_cmd_op(c->id,
				((struct dsl_cmd_func_param_v *) s->q[i].p)->c_c,
				((struct dsl_cmd_func_param_v *) s->q[i].p)->cache);
		}
	}
}

static void dsl_gc_cmd_ret(struct dsl_cmd_ret *s, struct dsl_ctx *c) {
	if(s->c == DSL_PARAM_TYPE_VARIABLE) {
		(void) dsl_gc_cmd_op(c->id,
			((struct dsl_cmd_ret_param_v *) s->p)->c_c,
			((struct dsl_cmd_ret_param_v *) s->p)->cache);
	}
}

static void dsl_gc_cmd_jmp(struct dsl_cmd_jmp *s, struct dsl_ctx *c) {
	if(s->c == DSL_PARAM_TYPE_VARIABLE) {
		(void) dsl_gc_cmd_op(c->id,
			((struct dsl_cmd_jmp_v *) s->p)->c_c,
			((struct dsl_cmd_jmp_v *) s->p)->cache);
	}
}

static void dsl_gc_cmd_op(D_TID id, D_TID c, struct dsl_var **v) {
	/* Set cache slot to zero */
	if(id <= c) {
		v[id] = NULL;
	}
}
