gambas-source-code/main/lib/jit/jit.c
Benoît Minisini 8a1d604e32 Support for computed Goto or GoSub in JIT compiler.
[INTERPRETER]
* BUG: Correctly initialize functions without computed Goto or GoSub.

[GB.JIT]
* NEW: Support for computed Goto or GoSub.
2023-10-06 03:31:20 +02:00

571 lines
11 KiB
C

/***************************************************************************
jit.c
(c) 2000-2018 Benoît Minisini <benoit.minisini@gambas-basic.org>
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 __JIT_C
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "gb_str.h"
#include "jit.h"
typedef
struct {
const char *name;
char type;
}
CLASS_TYPE;
CLASS *JIT_class;
char *JIT_prefix;
bool JIT_last_print_is_label;
static char *_buffer = NULL;
static char *_buffer_decl = NULL;
static char *_buffer_body = NULL;
static bool _decl_null_string = FALSE;
static bool _decl_null_date = FALSE;
static bool _decl_null_object = FALSE;
static bool _decl_null_variant = FALSE;
/*static const CLASS_TYPE _class_type[] = {
{ "Boolean[]", T_BOOLEAN },
{ "Byte[]", T_BYTE },
{ "Short[]", T_SHORT },
{ "Integer[]", T_INTEGER },
{ "Long[]", T_LONG },
{ "Single[]", T_SINGLE },
{ "Float[]", T_FLOAT },
{ "Date[]", T_DATE },
{ "String[]", T_STRING },
{ "Pointer[]", T_POINTER },
{ "Object[]", T_OBJECT },
{ "Variant[]", T_VARIANT },
{ NULL, 0 }
};*/
static const char *_type_name[] =
{
"V" , "b", "c", "h", "i", "l", "g", "f",
"d", "s", "t", "p", "v", "F", "C", "n",
"o", "u"
};
static const char *_gtype_name[] =
{
"GB_T_VOID" , "GB_T_BOOLEAN", "GB_T_BYTE", "GB_T_SHORT", "GB_T_INTEGER", "GB_T_LONG", "GB_T_SINGLE", "GB_T_FLOAT",
"GB_T_DATE", "GB_T_STRING", "GB_T_CSTRING", "GB_T_POINTER", "GB_T_VARIANT", "?", "GB_T_CLASS", "?",
"GB_T_OBJECT"
};
static const char *_ctype_name[] =
{
"void" , "bool", "uchar", "short", "int", "int64_t", "float", "double",
"GB_DATE", "GB_STRING", "GB_STRING", "intptr_t", "GB_VARIANT", "?", "void *", "?",
"GB_OBJECT", "GB_VALUE", "?"
};
const char *JIT_get_type(TYPE type)
{
return _type_name[TYPEID(type)];
}
const char *JIT_get_gtype(TYPE type)
{
return _gtype_name[TYPEID(type)];
}
const char *JIT_get_ctype(TYPE type)
{
return _ctype_name[TYPEID(type)];
}
TYPE JIT_ctype_to_type(CLASS *class, CTYPE ctype)
{
if (ctype.id == T_OBJECT && ctype.value >= 0)
return (TYPE)(class->load->class_ref[ctype.value]);
else if (ctype.id == TC_ARRAY)
{
CLASS_ARRAY *desc = class->load->array[ctype.value];
return (TYPE)JIT.get_array_class(class, *(JIT_CTYPE *)&desc->ctype);
}
else if (ctype.id == TC_STRUCT)
return (TYPE)(class->load->class_ref[ctype.value]);
else
return (TYPE)(ctype.id);
}
static void JIT_begin(void)
{
char *p;
JIT_prefix = STR_lower(JIT_class->name);
p = JIT_prefix;
while (*p)
{
if (*p == ':')
*p = '$';
p++;
}
_buffer = NULL;
_buffer_decl = NULL;
JIT_print("\n//////// %s\n\n", JIT_class->name);
}
static char *JIT_end(void)
{
char *result = _buffer;
STR_free(JIT_prefix);
_buffer = NULL;
GB.FreeStringLater(result);
return result;
}
static void declare_implementation(FUNCTION *func, int index)
{
int i;
int nopt;
int opt;
const char *vol = func->error ? "volatile " : "";
JIT_print("static %s jit_%s_%d_(", JIT_get_ctype(func->type), JIT_prefix, index);
for (i = 0; i < func->npmin; i++)
{
if (i) JIT_print(",");
JIT_print("%s%s p%d", vol, JIT_get_ctype(func->param[i].type), i);
}
if (i < func->n_param)
{
opt = nopt = 0;
for (; i < func->n_param; i++)
{
if (i) JIT_print(",");
if (nopt == 0)
{
JIT_print("uchar o%d,", opt);
opt++;
}
JIT_print("%s%s p%d", vol, JIT_get_ctype(func->param[i].type), i);
nopt++;
if (nopt >= 8)
nopt = 0;
}
}
if (func->vararg)
{
if (func->n_param)
JIT_print(",");
JIT_print("uchar nv,GB_VALUE *v");
}
JIT_print(")");
}
void JIT_declare_func(FUNCTION *func, int index)
{
JIT_print("void jit_%s_%d(uchar n);\n", JIT_prefix, index);
declare_implementation(func, index);
JIT_print(";\n");
}
const char *JIT_get_default_value(TYPE type)
{
switch(TYPEID(type))
{
case T_DATE:
if (!_decl_null_date)
{
JIT_print_decl(" const GB_DATE null_date = {GB_T_DATE};\n");
_decl_null_date = TRUE;
}
return "null_date";
case T_STRING:
if (!_decl_null_string)
{
JIT_print_decl(" const GB_STRING null_string = {GB_T_STRING};\n");
_decl_null_string = TRUE;
}
return "null_string";
case T_OBJECT:
if (!_decl_null_object)
{
JIT_print_decl(" const GB_OBJECT null_object = {GB_T_OBJECT};\n");
_decl_null_object = TRUE;
}
return "null_object";
case T_VARIANT:
if (!_decl_null_variant)
{
JIT_print_decl(" const GB_VARIANT null_variant = {GB_T_VARIANT,{GB_T_NULL}};\n");
_decl_null_variant = TRUE;
}
return "null_variant";
default:
return "0";
}
}
static bool JIT_translate_func(FUNCTION *func, int index)
{
int i;
TYPE type;
int nopt;
const char *def;
const char *vol = func->error ? "volatile " : "";
if (func->debug)
JIT_section(func->debug->name);
JIT_print("void jit_%s_%d(uchar n)\n{\n", JIT_prefix, index);
if (func->n_param || func->vararg)
JIT_print(" VALUE *sp = *((VALUE **)%p);\n", JIT.sp);
JIT_print(" ");
if (!TYPE_is_void(func->type))
JIT_print("RETURN_%s(", JIT_get_type(func->type));
JIT_print("jit_%s_%d_(", JIT_prefix, index);
for (i = 0; i < func->npmin; i++)
{
if (i) JIT_print(",");
type = func->param[i].type;
if (TYPE_is_pure_object(type))
JIT_print("PARAM_O(%d, CLASS(%p))", i, type);
else
JIT_print("PARAM_%s(%d)", JIT_get_type(type), i);
}
if (i < func->n_param)
{
nopt = 0;
for (; i < func->n_param; i++)
{
if (i) JIT_print(",");
if (nopt == 0)
JIT_print("OPT(%d,%d),", i, Min(func->n_param, i + 8) - i);
type = func->param[i].type;
if (TYPE_is_pure_object(type))
JIT_print("PARAM_OPT_O(%d, CLASS(%p))", i, type);
else
JIT_print("PARAM_OPT_%s(%d)", JIT_get_type(type), i);
nopt++;
if (nopt >= 8)
nopt = 0;
}
}
if (func->vararg)
{
if (func->n_param)
JIT_print(",");
JIT_print("n - %d,&sp[-n+%d]", i, i);
}
if (!TYPE_is_void(func->type))
JIT_print(")");
JIT_print(");\n");
JIT_print("}\n\n");
declare_implementation(func, index);
JIT_print("\n{\n");
_buffer_decl = NULL;
_buffer_body = NULL;
_decl_null_date = FALSE;
_decl_null_string = FALSE;
_decl_null_object = FALSE;
_decl_null_variant = FALSE;
for (i = -1; i < func->n_local; i++)
{
if (i < 0)
{
if (TYPE_is_void(func->type))
continue;
type = func->type;
def = JIT_get_default_value(type);
JIT_print_decl(" %s r = ", JIT_get_ctype(type));
}
else
{
type = JIT_ctype_to_type(JIT_class, func->local[i].type);
def = JIT_get_default_value(type);
JIT_print_decl(" %s%s l%d = ", vol, JIT_get_ctype(type), i);
}
JIT_print_decl(def);
JIT_print_decl(";\n");
}
for (i = 0; i < func->n_param; i++)
{
type = func->param[i].type;
switch(TYPEID(type))
{
case T_STRING: case T_OBJECT: case T_VARIANT:
JIT_print_body(" BORROW_%s(p%d);\n", JIT_get_type(type), i);
}
}
if (JIT_translate_body(func, index))
return TRUE;
if (!TYPE_is_void(func->type))
{
switch(TYPEID(func->type))
{
case T_STRING:
case T_OBJECT:
case T_VARIANT:
JIT_print_body(" JIT.unborrow((GB_VALUE *)&r);\n");
break;
}
JIT_print_body(" return r;\n");
}
else
JIT_print_body(" return;\n");
_buffer = GB.AddString(_buffer, _buffer_decl, GB.StringLength(_buffer_decl));
JIT_print("\n");
_buffer = GB.AddString(_buffer, _buffer_body, GB.StringLength(_buffer_body));
GB.FreeString(&_buffer_decl);
GB.FreeString(&_buffer_body);
JIT_print("}\n");
return FALSE;
}
void JIT_vprint(char **buffer, const char *fmt, va_list args)
{
int len, add;
va_list copy;
va_copy(copy, args);
add = vsnprintf(NULL, 0, fmt, copy);
va_end(copy);
len = GB.StringLength(*buffer);
*buffer = GB.ExtendString(*buffer, len + add);
vsprintf(*buffer + len, fmt, args);
JIT_last_print_is_label = (strncmp(fmt, "__L", 3) == 0);
}
void JIT_print(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
JIT_vprint(&_buffer, fmt, args);
va_end(args);
}
void JIT_print_decl(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
JIT_vprint(&_buffer_decl, fmt, args);
va_end(args);
}
void JIT_print_body(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
JIT_vprint(&_buffer_body, fmt, args);
va_end(args);
}
void JIT_section(const char *str)
{
JIT_print("\n// %s\n\n", str);
}
void JIT_declare(TYPE type, const char *fmt, ...)
{
va_list args;
const char *def;
def = JIT_get_default_value(type);
JIT_print_decl(" %s ", JIT_get_ctype(type));
va_start(args, fmt);
JIT_vprint(&_buffer_decl, fmt, args);
va_end(args);
switch (TYPEID(type))
{
case T_STRING:
case T_OBJECT:
case T_VARIANT:
JIT_print_decl(" = %s", def);
break;
}
JIT_print_decl(";\n");
}
char *JIT_translate(const char *name, const char *from)
{
CLASS *class;
int i;
FUNCTION *func;
JIT_class = class = (CLASS *)GB.LoadClassFrom(name, from);
JIT_begin();
for (i = 0; i < class->load->n_func; i++)
{
func = &class->load->func[i];
if (!func->fast)
continue;
JIT_declare_func(func, i);
}
for (i = 0; i < class->load->n_func; i++)
{
func = &class->load->func[i];
if (!func->fast)
continue;
JIT_last_print_is_label = FALSE;
if (JIT_translate_func(func, i))
return NULL;
}
return JIT_end();
}
void JIT_panic(const char *fmt, ...)
{
va_list args;
fprintf(stderr, "gb.jit: panic: ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fputc('\n', stderr);
va_end(args);
fputc('\n', stderr);
fputs(_buffer, stderr);
if (_buffer_decl) fputs(_buffer_decl, stderr);
if (_buffer_body) fputs(_buffer_body, stderr);
fputc('\n', stderr);
abort();
}
int JIT_get_code_size(FUNCTION *func)
{
ushort *code = func->code;
if (func->n_label)
code -= func->n_label + 1;
int size = ((int *)code)[-1] / sizeof(ushort);
if (code[size - 1] == 0)
size--;
return size;
}
void JIT_load_class_without_init(CLASS *class)
{
void *save_cp;
if (class->loaded)
return;
if (class->ready || class->in_load)
return;
save_cp = JIT.exec->cp;
JIT.exec->cp = JIT_class;
//fprintf(stderr, "gb.jit: load class: %s (%p)\n", class->name, class);
JIT.load_class_without_init(class);
JIT.exec->cp = save_cp;
}
int JIT_find_symbol(CLASS *class, const char *name)
{
JIT_load_class_without_init(class);
if (class->loaded)
return JIT.find_symbol(class->table, class->sort, class->n_desc, sizeof(CLASS_DESC_SYMBOL), TF_IGNORE_CASE, name, strlen(name), NULL);
else
return NO_SYMBOL;
}