mirror of
https://github.com/ThomasDickey/mawk-snapshots.git
synced 2026-01-26 19:09:15 +00:00
416 lines
8.0 KiB
C
416 lines
8.0 KiB
C
/********************************************
|
|
code.c
|
|
copyright 2009-2016,2019, Thomas E. Dickey
|
|
copyright 1991-1994,1995, 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.
|
|
********************************************/
|
|
|
|
/*
|
|
* $MawkId: code.c,v 1.39 2019/02/02 01:09:45 tom Exp $
|
|
*/
|
|
|
|
#include "mawk.h"
|
|
#include "code.h"
|
|
#include "init.h"
|
|
#include "jmp.h"
|
|
#include "field.h"
|
|
|
|
#ifdef NO_LEAKS
|
|
#include "repl.h"
|
|
#include "scan.h"
|
|
#endif
|
|
|
|
static CODEBLOCK *new_code(void);
|
|
|
|
CODEBLOCK active_code;
|
|
|
|
CODEBLOCK *main_code_p, *begin_code_p, *end_code_p;
|
|
|
|
INST *begin_start, *main_start, *end_start;
|
|
size_t begin_size, main_size, end_size;
|
|
|
|
INST *execution_start = 0;
|
|
|
|
/* grow the active code */
|
|
void
|
|
code_grow(void)
|
|
{
|
|
unsigned oldsize = (unsigned) (code_limit - code_base);
|
|
unsigned newsize = PAGESZ + oldsize;
|
|
unsigned delta = (unsigned) (code_ptr - code_base);
|
|
|
|
if (code_ptr > code_limit)
|
|
bozo("CODEWARN is too small");
|
|
|
|
code_base = (INST *)
|
|
zrealloc(code_base, INST_BYTES(oldsize),
|
|
INST_BYTES(newsize));
|
|
code_limit = code_base + newsize;
|
|
code_warn = code_limit - CODEWARN;
|
|
code_ptr = code_base + delta;
|
|
}
|
|
|
|
/* shrinks executable code that's done to its final size */
|
|
INST *
|
|
code_shrink(CODEBLOCK * p, size_t *sizep)
|
|
{
|
|
|
|
size_t oldsize = INST_BYTES(p->limit - p->base);
|
|
size_t newsize = INST_BYTES(p->ptr - p->base);
|
|
INST *retval;
|
|
|
|
*sizep = newsize;
|
|
|
|
retval = (INST *) zrealloc(p->base, oldsize, newsize);
|
|
TRACE(("code_shrink old %p %lu, new %p %lu\n",
|
|
(void *) p->base,
|
|
oldsize,
|
|
(void *) retval,
|
|
newsize));
|
|
ZFREE(p);
|
|
return retval;
|
|
}
|
|
|
|
/* code an op and a pointer in the active_code */
|
|
void
|
|
xcode2(int op, PTR ptr)
|
|
{
|
|
register INST *p = code_ptr + 2;
|
|
|
|
if (p >= code_warn) {
|
|
code_grow();
|
|
p = code_ptr + 2;
|
|
}
|
|
|
|
p[-2].op = op;
|
|
p[-1].ptr = ptr;
|
|
code_ptr = p;
|
|
}
|
|
|
|
/* code two ops in the active_code */
|
|
void
|
|
code2op(int x, int y)
|
|
{
|
|
register INST *p = code_ptr + 2;
|
|
|
|
if (p >= code_warn) {
|
|
code_grow();
|
|
p = code_ptr + 2;
|
|
}
|
|
|
|
p[-2].op = x;
|
|
p[-1].op = y;
|
|
code_ptr = p;
|
|
}
|
|
|
|
void
|
|
code_init(void)
|
|
{
|
|
main_code_p = new_code();
|
|
|
|
active_code = *main_code_p;
|
|
code1(_OMAIN);
|
|
}
|
|
|
|
/* final code relocation
|
|
set_code() as in set concrete */
|
|
void
|
|
set_code(void)
|
|
{
|
|
/* set the main code which is active_code */
|
|
if (end_code_p || code_offset > 1) {
|
|
int gl_offset = code_offset;
|
|
|
|
if (NR_flag)
|
|
code2op(OL_GL_NR, _HALT);
|
|
else
|
|
code2op(OL_GL, _HALT);
|
|
|
|
*main_code_p = active_code;
|
|
main_start = code_shrink(main_code_p, &main_size);
|
|
next_label = main_start + gl_offset;
|
|
execution_start = main_start;
|
|
} else { /* only BEGIN */
|
|
zfree(code_base, INST_BYTES(PAGESZ));
|
|
code_base = 0;
|
|
ZFREE(main_code_p);
|
|
}
|
|
|
|
/* set the END code */
|
|
if (end_code_p) {
|
|
active_code = *end_code_p;
|
|
code2op(_EXIT0, _HALT);
|
|
*end_code_p = active_code;
|
|
end_start = code_shrink(end_code_p, &end_size);
|
|
}
|
|
|
|
/* set the BEGIN code */
|
|
if (begin_code_p) {
|
|
active_code = *begin_code_p;
|
|
if (main_start)
|
|
code2op(_JMAIN, _HALT);
|
|
else
|
|
code2op(_EXIT0, _HALT);
|
|
*begin_code_p = active_code;
|
|
begin_start = code_shrink(begin_code_p, &begin_size);
|
|
|
|
execution_start = begin_start;
|
|
}
|
|
|
|
if (!execution_start) {
|
|
/* program had functions but no pattern-action bodies */
|
|
execution_start = begin_start = (INST *) zmalloc(2 * sizeof(INST));
|
|
execution_start[0].op = _EXIT0;
|
|
execution_start[1].op = _HALT;
|
|
}
|
|
}
|
|
|
|
void
|
|
dump_code(void)
|
|
{
|
|
dump_funcs(); /* dumps all user functions */
|
|
if (begin_start) {
|
|
fprintf(stdout, "BEGIN\n");
|
|
da(begin_start, stdout);
|
|
}
|
|
if (end_start) {
|
|
fprintf(stdout, "END\n");
|
|
da(end_start, stdout);
|
|
}
|
|
if (main_start) {
|
|
fprintf(stdout, "MAIN\n");
|
|
da(main_start, stdout);
|
|
}
|
|
dump_regex(); /* dumps all regular expressions */
|
|
}
|
|
|
|
static CODEBLOCK *
|
|
new_code(void)
|
|
{
|
|
CODEBLOCK *p = ZMALLOC(CODEBLOCK);
|
|
|
|
p->base = (INST *) zmalloc(INST_BYTES(PAGESZ));
|
|
p->limit = p->base + PAGESZ;
|
|
p->warn = p->limit - CODEWARN;
|
|
p->ptr = p->base;
|
|
|
|
return p;
|
|
}
|
|
|
|
/* moves the active_code from MAIN to a BEGIN or END */
|
|
|
|
void
|
|
be_setup(int scope)
|
|
{
|
|
*main_code_p = active_code;
|
|
|
|
if (scope == SCOPE_BEGIN) {
|
|
if (!begin_code_p)
|
|
begin_code_p = new_code();
|
|
active_code = *begin_code_p;
|
|
} else {
|
|
if (!end_code_p)
|
|
end_code_p = new_code();
|
|
active_code = *end_code_p;
|
|
}
|
|
}
|
|
|
|
#ifdef NO_LEAKS
|
|
void
|
|
free_cell_data(CELL *cp)
|
|
{
|
|
switch (cp->type) {
|
|
case C_RE:
|
|
TRACE(("\t... C_RE\n"));
|
|
re_destroy(cp->ptr);
|
|
zfree(cp, sizeof(CELL));
|
|
break;
|
|
case C_REPL:
|
|
TRACE(("\t... C_REPL\n"));
|
|
repl_destroy(cp);
|
|
zfree(cp, sizeof(CELL));
|
|
break;
|
|
case C_REPLV:
|
|
TRACE(("\t... C_REPLV\n"));
|
|
repl_destroy(cp);
|
|
zfree(cp, sizeof(CELL));
|
|
break;
|
|
case C_MBSTRN:
|
|
case C_STRING:
|
|
case C_STRNUM:
|
|
if (cp >= (field + (nf < 1 ? 1 : nf)) || (cp < field)) {
|
|
cell_destroy(cp);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
free_codes(const char *tag, INST * base, size_t size)
|
|
{
|
|
INST *cdp;
|
|
INST *last = base + (size / sizeof(*last));
|
|
CELL *cp;
|
|
|
|
(void) tag;
|
|
|
|
TRACE(("free_codes(%s) base %p, size %lu\n", tag, (void *) base, size));
|
|
if (base != 0 && size != 0) {
|
|
for (cdp = base; cdp < last; ++cdp) {
|
|
TRACE_INST(cdp, base);
|
|
|
|
switch ((MAWK_OPCODES) (cdp->op)) {
|
|
case AE_PUSHA:
|
|
case AE_PUSHI:
|
|
++cdp; /* skip pointer */
|
|
cp = (CELL *) (cdp->ptr);
|
|
if (cp != 0) {
|
|
free_cell_data(cp);
|
|
}
|
|
break;
|
|
case _MATCH0:
|
|
case _MATCH1:
|
|
++cdp; /* skip pointer */
|
|
re_destroy(cdp->ptr);
|
|
break;
|
|
case LAE_PUSHA:
|
|
case LA_PUSHA:
|
|
case A_CAT:
|
|
++cdp; /* skip value */
|
|
break;
|
|
case A_PUSHA:
|
|
case L_PUSHA:
|
|
case L_PUSHI:
|
|
case _BUILTIN:
|
|
case _PRINT:
|
|
case _PUSHA:
|
|
case _PUSHI:
|
|
case _PUSHINT:
|
|
++cdp; /* skip value */
|
|
break;
|
|
case _PUSHD:
|
|
++cdp; /* skip value */
|
|
if (cdp->ptr != &double_one && cdp->ptr != &double_zero)
|
|
zfree(cdp->ptr, sizeof(double));
|
|
break;
|
|
case F_PUSHI:
|
|
++cdp; /* skip pointer */
|
|
++cdp; /* skip integer */
|
|
break;
|
|
case _PUSHS:
|
|
++cdp; /* skip value */
|
|
free_STRING((STRING *) (cdp->ptr));
|
|
break;
|
|
case _RANGE:
|
|
cdp += 4; /* PAT1 */
|
|
break;
|
|
case _CALL:
|
|
cdp += 1 + cdp[2].op;
|
|
break;
|
|
case A_DEL:
|
|
case A_LENGTH:
|
|
case A_TEST:
|
|
case DEL_A:
|
|
case FE_PUSHA:
|
|
case FE_PUSHI:
|
|
case F_ADD_ASG:
|
|
case F_ASSIGN:
|
|
case F_DIV_ASG:
|
|
case F_MOD_ASG:
|
|
case F_MUL_ASG:
|
|
case F_POST_DEC:
|
|
case F_POST_INC:
|
|
case F_POW_ASG:
|
|
case F_PRE_DEC:
|
|
case F_PRE_INC:
|
|
case F_PUSHA:
|
|
case F_SUB_ASG:
|
|
case NF_PUSHI:
|
|
case OL_GL:
|
|
case OL_GL_NR:
|
|
case POP_AL:
|
|
case _ADD:
|
|
case _ADD_ASG:
|
|
case _ASSIGN:
|
|
case _CAT:
|
|
case _DIV:
|
|
case _DIV_ASG:
|
|
case _EQ:
|
|
case _EXIT0: /* this does free memory... */
|
|
case _EXIT:
|
|
case _GT:
|
|
case _GTE:
|
|
case _HALT:
|
|
case _JMAIN:
|
|
case _LT:
|
|
case _LTE:
|
|
case _MATCH2:
|
|
case _MOD:
|
|
case _MOD_ASG:
|
|
case _MUL:
|
|
case _MUL_ASG:
|
|
case _NEQ:
|
|
case _NEXT:
|
|
case _NEXTFILE:
|
|
case _NOT:
|
|
case _OMAIN:
|
|
case _POP:
|
|
case _POST_DEC:
|
|
case _POST_INC:
|
|
case _POW:
|
|
case _POW_ASG:
|
|
case _PRE_DEC:
|
|
case _PRE_INC:
|
|
case _RET0:
|
|
case _RET:
|
|
case _STOP:
|
|
case _SUB:
|
|
case _SUB_ASG:
|
|
case _TEST:
|
|
case _UMINUS:
|
|
case _UPLUS:
|
|
break;
|
|
case _JNZ:
|
|
case _JZ:
|
|
case _LJZ:
|
|
case _LJNZ:
|
|
case _JMP:
|
|
case _PUSHC:
|
|
case ALOOP:
|
|
case LAE_PUSHI:
|
|
case SET_ALOOP:
|
|
++cdp; /* cdp->op is literal param */
|
|
break;
|
|
}
|
|
}
|
|
zfree(base, size);
|
|
}
|
|
}
|
|
|
|
void
|
|
code_leaks(void)
|
|
{
|
|
TRACE(("code_leaks\n"));
|
|
if (begin_start != 0) {
|
|
free_codes("BEGIN", begin_start, begin_size);
|
|
begin_start = 0;
|
|
begin_size = 0;
|
|
}
|
|
if (end_start != 0) {
|
|
free_codes("END", end_start, end_size);
|
|
end_start = 0;
|
|
end_size = 0;
|
|
}
|
|
if (main_start != 0) {
|
|
free_codes("MAIN", main_start, main_size);
|
|
main_start = 0;
|
|
main_size = 0;
|
|
}
|
|
}
|
|
#endif
|