
/********************************************
code.c

libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:

copyright 1991-93, Michael D. Brennan

This is a source file for mawk, an implementation of
the AWK programming language.

Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include "mawk.h"
#include "code.h"
#include "init.h"
#include "jmp.h"
#include "field.h"


static CODEBLOCK *new_code(mawk_state_t *);

/* grow the active code */
void mawk_code_grow(mawk_state_t * MAWK)
{
	unsigned oldsize = mawk_code_limit - mawk_code_base;
	unsigned newsize = PAGESZ + oldsize;
	unsigned delta = mawk_code_ptr - mawk_code_base;

	if (mawk_code_ptr > mawk_code_limit)
		mawk_bozo(MAWK, "CODEWARN is too small");

	mawk_code_base = (INST *)
		mawk_zrealloc(MAWK, mawk_code_base, INST_BYTES(oldsize), INST_BYTES(newsize));
	mawk_code_limit = mawk_code_base + newsize;
	mawk_code_warn = mawk_code_limit - CODEWARN;
	mawk_code_ptr = mawk_code_base + delta;
}

void mawk_code_reset_size(mawk_state_t *MAWK, int newsize)
{
	unsigned oldsize = mawk_code_limit - mawk_code_base;

	mawk_bfree(MAWK, mawk_code_base, oldsize);

	mawk_code_base = (INST *)mawk_zmalloc(MAWK, INST_BYTES(newsize));
	mawk_code_limit = mawk_code_base + newsize;
	mawk_code_warn = mawk_code_limit - CODEWARN;
	mawk_code_ptr = mawk_code_base;
}


/* shrinks executable code that's done to its final size */
INST *mawk_code_shrink(mawk_state_t *MAWK, CODEBLOCK *p, unsigned *sizep)
{

	unsigned oldsize = INST_BYTES(p->limit - p->base);
	unsigned newsize = INST_BYTES(p->ptr - p->base);
	INST *retval;

	*sizep = newsize;

	retval = (INST *) mawk_zrealloc(MAWK, p->base, oldsize, newsize);

 /* free CODEBLOCK: only INST will be used as this block won't grow anymore */
	MAWK_ZFREE(MAWK, p);
	return retval;
}

/* code an op and a pointer in the active_code */
void mawk_xcode2(mawk_state_t *MAWK, int op, PTR ptr)
{
	register INST *p = mawk_code_ptr + 2;

	if (p >= mawk_code_warn) {
		mawk_code_grow(MAWK);
		p = mawk_code_ptr + 2;
	}

	p[-2].op = op;
	p[-1].ptr = ptr;
	mawk_code_ptr = p;
}

/* code two ops in the active_code */
void mawk_code2op(mawk_state_t *MAWK, int x, int y)
{
	register INST *p = mawk_code_ptr + 2;

	if (p >= mawk_code_warn) {
		mawk_code_grow(MAWK);
		p = mawk_code_ptr + 2;
	}

	p[-2].op = x;
	p[-1].op = y;
	mawk_code_ptr = p;
}

void mawk_code_init(mawk_state_t *MAWK)
{
	MAWK->main_code_p = new_code(MAWK);

	if (MAWK->main_code_p->ptr == NULL)
		return;

	MAWK->active_code = *MAWK->main_code_p;
	code1(_OMAIN);
}

/* final code relocation
   set_code() as in set concrete */
void mawk_set_code(mawk_state_t * MAWK)
{
	/* set the main code which is active_code */
	if (MAWK->end_code_p || mawk_code_offset > 1) {
		int gl_offset = mawk_code_offset;

		if (MAWK->NR_flag)
			mawk_code2op(MAWK, OL_GL_NR, _HALT);
		else
			mawk_code2op(MAWK, OL_GL, _HALT);

		*MAWK->main_code_p = MAWK->active_code;
		MAWK->main_start = mawk_code_shrink(MAWK, MAWK->main_code_p, &MAWK->main_size);
		MAWK->next_label = MAWK->main_start + gl_offset;
		MAWK->execution_start = MAWK->main_start;
	}
	else {												/* only BEGIN */

		mawk_zfree(MAWK, mawk_code_base, INST_BYTES(PAGESZ));
		MAWK_ZFREE(MAWK, MAWK->main_code_p);
		MAWK->main_code_p = NULL;
	}

	/* set the END code */
	if (MAWK->end_code_p) {
		MAWK->active_code = *MAWK->end_code_p;
		mawk_code2op(MAWK, _EXIT0, _HALT);
		*MAWK->end_code_p = MAWK->active_code;
		MAWK->end_start = mawk_code_shrink(MAWK, MAWK->end_code_p, &MAWK->end_size);
		MAWK->end_start_orig = MAWK->end_start;
	}

	/* set the BEGIN code */
	if (MAWK->begin_code_p) {
		MAWK->active_code = *MAWK->begin_code_p;
		if (MAWK->main_start)
			mawk_code2op(MAWK, _JMAIN, _HALT);
		else
			mawk_code2op(MAWK, _EXIT0, _HALT);
		*MAWK->begin_code_p = MAWK->active_code;
		MAWK->begin_start = mawk_code_shrink(MAWK, MAWK->begin_code_p, &MAWK->begin_size);

		MAWK->execution_start = MAWK->begin_start;
	}

	if (!MAWK->execution_start) {
		/* program had functions but no pattern-action bodies */
		MAWK->execution_start = MAWK->begin_start = (INST *) mawk_zmalloc(MAWK, 2 * sizeof(INST));
		MAWK->execution_start[0].op = _EXIT0;
		MAWK->execution_start[1].op = _HALT;
	}
}

static CODEBLOCK *new_code(mawk_state_t *MAWK)
{
	CODEBLOCK *p = MAWK_ZMALLOC(MAWK, CODEBLOCK);

	p->base = (INST *) mawk_zmalloc(MAWK, INST_BYTES(PAGESZ));
	p->limit = p->base + PAGESZ;
	p->warn = p->limit - CODEWARN;
	p->ptr = p->base;

	return p;
}

/* mawk_begin/end_setup: switches the active_code from MAIN to a
   BEGIN or END */

void mawk_be_setup(mawk_state_t *MAWK, int scope)
{
	*MAWK->main_code_p = MAWK->active_code;

	if (scope == SCOPE_BEGIN) {
		if (!MAWK->begin_code_p)
			MAWK->begin_code_p = new_code(MAWK);
		MAWK->active_code = *MAWK->begin_code_p;
	}
	else {
		if (!MAWK->end_code_p)
			MAWK->end_code_p = new_code(MAWK);
		MAWK->active_code = *MAWK->end_code_p;
	}
}
