1d276cdc68
[INTERPRETER] * BUG: Release arguments after having called a JIT method. * NEW: Add JIT interface for returning a value. [COMPILER] * NEW: JIT: Nicer translation for quick add of negative numbers.
1713 lines
35 KiB
C
1713 lines
35 KiB
C
/***************************************************************************
|
|
|
|
gbc_jit.c
|
|
|
|
(c) 2000-2018 Benoît Minisini <g4mba5@gmail.com>
|
|
|
|
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, 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., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#define __GBC_JIT_BODY_C
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
|
|
#include "gb_file.h"
|
|
#include "gb_str.h"
|
|
#include "gb_error.h"
|
|
#include "gb_pcode.h"
|
|
#include "gb_reserved.h"
|
|
#include "gbc_compile.h"
|
|
#include "gbc_chown.h"
|
|
#include "gbc_class.h"
|
|
#include "gbc_jit.h"
|
|
|
|
#define MAX_STACK 256
|
|
|
|
typedef
|
|
struct {
|
|
TYPE type;
|
|
char *expr;
|
|
}
|
|
STACK_SLOT;
|
|
|
|
static STACK_SLOT _stack[MAX_STACK];
|
|
static int _stack_current = 0;
|
|
|
|
static bool _decl_rs;
|
|
static bool _decl_ro;
|
|
static bool _decl_rv;
|
|
|
|
static int _ctrl_count;
|
|
static ushort _pc;
|
|
|
|
static bool _no_release = FALSE;
|
|
|
|
static char _func_type;
|
|
static int _func_index;
|
|
|
|
static void init(void)
|
|
{
|
|
_ctrl_count = 0;
|
|
|
|
JIT_print(" VALUE *sp = SP;\n");
|
|
JIT_print(" ushort *pc = PC;\n");
|
|
JIT_print(" void *gp = 0;\n");
|
|
}
|
|
|
|
|
|
static void free_stack(int n)
|
|
{
|
|
if (n < 0) n = _stack_current - n;
|
|
STR_free(_stack[n].expr);
|
|
_stack[n].expr = NULL;
|
|
}
|
|
|
|
|
|
static void check_stack(int n)
|
|
{
|
|
if (_stack_current < n)
|
|
THROW("Stack mismatch");
|
|
}
|
|
|
|
|
|
static void pop_stack(int n)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i <= n; i++)
|
|
free_stack(-i);
|
|
|
|
_stack_current -= n;
|
|
}
|
|
|
|
|
|
static void check_labels(ushort pos)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_count(TRANS_labels); i++)
|
|
{
|
|
if (TRANS_labels[i] == pos)
|
|
{
|
|
JIT_print("__L%d:;\n", pos);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void declare(bool *flag, const char *expr)
|
|
{
|
|
if (*flag)
|
|
return;
|
|
|
|
JIT_print(" %s;\n", expr);
|
|
*flag = TRUE;
|
|
}
|
|
|
|
|
|
static void push_one(TYPE type, const char *fmt, va_list args)
|
|
{
|
|
if (_stack_current > MAX_STACK)
|
|
THROW("Expression too complex");
|
|
|
|
_stack[_stack_current].expr = NULL;
|
|
|
|
if (fmt)
|
|
STR_vadd(&_stack[_stack_current].expr, fmt, args);
|
|
else
|
|
_stack[_stack_current].expr = STR_copy(va_arg(args, char *));
|
|
|
|
_stack[_stack_current].type = type;
|
|
_stack_current++;
|
|
}
|
|
|
|
|
|
static void push(TYPE type, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
//char *borrow = NULL;
|
|
|
|
va_start(args, fmt);
|
|
|
|
/*switch (TYPE_get_id(type))
|
|
{
|
|
case T_STRING:
|
|
case T_VARIANT:
|
|
case T_OBJECT:
|
|
STR_add(&borrow, "BORROW_%s(%s)", JIT_get_type(type), fmt);
|
|
push_one(type, borrow, args);
|
|
STR_free(borrow);
|
|
break;
|
|
|
|
default:
|
|
push_one(type, fmt, args);
|
|
}*/
|
|
|
|
push_one(type, fmt, args);
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
|
|
static TYPE get_type(int n)
|
|
{
|
|
if (n < 0) n += _stack_current;
|
|
return _stack[n].type;
|
|
}
|
|
|
|
#define get_type_id(_n) TYPE_get_id(get_type(_n))
|
|
|
|
|
|
static char *get_conv(TYPE src, TYPE dest)
|
|
{
|
|
static char buffer[32];
|
|
char s, d;
|
|
|
|
s = TYPE_get_id(src);
|
|
d = TYPE_get_id(dest);
|
|
|
|
if (s == T_UNKNOWN)
|
|
{
|
|
sprintf(buffer, "GB.Conv(%%s,%d)", d);
|
|
return buffer;
|
|
}
|
|
|
|
switch(d)
|
|
{
|
|
case T_VOID:
|
|
|
|
switch(s)
|
|
{
|
|
case T_STRING:
|
|
return "RELEASE_s(%s)";
|
|
case T_OBJECT:
|
|
return "RELEASE_o(%s)";
|
|
case T_VARIANT:
|
|
return "RELEASE_v(%s)";
|
|
default:
|
|
return "((void)%s)";
|
|
}
|
|
|
|
case T_BOOLEAN:
|
|
|
|
switch(s)
|
|
{
|
|
case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG: case T_SINGLE: case T_FLOAT: case T_POINTER:
|
|
return "((%s)!=0)";
|
|
case T_OBJECT:
|
|
return "((%s).value!=0)";
|
|
}
|
|
break;
|
|
|
|
case T_BYTE:
|
|
|
|
switch(s)
|
|
{
|
|
case T_BOOLEAN:
|
|
return "((uchar)(%s)?255:0)";
|
|
case T_SHORT: case T_INTEGER: case T_LONG: case T_SINGLE: case T_FLOAT:
|
|
return "((uchar)(%s))";
|
|
}
|
|
break;
|
|
|
|
case T_SHORT:
|
|
|
|
switch(s)
|
|
{
|
|
case T_BOOLEAN:
|
|
return "((short)(%s)?-1:0)";
|
|
case T_BYTE: case T_INTEGER: case T_LONG: case T_SINGLE: case T_FLOAT:
|
|
return "((short)(%s))";
|
|
}
|
|
break;
|
|
|
|
case T_INTEGER:
|
|
|
|
switch(s)
|
|
{
|
|
case T_BOOLEAN:
|
|
return "((int)(%s)?-1:0)";
|
|
case T_BYTE: case T_SHORT: case T_LONG: case T_SINGLE: case T_FLOAT: case T_POINTER:
|
|
return "((int)(%s))";
|
|
}
|
|
break;
|
|
|
|
case T_LONG:
|
|
|
|
switch(s)
|
|
{
|
|
case T_BOOLEAN:
|
|
return "((int64_t)(%s)?-1:0)";
|
|
case T_BYTE: case T_SHORT: case T_INTEGER: case T_SINGLE: case T_FLOAT: case T_POINTER:
|
|
return "((int64_t)(%s))";
|
|
}
|
|
break;
|
|
|
|
case T_SINGLE:
|
|
|
|
switch(s)
|
|
{
|
|
case T_BOOLEAN:
|
|
return "((float)(%s)?-1:0)";
|
|
case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG: case T_FLOAT:
|
|
return "((float)(%s))";
|
|
}
|
|
break;
|
|
|
|
case T_FLOAT:
|
|
|
|
switch(s)
|
|
{
|
|
case T_BOOLEAN:
|
|
return "((double)(%s)?-1:0)";
|
|
case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG: case T_SINGLE:
|
|
return "((double)(%s))";
|
|
}
|
|
break;
|
|
|
|
case T_STRING:
|
|
|
|
switch(s)
|
|
{
|
|
case T_CSTRING: return "%s";
|
|
}
|
|
break;
|
|
|
|
case T_CSTRING:
|
|
|
|
switch(s)
|
|
{
|
|
case T_STRING: return "%s";
|
|
}
|
|
break;
|
|
}
|
|
|
|
sprintf(buffer, "CONV_%s_%s(%%s)", JIT_get_type(src), JIT_get_type(dest));
|
|
return buffer;
|
|
}
|
|
|
|
static char *peek(int n, TYPE conv, const char *fmt, va_list args)
|
|
{
|
|
char *dest = NULL;
|
|
char *expr;
|
|
TYPE type;
|
|
char *op;
|
|
|
|
if (n < 0) n += _stack_current;
|
|
|
|
expr = _stack[n].expr;
|
|
type = _stack[n].type;
|
|
|
|
if (fmt)
|
|
{
|
|
STR_vadd(&dest, fmt, args);
|
|
|
|
if (!_no_release)
|
|
{
|
|
switch (TYPE_get_id(conv))
|
|
{
|
|
case T_STRING:
|
|
declare(&_decl_rs, "char *rs");
|
|
JIT_print(" rs = (%s).value.addr;\n", dest);
|
|
break;
|
|
|
|
case T_OBJECT:
|
|
declare(&_decl_ro, "void *ro");
|
|
JIT_print(" ro = (%s).value;\n", dest);
|
|
break;
|
|
|
|
case T_VARIANT:
|
|
declare(&_decl_rv, "GB_VARIANT rv");
|
|
JIT_print(" rv = (%s);\n", dest);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!TYPE_compare(&type, &conv))
|
|
{
|
|
char *expr2 = NULL;
|
|
STR_add(&expr2, get_conv(type, conv), expr);
|
|
STR_free(expr);
|
|
expr = expr2;
|
|
_stack[n].expr = expr2;
|
|
}
|
|
|
|
if (fmt)
|
|
{
|
|
if (_no_release)
|
|
{
|
|
JIT_print(" ");
|
|
JIT_print(dest, expr);
|
|
JIT_print(";\n");
|
|
}
|
|
else
|
|
{
|
|
if (dest[strlen(dest) - 1] != '=')
|
|
op = " =";
|
|
else
|
|
op = "";
|
|
|
|
switch (TYPE_get_id(conv))
|
|
{
|
|
case T_STRING:
|
|
JIT_print(" %s%s BORROW_s(%s);\n", dest, op, expr);
|
|
break;
|
|
|
|
case T_OBJECT:
|
|
JIT_print(" %s%s BORROW_o(%s);\n", dest, op, expr);
|
|
break;
|
|
|
|
case T_VARIANT:
|
|
JIT_print(" %s%s BORROW_v(%s);\n", dest, op, expr);
|
|
break;
|
|
|
|
default:
|
|
JIT_print(" %s%s %s;\n", dest, op, expr);
|
|
}
|
|
|
|
|
|
|
|
if (!_no_release)
|
|
{
|
|
switch (TYPE_get_id(conv))
|
|
{
|
|
case T_STRING: JIT_print(" GB.FreeString(&rs);\n"); break;
|
|
case T_OBJECT: JIT_print(" GB.Unref(&ro);\n"); break;
|
|
case T_VARIANT: JIT_print(" GB.ReleaseValue((GB_VALUE *)&rv);\n"); break;
|
|
}
|
|
}
|
|
}
|
|
STR_free(dest);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
|
|
static void pop(TYPE type, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
char *expr;
|
|
|
|
check_stack(1);
|
|
|
|
_stack_current--;
|
|
|
|
va_start(args, fmt);
|
|
expr = peek(_stack_current, type, fmt, args);
|
|
va_end(args);
|
|
|
|
if (!fmt)
|
|
JIT_print(" %s;\n", expr);
|
|
|
|
free_stack(_stack_current);
|
|
}
|
|
|
|
|
|
static void push_constant(int index)
|
|
{
|
|
CONSTANT *c = &JOB->class->constant[index];
|
|
|
|
switch(TYPE_get_id(c->type))
|
|
{
|
|
case T_SINGLE:
|
|
push(c->type, "(float)%s", TABLE_get_symbol_name(JOB->class->table, c->value));
|
|
break;
|
|
case T_FLOAT:
|
|
push(c->type, "(double)%s", TABLE_get_symbol_name(JOB->class->table, c->value));
|
|
break;
|
|
default:
|
|
push(TYPE_get_id(c->type) == T_STRING ? TYPE_make_simple(T_CSTRING) : c->type, "CONSTANT_%s(%d)", JIT_get_type(c->type), index);
|
|
}
|
|
}
|
|
|
|
|
|
static void push_subr(ushort code, const char *call)
|
|
{
|
|
char type_id;
|
|
TYPE type;
|
|
int i, narg;
|
|
char *expr = NULL;
|
|
ushort op;
|
|
bool rst = FALSE;
|
|
|
|
//declare_sp();
|
|
|
|
//JIT_print(" static ushort s%d = 0x%04X;\n", _subr_count, code);
|
|
|
|
op = code >> 8;
|
|
|
|
if (op == (C_NEW >> 8))
|
|
{
|
|
narg = code & 0x3F;
|
|
type_id = T_OBJECT;
|
|
type = get_type(-narg);
|
|
}
|
|
else if (op < CODE_FIRST_SUBR)
|
|
{
|
|
int index = RESERVED_get_from_opcode(code);
|
|
|
|
if (index < 0)
|
|
THROW("Unknown operator");
|
|
|
|
if (RES_is_unary(index))
|
|
narg = 1;
|
|
else if (RES_is_binary(index))
|
|
narg = 2;
|
|
else
|
|
narg = code & 0x3F;
|
|
|
|
type_id = COMP_res_info[index].type;
|
|
rst = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SUBR_INFO *info = SUBR_get_from_opcode(op - CODE_FIRST_SUBR, code & 0x3F);
|
|
if (info->min_param != info->max_param)
|
|
narg = code & 0x3F;
|
|
else
|
|
narg = info->min_param;
|
|
|
|
type_id = info->type;
|
|
rst = TRUE;
|
|
}
|
|
|
|
check_stack(narg);
|
|
|
|
if (rst)
|
|
{
|
|
switch(type_id)
|
|
{
|
|
case RST_SAME:
|
|
case RST_BCLR:
|
|
type_id = get_type_id(-narg);
|
|
break;
|
|
|
|
case RST_MIN:
|
|
type_id = Max(get_type_id(-1), get_type_id(-2));
|
|
if (type_id > T_DATE && type_id != T_VARIANT)
|
|
type_id = T_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
if (type_id > T_OBJECT)
|
|
type_id = T_UNKNOWN;
|
|
|
|
for (i = _stack_current - narg; i < _stack_current; i++)
|
|
{
|
|
STR_add(&expr, "PUSH_%s(%s),", JIT_get_type(_stack[i].type), _stack[i].expr);
|
|
free_stack(i);
|
|
}
|
|
|
|
_stack_current -= narg;
|
|
|
|
STR_add(&expr, "%s(%d, 0x%04X)", call, _pc, code);
|
|
if (type_id == T_VOID)
|
|
STR_add(&expr, ",sp--");
|
|
else
|
|
STR_add(&expr, ",POP_%s()", JIT_get_type(TYPE_make_simple(type_id)));
|
|
|
|
if (op == (C_NEW >> 8))
|
|
{
|
|
if (TYPE_get_id(type) == T_CLASS)
|
|
TYPE_set_id(&type, T_OBJECT);
|
|
else
|
|
type = TYPE_make_simple(T_OBJECT);
|
|
}
|
|
else
|
|
type = TYPE_make_simple(type_id);
|
|
|
|
push(type, "(%s)", expr);
|
|
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void push_subr_add(ushort code, const char *op, const char *opb, bool allow_pointer)
|
|
{
|
|
char *expr;
|
|
char *expr1, *expr2;
|
|
TYPE type1, type2, type;
|
|
|
|
check_stack(2);
|
|
|
|
type1 = get_type(-2);
|
|
type2 = get_type(-1);
|
|
|
|
if (TYPE_get_id(type1) > TYPE_get_id(type2))
|
|
type = type1;
|
|
else
|
|
type = type2;
|
|
|
|
switch(TYPE_get_id(type))
|
|
{
|
|
case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG: case T_SINGLE: case T_FLOAT:
|
|
break;
|
|
|
|
case T_DATE: case T_STRING: case T_CSTRING:
|
|
type = TYPE_make_simple(T_FLOAT);
|
|
break;
|
|
|
|
case T_POINTER:
|
|
if (allow_pointer)
|
|
break;
|
|
|
|
default:
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
return;
|
|
}
|
|
|
|
expr1 = peek(-2, type, NULL, NULL);
|
|
expr2 = peek(-1, type, NULL, NULL);
|
|
|
|
switch(TYPE_get_id(type))
|
|
{
|
|
case T_BOOLEAN:
|
|
expr = STR_print("%s %s %s", expr1, opb, expr2);
|
|
break;
|
|
|
|
default:
|
|
expr = STR_print("%s %s %s", expr1, op, expr2);
|
|
break;
|
|
}
|
|
|
|
pop_stack(2);
|
|
|
|
push(type, "(%s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void push_subr_div(ushort code)
|
|
{
|
|
char *expr;
|
|
char *expr1, *expr2;
|
|
TYPE type1, type2, type;
|
|
|
|
check_stack(2);
|
|
|
|
type1 = get_type(-2);
|
|
type2 = get_type(-1);
|
|
|
|
if (TYPE_get_id(type1) > TYPE_get_id(type2))
|
|
type = type1;
|
|
else
|
|
type = type2;
|
|
|
|
switch(TYPE_get_id(type))
|
|
{
|
|
case T_SINGLE: case T_FLOAT:
|
|
break;
|
|
|
|
case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG:
|
|
type = TYPE_make_simple(T_FLOAT);
|
|
break;
|
|
|
|
default:
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
return;
|
|
}
|
|
|
|
expr1 = peek(-2, type, NULL, NULL);
|
|
expr2 = peek(-1, type, NULL, NULL);
|
|
expr = STR_print("%s / %s", expr1, expr2);
|
|
|
|
pop_stack(2);
|
|
|
|
push(type, "(%s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void push_subr_neg(ushort code)
|
|
{
|
|
TYPE type;
|
|
char *expr;
|
|
|
|
check_stack(1);
|
|
|
|
type = get_type(-1);
|
|
|
|
switch(TYPE_get_id(type))
|
|
{
|
|
case T_BOOLEAN:
|
|
return;
|
|
|
|
case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG: case T_SINGLE: case T_FLOAT:
|
|
break;
|
|
|
|
default:
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
return;
|
|
}
|
|
|
|
expr = STR_copy(peek(-1, type, NULL, NULL));
|
|
|
|
pop_stack(1);
|
|
push(type, "(- %s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
|
|
static void push_subr_and(ushort code, const char *op)
|
|
{
|
|
char *expr;
|
|
char *expr1, *expr2;
|
|
TYPE type1, type2, type;
|
|
|
|
check_stack(2);
|
|
|
|
type1 = get_type(-2);
|
|
type2 = get_type(-1);
|
|
|
|
if (TYPE_get_id(type1) > TYPE_get_id(type2))
|
|
type = type1;
|
|
else
|
|
type = type2;
|
|
|
|
switch(TYPE_get_id(type))
|
|
{
|
|
case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG:
|
|
break;
|
|
|
|
case T_DATE: case T_STRING: case T_CSTRING:
|
|
type = TYPE_make_simple(T_BOOLEAN);
|
|
break;
|
|
|
|
default:
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
return;
|
|
}
|
|
|
|
expr1 = peek(-2, type, NULL, NULL);
|
|
expr2 = peek(-1, type, NULL, NULL);
|
|
|
|
expr = STR_print("%s %s %s", expr1, op, expr2);
|
|
|
|
pop_stack(2);
|
|
push(type, "(%s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void push_subr_not(ushort code)
|
|
{
|
|
TYPE type;
|
|
char *expr;
|
|
char *op;
|
|
|
|
check_stack(1);
|
|
|
|
type = get_type(-1);
|
|
|
|
switch(TYPE_get_id(type))
|
|
{
|
|
case T_BOOLEAN:
|
|
op = "!";
|
|
break;
|
|
|
|
case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG:
|
|
op = "~";
|
|
break;
|
|
|
|
default:
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
return;
|
|
}
|
|
|
|
expr = STR_print("%s%s", op, peek(-1, type, NULL, NULL));
|
|
|
|
pop_stack(1);
|
|
push(type, "(%s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void push_subr_comp(ushort code)
|
|
{
|
|
char *op = NULL;
|
|
char *expr;
|
|
char *expr1, *expr2;
|
|
TYPE type1, type2, type;
|
|
|
|
check_stack(2);
|
|
|
|
type1 = get_type(-2);
|
|
type2 = get_type(-1);
|
|
|
|
if (TYPE_get_id(type1) > TYPE_get_id(type2))
|
|
type = type1;
|
|
else
|
|
type = type2;
|
|
|
|
switch(TYPE_get_id(type))
|
|
{
|
|
case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_INTEGER: case T_LONG: case T_SINGLE: case T_FLOAT: case T_POINTER:
|
|
|
|
switch(code & 0xFF00)
|
|
{
|
|
case C_EQ: op = "=="; break;
|
|
case C_NE: op = "!="; break;
|
|
case C_GT: op = ">"; break;
|
|
case C_LT: op = "<"; break;
|
|
case C_GE: op = ">="; break;
|
|
case C_LE: op = "<="; break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!op)
|
|
{
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
return;
|
|
}
|
|
|
|
expr1 = peek(-2, type, NULL, NULL);
|
|
expr2 = peek(-1, type, NULL, NULL);
|
|
|
|
expr = STR_print("%s %s %s", expr1, op, expr2);
|
|
|
|
pop_stack(2);
|
|
|
|
push(TYPE_make_simple(T_BOOLEAN), "(%s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void push_subr_conv(ushort code)
|
|
{
|
|
char *expr;
|
|
TYPE type;
|
|
TYPE conv = TYPE_make_simple(code & 0x3F);
|
|
|
|
check_stack(1);
|
|
type = get_type(-1);
|
|
|
|
if (TYPE_compare(&type, &conv))
|
|
return;
|
|
|
|
expr = peek(-1, conv, NULL, NULL);
|
|
pop_stack(1);
|
|
push(conv, "(%s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void push_subr_len(ushort code)
|
|
{
|
|
char *expr;
|
|
|
|
check_stack(1);
|
|
|
|
expr = peek(-1, TYPE_make_simple(T_STRING), NULL, NULL);
|
|
pop_stack(1);
|
|
push(TYPE_make_simple(T_INTEGER), "((%s).value.len)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
/*static void push_subr_left(ushort code)
|
|
{
|
|
char *expr = NULL;
|
|
TYPE type;
|
|
char *expr_str, *expr_len = NULL;
|
|
|
|
declare_sp();
|
|
|
|
JIT_print(" static ushort s%d = 0x%04X;\n", _subr_count, code);
|
|
|
|
check_stack(1);
|
|
|
|
if (_stack_current >= 2)
|
|
{
|
|
expr_len = peek(-1, TYPE_make_simple(T_INTEGER), NULL, NULL);
|
|
pop_stack(1);
|
|
}
|
|
|
|
type = get_type(-1);
|
|
expr_str = peek(-1, TYPE_make_simple(T_CSTRING), NULL, NULL);
|
|
pop_stack(1);
|
|
|
|
STR_add(&expr, "(PUSH_t(%s)", expr_str);
|
|
STR_free(expr_str);
|
|
if (expr_len)
|
|
{
|
|
STR_add(&expr, ",PUSH_i(%s)", expr_len);
|
|
STR_free(expr_len);
|
|
}
|
|
|
|
push(type, "%s,CALL_SUBR_CODE(s%d),POP_t())", expr, _subr_count, code);
|
|
_subr_count++;
|
|
}*/
|
|
|
|
|
|
static void push_array(ushort code)
|
|
{
|
|
TYPE type;
|
|
int i, narg;
|
|
char *expr = NULL;
|
|
char *expr1, *expr2;
|
|
|
|
narg = code & 0x3F;
|
|
check_stack(narg);
|
|
|
|
type = get_type(-narg);
|
|
|
|
if (TYPE_get_id(type) == T_OBJECT)
|
|
{
|
|
CLASS_REF *cr = &JOB->class->class[TYPE_get_value(type)];
|
|
|
|
SYMBOL *sym = (SYMBOL *)CLASS_get_symbol(JOB->class, cr->index);
|
|
JIT_print(" // %.*s\n", sym->len, sym->name);
|
|
|
|
if (!TYPE_is_null(cr->type))
|
|
{
|
|
if (narg == 2)
|
|
{
|
|
expr1 = peek(-2, get_type(-2), NULL, NULL);
|
|
expr2 = peek(-1, TYPE_make_simple(T_INTEGER), NULL, NULL);
|
|
|
|
expr = STR_print("PUSH_ARRAY_%s(%s,%s)", JIT_get_type(cr->type), expr1, expr2);
|
|
|
|
pop_stack(2);
|
|
|
|
push(cr->type, "(%s)", expr);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
type = cr->type;
|
|
}
|
|
else
|
|
type = TYPE_make_simple(T_UNKNOWN);
|
|
|
|
//declare_sp();
|
|
|
|
for (i = _stack_current - narg; i < _stack_current; i++)
|
|
{
|
|
STR_add(&expr, "PUSH_%s(%s),", JIT_get_type(_stack[i].type), _stack[i].expr);
|
|
free_stack(i);
|
|
}
|
|
|
|
_stack_current -= narg;
|
|
|
|
STR_add(&expr, "CALL_PUSH_ARRAY(%d),sp--", _pc);
|
|
|
|
push(type, "(%s)", expr);
|
|
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
static void pop_array(ushort code)
|
|
{
|
|
TYPE type;
|
|
int i, narg;
|
|
char *expr = NULL;
|
|
char *expr1, *expr2;
|
|
|
|
narg = code & 0x3F;
|
|
check_stack(narg + 1);
|
|
|
|
type = get_type(-narg);
|
|
|
|
if (TYPE_get_id(type) == T_OBJECT)
|
|
{
|
|
CLASS_REF *cr = &JOB->class->class[TYPE_get_value(type)];
|
|
|
|
SYMBOL *sym = (SYMBOL *)CLASS_get_symbol(JOB->class, cr->index);
|
|
JIT_print(" // %.*s\n", sym->len, sym->name);
|
|
|
|
if (!TYPE_is_null(cr->type))
|
|
{
|
|
if (narg == 2)
|
|
{
|
|
expr = peek(-3, cr->type, NULL, NULL);
|
|
expr1 = peek(-2, get_type(-2), NULL, NULL);
|
|
expr2 = peek(-1, TYPE_make_simple(T_INTEGER), NULL, NULL);
|
|
|
|
JIT_print(" POP_ARRAY_%s(%s,%s,%s);\n", JIT_get_type(cr->type), expr1, expr2, expr);
|
|
|
|
pop_stack(3);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
type = cr->type;
|
|
}
|
|
else
|
|
type = TYPE_make_simple(T_UNKNOWN);
|
|
|
|
//declare_sp();
|
|
|
|
narg++;
|
|
|
|
for (i = _stack_current - narg; i < _stack_current; i++)
|
|
{
|
|
STR_add(&expr, "PUSH_%s(%s),", JIT_get_type(_stack[i].type), _stack[i].expr);
|
|
free_stack(i);
|
|
}
|
|
|
|
_stack_current -= narg;
|
|
|
|
STR_add(&expr, "CALL_POP_ARRAY(%d),sp--", _pc);
|
|
|
|
push(TYPE_make_simple(T_VOID), "(%s)", expr);
|
|
|
|
STR_free(expr);
|
|
|
|
pop(TYPE_make_simple(T_VOID), NULL);
|
|
}
|
|
|
|
|
|
static void push_call(ushort code)
|
|
{
|
|
char *call = NULL;
|
|
int i;
|
|
int narg;
|
|
FUNCTION *func;
|
|
|
|
narg = code & 0x3F;
|
|
|
|
switch (_func_type)
|
|
{
|
|
case FUNCTION_PRIVATE:
|
|
|
|
func = &JOB->class->function[_func_index];
|
|
|
|
STR_add(&call,"%s_%d_IMPL(", JIT_prefix, _func_index);
|
|
|
|
for (i = 0; i < narg; i++)
|
|
STR_add(&call, ((i < (narg - 1)) ? "%s," : "%s"), peek(i - narg, func->param[i].type, NULL, NULL));
|
|
|
|
STR_add(&call, ")");
|
|
|
|
pop_stack(narg);
|
|
|
|
push(func->type, "(%s)", call);
|
|
|
|
break;
|
|
}
|
|
|
|
_func_type = -1;
|
|
}
|
|
|
|
|
|
static void push_subr_isnan(ushort code)
|
|
{
|
|
char *func;
|
|
char *expr;
|
|
|
|
check_stack(1);
|
|
|
|
switch (code & 0xFF)
|
|
{
|
|
case 1: // IsNan
|
|
func = "isnan";
|
|
break;
|
|
|
|
case 2: // IsInf
|
|
func = "isinf";
|
|
break;
|
|
|
|
default:
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
return;
|
|
}
|
|
|
|
expr = STR_print("%s(%s) != 0", func, peek(-1, TYPE_make_simple(T_FLOAT), NULL, NULL));
|
|
|
|
pop_stack(1);
|
|
push(TYPE_make_simple(T_BOOLEAN), "(%s)", expr);
|
|
STR_free(expr);
|
|
}
|
|
|
|
|
|
#define GET_XXX() (((signed short)(code << 4)) >> 4)
|
|
#define GET_UXX() (code & 0xFFF)
|
|
#define GET_7XX() (code & 0x7FF)
|
|
#define GET_XX() ((signed char)code)
|
|
#define GET_UX() ((unsigned char)code)
|
|
#define GET_3X() (code & 0x3F)
|
|
#define TEST_XX() (code & 1)
|
|
#define PC (&func->code[p])
|
|
|
|
void JIT_translate_body(FUNCTION *func)
|
|
{
|
|
static const void *jump_table[256] =
|
|
{
|
|
/* 00 NOP */ &&_MAIN,
|
|
/* 01 PUSH LOCAL */ &&_PUSH_LOCAL,
|
|
/* 02 PUSH PARAM */ &&_PUSH_PARAM,
|
|
/* 03 PUSH ARRAY */ &&_PUSH_ARRAY,
|
|
/* 04 PUSH UNKNOWN */ &&_PUSH_UNKNOWN,
|
|
/* 05 PUSH EXTERN */ &&_PUSH_EXTERN,
|
|
/* 06 BYREF */ &&_BYREF,
|
|
/* 07 PUSH EVENT */ &&_PUSH_EVENT,
|
|
/* 08 QUIT */ &&_QUIT,
|
|
/* 09 POP LOCAL */ &&_POP_LOCAL,
|
|
/* 0A POP PARAM */ &&_POP_PARAM,
|
|
/* 0B POP ARRAY */ &&_POP_ARRAY,
|
|
/* 0C POP UNKNOWN */ &&_POP_UNKNOWN,
|
|
/* 0D POP OPTIONAL */ &&_POP_OPTIONAL,
|
|
/* 0E POP CTRL */ &&_POP_CTRL,
|
|
/* 0F BREAK */ &&_BREAK,
|
|
/* 10 RETURN */ &&_RETURN,
|
|
/* 11 PUSH SHORT */ &&_PUSH_SHORT,
|
|
/* 12 PUSH INTEGER */ &&_PUSH_INTEGER,
|
|
/* 13 PUSH CHAR */ &&_PUSH_CHAR,
|
|
/* 14 PUSH MISC */ &&_PUSH_MISC,
|
|
/* 15 PUSH ME */ &&_PUSH_ME,
|
|
/* 16 TRY */ &&_TRY,
|
|
/* 17 END TRY */ &&_END_TRY,
|
|
/* 18 CATCH */ &&_CATCH,
|
|
/* 19 DUP */ &&_DUP,
|
|
/* 1A DROP */ &&_DROP,
|
|
/* 1B NEW */ &&_NEW,
|
|
/* 1C CALL */ &&_CALL,
|
|
/* 1D CALL QUICK */ &&_CALL_QUICK,
|
|
/* 1E CALL EASY */ &&_CALL_SLOW,
|
|
/* 1F ON */ &&_ON_GOTO_GOSUB,
|
|
/* 20 JUMP */ &&_JUMP,
|
|
/* 21 JUMP IF TRUE */ &&_JUMP_IF_TRUE,
|
|
/* 22 JUMP IF FALSE */ &&_JUMP_IF_FALSE,
|
|
/* 23 GOSUB */ &&_GOSUB,
|
|
/* 24 JUMP FIRST */ &&_JUMP_FIRST,
|
|
/* 25 JUMP NEXT */ &&_JUMP_NEXT,
|
|
/* 26 FIRST */ &&_ENUM_FIRST,
|
|
/* 27 NEXT */ &&_ENUM_NEXT,
|
|
/* 28 = */ &&_SUBR_COMPE,
|
|
/* 29 <> */ &&_SUBR_COMPN,
|
|
/* 2A > */ &&_SUBR_COMPGT,
|
|
/* 2B <= */ &&_SUBR_COMPLE,
|
|
/* 2C < */ &&_SUBR_COMPLT,
|
|
/* 2D >= */ &&_SUBR_COMPGE,
|
|
/* 2E == */ &&_SUBR,
|
|
/* 2F CASE */ &&_SUBR_CODE,
|
|
/* 30 + */ &&_SUBR_ADD,
|
|
/* 31 - */ &&_SUBR_SUB,
|
|
/* 32 * */ &&_SUBR_MUL,
|
|
/* 33 / */ &&_SUBR_DIV,
|
|
/* 34 NEG */ &&_SUBR_NEG,
|
|
/* 35 \ */ &&_SUBR_QUO,
|
|
/* 36 MOD */ &&_SUBR_REM,
|
|
/* 37 ^ */ &&_SUBR_CODE,
|
|
/* 38 AND */ &&_SUBR_AND,
|
|
/* 39 OR */ &&_SUBR_OR,
|
|
/* 3A XOR */ &&_SUBR_XOR,
|
|
/* 3B NOT */ &&_SUBR_NOT,
|
|
/* 3C & */ &&_SUBR_CODE,
|
|
/* 3D LIKE */ &&_SUBR_CODE,
|
|
/* 3E &/ */ &&_SUBR_CODE,
|
|
/* 3F Is */ &&_SUBR_CODE,
|
|
/* 40 Left$ */ &&_SUBR_CODE,
|
|
/* 41 Mid$ */ &&_SUBR_CODE,
|
|
/* 42 Right$ */ &&_SUBR_CODE,
|
|
/* 43 Len */ &&_SUBR_LEN,
|
|
/* 44 Space$ */ &&_SUBR,
|
|
/* 45 String$ */ &&_SUBR,
|
|
/* 46 Trim$ */ &&_SUBR_CODE,
|
|
/* 47 UCase$ */ &&_SUBR_CODE,
|
|
/* 48 Oct$ */ &&_SUBR_CODE,
|
|
/* 49 Chr$ */ &&_SUBR,
|
|
/* 4A Asc */ &&_SUBR_CODE,
|
|
/* 4B InStr */ &&_SUBR_CODE,
|
|
/* 4C RInStr */ &&_SUBR_CODE,
|
|
/* 4D Subst$ */ &&_SUBR_CODE,
|
|
/* 4E Replace$ */ &&_SUBR_CODE,
|
|
/* 4F Split */ &&_SUBR_CODE,
|
|
/* 50 Scan */ &&_SUBR,
|
|
/* 51 Comp */ &&_SUBR_CODE,
|
|
/* 52 Conv */ &&_SUBR,
|
|
/* 53 DConv */ &&_SUBR_CODE,
|
|
/* 54 Abs */ &&_SUBR_CODE,
|
|
/* 55 Int */ &&_SUBR_CODE,
|
|
/* 56 Fix */ &&_SUBR_CODE,
|
|
/* 57 Sgn */ &&_SUBR_CODE,
|
|
/* 58 Frac... */ &&_SUBR_CODE,
|
|
/* 59 Pi */ &&_SUBR_CODE,
|
|
/* 5A Round */ &&_SUBR_CODE,
|
|
/* 5B Randomize */ &&_SUBR_CODE,
|
|
/* 5C Rnd */ &&_SUBR_CODE,
|
|
/* 5D Min */ &&_SUBR_CODE,
|
|
/* 5E Max */ &&_SUBR_CODE,
|
|
/* 5F IIf */ &&_SUBR_CODE,
|
|
/* 60 Choose */ &&_SUBR_CODE,
|
|
/* 61 Array */ &&_SUBR_CODE,
|
|
/* 62 ATan2... */ &&_SUBR_CODE,
|
|
/* 63 IsAscii... */ &&_SUBR_CODE,
|
|
/* 64 BClr... */ &&_SUBR_CODE,
|
|
/* 65 IsBoolean... */ &&_SUBR_CODE,
|
|
/* 66 TypeOf */ &&_SUBR_CODE,
|
|
/* 67 CBool... */ &&_SUBR_CONV,
|
|
/* 68 Bin$ */ &&_SUBR_CODE,
|
|
/* 69 Hex$ */ &&_SUBR_CODE,
|
|
/* 6A Val */ &&_SUBR,
|
|
/* 6B Str */ &&_SUBR,
|
|
/* 6C Format */ &&_SUBR_CODE,
|
|
/* 6D Timer */ &&_SUBR,
|
|
/* 6E Now */ &&_SUBR,
|
|
/* 6F Year... */ &&_SUBR_CODE,
|
|
/* 70 Week */ &&_SUBR_CODE,
|
|
/* 71 Date */ &&_SUBR_CODE,
|
|
/* 72 Time... */ &&_SUBR_CODE,
|
|
/* 73 DateAdd... */ &&_SUBR_CODE,
|
|
/* 74 Eval */ &&_SUBR_CODE,
|
|
/* 75 Error */ &&_SUBR,
|
|
/* 76 Debug */ &&_SUBR,
|
|
/* 77 Wait */ &&_SUBR_CODE,
|
|
/* 78 Open */ &&_SUBR_CODE,
|
|
/* 79 Close */ &&_SUBR,
|
|
/* 7A Input */ &&_SUBR_CODE,
|
|
/* 7B LineInput */ &&_SUBR,
|
|
/* 7C Print */ &&_SUBR_CODE,
|
|
/* 7D Read */ &&_SUBR_CODE,
|
|
/* 7E Write */ &&_SUBR_CODE,
|
|
/* 7F Flush */ &&_SUBR,
|
|
/* 80 Lock... */ &&_SUBR_CODE,
|
|
/* 81 InputFrom... */ &&_SUBR_CODE,
|
|
/* 82 Eof */ &&_SUBR_CODE,
|
|
/* 83 Lof */ &&_SUBR_CODE,
|
|
/* 84 Seek */ &&_SUBR_CODE,
|
|
/* 85 Kill */ &&_SUBR_CODE,
|
|
/* 86 Mkdir */ &&_SUBR_CODE,
|
|
/* 87 Rmdir */ &&_SUBR_CODE,
|
|
/* 88 Move */ &&_SUBR_CODE,
|
|
/* 89 Copy */ &&_SUBR_CODE,
|
|
/* 8A Link */ &&_SUBR_ISNAN,
|
|
/* 8B Exist */ &&_SUBR_CODE,
|
|
/* 8C Access */ &&_SUBR_CODE,
|
|
/* 8D Stat */ &&_SUBR_CODE,
|
|
/* 8E Dfree */ &&_SUBR,
|
|
/* 8F Temp$ */ &&_SUBR_CODE,
|
|
/* 90 IsDir */ &&_SUBR,
|
|
/* 91 Dir */ &&_SUBR_CODE,
|
|
/* 92 RDir */ &&_SUBR_CODE,
|
|
/* 93 Exec... */ &&_SUBR_CODE,
|
|
/* 94 Alloc */ &&_SUBR_CODE,
|
|
/* 95 Free */ &&_SUBR,
|
|
/* 96 Realloc */ &&_SUBR_CODE,
|
|
/* 97 StrPtr */ &&_SUBR_CODE,
|
|
/* 98 Sleep... */ &&_SUBR_CODE,
|
|
/* 99 VarPtr */ &&_SUBR_CODE,
|
|
/* 9A Collection */ &&_SUBR_CODE,
|
|
/* 9B Tr$ */ &&_SUBR,
|
|
/* 9C Quote$... */ &&_SUBR_CODE,
|
|
/* 9D Unquote$... */ &&_SUBR_CODE,
|
|
/* 9E MkInt$... */ &&_SUBR_CODE,
|
|
/* 9F Byte@... */ &&_SUBR_CODE,
|
|
/* A0 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A1 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A2 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A3 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A4 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A5 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A6 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A7 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A8 ADD QUICK */ &&_ADD_QUICK,
|
|
/* A9 ADD QUICK */ &&_ADD_QUICK,
|
|
/* AA ADD QUICK */ &&_ADD_QUICK,
|
|
/* AB ADD QUICK */ &&_ADD_QUICK,
|
|
/* AC ADD QUICK */ &&_ADD_QUICK,
|
|
/* AD ADD QUICK */ &&_ADD_QUICK,
|
|
/* AE ADD QUICK */ &&_ADD_QUICK,
|
|
/* AF ADD QUICK */ &&_ADD_QUICK,
|
|
/* B0 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B1 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B2 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B3 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B4 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B5 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B6 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B7 PUSH CLASS */ &&_PUSH_CLASS,
|
|
/* B8 PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* B9 PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* BA PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* BB PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* BC PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* BD PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* BE PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* BF PUSH FUNCTION */ &&_PUSH_FUNCTION,
|
|
/* C0 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C1 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C2 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C3 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C4 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C5 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C6 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C7 PUSH DYNAMIC */ &&_PUSH_DYNAMIC,
|
|
/* C8 PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* C9 PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* CA PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* CB PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* CC PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* CD PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* CE PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* CF PUSH STATIC */ &&_PUSH_STATIC,
|
|
/* D0 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D1 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D2 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D3 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D4 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D5 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D6 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D7 POP DYNAMIC */ &&_POP_DYNAMIC,
|
|
/* D8 POP STATIC */ &&_POP_STATIC,
|
|
/* D9 POP STATIC */ &&_POP_STATIC,
|
|
/* DA POP STATIC */ &&_POP_STATIC,
|
|
/* DB POP STATIC */ &&_POP_STATIC,
|
|
/* DC POP STATIC */ &&_POP_STATIC,
|
|
/* DD POP STATIC */ &&_POP_STATIC,
|
|
/* DE POP STATIC */ &&_POP_STATIC,
|
|
/* DF POP STATIC */ &&_POP_STATIC,
|
|
/* E0 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E1 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E2 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E3 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E4 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E5 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E6 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E7 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E8 PUSH CONST */ &&_PUSH_CONST,
|
|
/* E9 PUSH CONST */ &&_PUSH_CONST,
|
|
/* EA PUSH CONST */ &&_PUSH_CONST,
|
|
/* EB PUSH CONST */ &&_PUSH_CONST,
|
|
/* EC PUSH CONST */ &&_PUSH_CONST,
|
|
/* ED PUSH CONST */ &&_PUSH_CONST,
|
|
/* EE PUSH CONST */ &&_PUSH_CONST,
|
|
/* EF PUSH CONST */ &&_PUSH_CONST_EX,
|
|
/* F0 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F1 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F2 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F3 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F4 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F5 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F6 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F7 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F8 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* F9 PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* FA PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* FB PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* FC PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* FD PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* FE PUSH QUICK */ &&_PUSH_QUICK,
|
|
/* FF PUSH QUICK */ &&_PUSH_QUICK
|
|
};
|
|
|
|
CLASS *class = JOB->class;
|
|
TYPE type;
|
|
uint p = 0;
|
|
ushort code;
|
|
int index;
|
|
|
|
init();
|
|
|
|
//JIT_print(" JIT.debug(\"SP = %%p\\n\", SP);\n");
|
|
|
|
goto _MAIN;
|
|
|
|
_MAIN:
|
|
|
|
//JIT_print("__L%d:\n", p);
|
|
check_labels(p);
|
|
|
|
if (p >= (func->ncode - 1)) // ignore the last opcode which is RETURN
|
|
{
|
|
if (_stack_current)
|
|
THROW("Stack mismatch");
|
|
STR_free_later(NULL);
|
|
JIT_print("__RETURN:\n");
|
|
JIT_print(" SP = sp;\n");
|
|
return;
|
|
}
|
|
|
|
_pc = p;
|
|
code = func->code[p++];
|
|
goto *jump_table[code >> 8];
|
|
|
|
_PUSH_LOCAL:
|
|
|
|
push(func->local[func->nparam + GET_XX()].type, "l%d", GET_XX());
|
|
goto _MAIN;
|
|
|
|
_POP_LOCAL:
|
|
|
|
pop(func->local[func->nparam + GET_XX()].type, "l%d", GET_XX());
|
|
goto _MAIN;
|
|
|
|
_PUSH_PARAM:
|
|
|
|
index = func->nparam + GET_XX();
|
|
push(func->param[index].type, "p%d", index);
|
|
goto _MAIN;
|
|
|
|
_POP_PARAM:
|
|
|
|
index = func->nparam + GET_XX();
|
|
pop(func->param[index].type, "p%d", index);
|
|
goto _MAIN;
|
|
|
|
_PUSH_QUICK:
|
|
|
|
push(TYPE_make_simple(T_INTEGER), "%d", GET_XXX());
|
|
goto _MAIN;
|
|
|
|
_PUSH_SHORT:
|
|
|
|
push(TYPE_make_simple(T_INTEGER), "%d", (short)PC[0]);
|
|
p++;
|
|
goto _MAIN;
|
|
|
|
_PUSH_INTEGER:
|
|
|
|
push(TYPE_make_simple(T_INTEGER), "%d", PC[0] | ((uint)PC[1] << 16));
|
|
p += 2;
|
|
goto _MAIN;
|
|
|
|
_PUSH_STATIC:
|
|
|
|
type = class->stat[GET_7XX()].type;
|
|
if (TYPE_get_id(type) == T_OBJECT)
|
|
{
|
|
if (TYPE_get_value(type) < 0)
|
|
push(type, "GET_STATIC_o(%d, GB_T_OBJECT)", GET_7XX());
|
|
else
|
|
push(type, "GET_STATIC_o(%d, GET_CLASS(%d))", GET_7XX(), TYPE_get_value(type));
|
|
}
|
|
else
|
|
push(type, "GET_STATIC_%s(%d)", JIT_get_type(type), GET_7XX());
|
|
goto _MAIN;
|
|
|
|
_PUSH_DYNAMIC:
|
|
|
|
type = class->dyn[GET_7XX()].type;
|
|
push(type, "GET_DYNAMIC_%s(%d)", JIT_get_type(type), GET_7XX());
|
|
goto _MAIN;
|
|
|
|
_POP_STATIC:
|
|
|
|
type = class->stat[GET_7XX()].type;
|
|
_no_release = TRUE;
|
|
pop(type, "SET_STATIC_%s(%d, %%s)", JIT_get_type(type), GET_7XX());
|
|
_no_release = FALSE;
|
|
goto _MAIN;
|
|
|
|
_POP_DYNAMIC:
|
|
|
|
type = class->stat[GET_7XX()].type;
|
|
_no_release = TRUE;
|
|
pop(type, "SET_DYNAMIC_%s(%d, %%s)", JIT_get_type(type), GET_7XX());
|
|
_no_release = FALSE;
|
|
goto _MAIN;
|
|
|
|
_PUSH_MISC:
|
|
|
|
switch (GET_UX())
|
|
{
|
|
case 0:
|
|
push(TYPE_make_simple(T_OBJECT), "NULL");
|
|
break;
|
|
|
|
case 1:
|
|
push(TYPE_make_simple(T_VOID), "");
|
|
break;
|
|
|
|
case 2:
|
|
push(TYPE_make_simple(T_BOOLEAN), "1");
|
|
break;
|
|
|
|
case 3:
|
|
push(TYPE_make_simple(T_BOOLEAN), "0");
|
|
break;
|
|
|
|
default:
|
|
goto _ILLEGAL;
|
|
}
|
|
goto _MAIN;
|
|
|
|
_PUSH_CHAR:
|
|
|
|
push(TYPE_make_simple(T_CSTRING), "GET_CHAR(%d)", GET_UX());
|
|
goto _MAIN;
|
|
|
|
_POP_OPTIONAL:
|
|
|
|
check_stack(1);
|
|
if (TYPE_get_id(get_type(-1)) == T_VOID)
|
|
pop_stack(1);
|
|
else
|
|
{
|
|
index = func->nparam + GET_XX() - func->npmin;
|
|
JIT_print(" if (o%d & %d)\n ", index / 8, (1 << (index % 8)));
|
|
index = func->nparam + GET_XX();
|
|
pop(func->param[index].type, "p%d", index);
|
|
}
|
|
goto _MAIN;
|
|
|
|
_PUSH_CLASS:
|
|
|
|
index = GET_7XX();
|
|
type = TYPE_make(T_OBJECT, index, 0);
|
|
TYPE_set_id(&type, T_CLASS);
|
|
push(type, "GET_CLASS(%d)", index);
|
|
goto _MAIN;
|
|
|
|
_PUSH_FUNCTION:
|
|
|
|
_func_type = FUNCTION_PRIVATE;
|
|
_func_index = GET_7XX();
|
|
goto _MAIN;
|
|
|
|
_CALL:
|
|
|
|
push_call(code);
|
|
goto _MAIN;
|
|
|
|
_SUBR:
|
|
|
|
push_subr(code, "CALL_SUBR");
|
|
goto _MAIN;
|
|
|
|
_SUBR_CODE:
|
|
|
|
push_subr(code, "CALL_SUBR_CODE");
|
|
goto _MAIN;
|
|
|
|
_DROP:
|
|
|
|
pop(TYPE_make_simple(T_VOID), NULL);
|
|
goto _MAIN;
|
|
|
|
_NEW:
|
|
|
|
push_subr(code, "CALL_NEW");
|
|
goto _MAIN;
|
|
|
|
_RETURN:
|
|
|
|
switch(code & 0xFF)
|
|
{
|
|
case 0:
|
|
// TODO: Return from GoSub
|
|
JIT_print(" goto __RETURN;\n");
|
|
break;
|
|
|
|
case 1:
|
|
pop(func->type, "r");
|
|
JIT_print(" goto __RETURN;\n");
|
|
break;
|
|
|
|
case 2:
|
|
JIT_print(" goto __RETURN;\n");
|
|
break;
|
|
|
|
default:
|
|
goto _ILLEGAL;
|
|
}
|
|
goto _MAIN;
|
|
|
|
_GOSUB:
|
|
|
|
JIT_print(" PUSH_GOSUB();\n");
|
|
|
|
_JUMP:
|
|
|
|
JIT_print(" goto __L%d;\n", p + (signed short)PC[0] + 1);
|
|
p++;
|
|
goto _MAIN;
|
|
|
|
_JUMP_IF_TRUE:
|
|
|
|
JIT_print(" if (%s) goto __L%d;\n", peek(-1, TYPE_make_simple(T_BOOLEAN), NULL, NULL), p + (signed short)PC[0] + 1);
|
|
pop_stack(1);
|
|
goto _MAIN;
|
|
|
|
_JUMP_IF_FALSE:
|
|
|
|
JIT_print(" if (!(%s)) goto __L%d;\n", peek(-1, TYPE_make_simple(T_BOOLEAN), NULL, NULL), p + (signed short)PC[0] + 1);
|
|
pop_stack(1);
|
|
goto _MAIN;
|
|
|
|
_JUMP_FIRST:
|
|
|
|
index = PC[2] & 0xFF;
|
|
type = func->local[func->nparam + index].type;
|
|
pop(type, "const %s c%d", JIT_get_ctype(type), _ctrl_count);
|
|
JIT_print(" goto __L%ds;\n", p + 1);
|
|
|
|
goto _MAIN;
|
|
|
|
_JUMP_NEXT:
|
|
{
|
|
char *expr;
|
|
|
|
expr = peek(-1, type, NULL, NULL);
|
|
pop_stack(1);
|
|
|
|
JIT_print(" l%d += c%d;\n", index, _ctrl_count);
|
|
JIT_print("__L%ds:\n", p);
|
|
JIT_print(" if (((c%d > 0) && (l%d > %s)) || ((c%d < 0) && (l%d < %s))) goto __L%d;\n", _ctrl_count, index, expr, _ctrl_count, index, expr, p + (signed short)PC[0] + 1);
|
|
|
|
STR_free(expr);
|
|
_ctrl_count++;
|
|
|
|
p +=2;
|
|
goto _MAIN;
|
|
}
|
|
|
|
_PUSH_CONST:
|
|
|
|
push_constant(GET_UXX());
|
|
|
|
index = GET_UXX();
|
|
goto _MAIN;
|
|
|
|
_PUSH_CONST_EX:
|
|
|
|
push_constant(PC[0]);
|
|
p++;
|
|
goto _MAIN;
|
|
|
|
_PUSH_ARRAY:
|
|
|
|
push_array(code);
|
|
goto _MAIN;
|
|
|
|
_POP_ARRAY:
|
|
|
|
pop_array(code);
|
|
goto _MAIN;
|
|
|
|
_ADD_QUICK:
|
|
|
|
index = GET_XXX();
|
|
push(TYPE_make_simple(T_INTEGER), "%d", abs(index));
|
|
if (index < 0)
|
|
goto _SUBR_SUB;
|
|
|
|
_SUBR_ADD:
|
|
|
|
push_subr_add(code, "+", "|", TRUE);
|
|
goto _MAIN;
|
|
|
|
_SUBR_SUB:
|
|
|
|
push_subr_add(code, "-", "^", TRUE);
|
|
goto _MAIN;
|
|
|
|
_SUBR_MUL:
|
|
|
|
push_subr_add(code, "*", "&", FALSE);
|
|
goto _MAIN;
|
|
|
|
_SUBR_DIV:
|
|
|
|
push_subr_div(code);
|
|
goto _MAIN;
|
|
|
|
_SUBR_NEG:
|
|
|
|
push_subr_neg(code);
|
|
goto _MAIN;
|
|
|
|
_SUBR_AND:
|
|
|
|
push_subr_and(code, "&");
|
|
goto _MAIN;
|
|
|
|
_SUBR_OR:
|
|
|
|
push_subr_and(code, "|");
|
|
goto _MAIN;
|
|
|
|
_SUBR_XOR:
|
|
|
|
push_subr_and(code, "^");
|
|
goto _MAIN;
|
|
|
|
_SUBR_NOT:
|
|
|
|
push_subr_not(code);
|
|
goto _MAIN;
|
|
|
|
_SUBR_COMPE:
|
|
_SUBR_COMPN:
|
|
_SUBR_COMPGT:
|
|
_SUBR_COMPLE:
|
|
_SUBR_COMPLT:
|
|
_SUBR_COMPGE:
|
|
|
|
push_subr_comp(code);
|
|
goto _MAIN;
|
|
|
|
_SUBR_ISNAN:
|
|
|
|
push_subr_isnan(code);
|
|
goto _MAIN;
|
|
|
|
_SUBR_CONV:
|
|
|
|
push_subr_conv(code);
|
|
goto _MAIN;
|
|
|
|
_SUBR_LEN:
|
|
|
|
push_subr_len(code);
|
|
goto _MAIN;
|
|
|
|
_BREAK:
|
|
|
|
goto _MAIN;
|
|
|
|
_PUSH_UNKNOWN:
|
|
_PUSH_EXTERN:
|
|
_BYREF:
|
|
_PUSH_EVENT:
|
|
_QUIT:
|
|
_POP_UNKNOWN:
|
|
_POP_CTRL:
|
|
_PUSH_ME:
|
|
_TRY:
|
|
_END_TRY:
|
|
_CATCH:
|
|
_DUP:
|
|
_CALL_QUICK:
|
|
_CALL_SLOW:
|
|
_ON_GOTO_GOSUB:
|
|
_ENUM_FIRST:
|
|
_ENUM_NEXT:
|
|
_SUBR_QUO:
|
|
_SUBR_REM:
|
|
_ILLEGAL:
|
|
{
|
|
char opcode[8];
|
|
sprintf(opcode, "%04X", code);
|
|
THROW("Unsupported opcode &1", opcode);
|
|
}
|
|
}
|
|
|