db50637bf4
[INTERPRETER] * BUG: Static class initializer are now always correctly run in the context of their component.
1358 lines
31 KiB
C
1358 lines
31 KiB
C
/***************************************************************************
|
|
|
|
gbx_class_load.c
|
|
|
|
(c) 2000-2017 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 __GBX_CLASS_LOAD_C
|
|
|
|
#include "gb_common.h"
|
|
#include "gb_common_case.h"
|
|
#include "gb_common_buffer.h"
|
|
#include "gb_common_swap.h"
|
|
#include "gb_alloc.h"
|
|
#include "gb_error.h"
|
|
#include "gb_limit.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "gb_buffer.h"
|
|
#include "gb_file.h"
|
|
#include "gbx_type.h"
|
|
#include "gbx_exec.h"
|
|
#include "gbx_debug.h"
|
|
#include "gb_magic.h"
|
|
#include "gbx_stream.h"
|
|
#include "gbx_c_array.h"
|
|
#include "gbx_string.h"
|
|
#include "gbx_object.h"
|
|
#include "gbx_variant.h"
|
|
#include "gbx_number.h"
|
|
#include "gbx_struct.h"
|
|
#include "gbx_jit.h"
|
|
|
|
#include "gambas.h"
|
|
|
|
#include "gbx_class.h"
|
|
|
|
//#define DEBUG DEBUG
|
|
//#define DEBUG_LOAD 1
|
|
//#define DEBUG_STRUCT 1
|
|
|
|
static bool _load_without_init = FALSE;
|
|
static const char *_class_name;
|
|
static bool _swap;
|
|
static bool _last_ctype_is_static;
|
|
|
|
#define _b "\x1"
|
|
#define _s "\x2"
|
|
#define _i "\x3"
|
|
#define _p "\x4"
|
|
#define _c "\x5"
|
|
#define _t "\x6"
|
|
|
|
#ifdef DEBUG
|
|
static CLASS *Class;
|
|
static int NSection;
|
|
#endif
|
|
|
|
static void SWAP_type(CTYPE *p)
|
|
{
|
|
SWAP_short(&p->value);
|
|
}
|
|
|
|
|
|
static int align_pos(int pos, int size)
|
|
{
|
|
switch (size)
|
|
{
|
|
case 1:
|
|
return pos;
|
|
case 2:
|
|
return (pos + 1) & ~1;
|
|
#ifndef OS_64BITS
|
|
case 4:
|
|
default:
|
|
return (pos + 3) & ~3;
|
|
#else
|
|
case 4:
|
|
return (pos + 3) & ~3;
|
|
case 8:
|
|
default:
|
|
return (pos + 7) & ~7;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
int CLASS_sizeof_ctype(CLASS *class, CTYPE ctype)
|
|
{
|
|
size_t size;
|
|
|
|
if (ctype.id == TC_ARRAY)
|
|
{
|
|
CLASS_ARRAY *array = class->load->array[ctype.value];
|
|
size = CARRAY_get_static_size(class, array);
|
|
return (size + 3) & ~3;
|
|
}
|
|
else if (ctype.id == TC_STRUCT)
|
|
{
|
|
return CSTRUCT_get_size(class->load->class_ref[ctype.value]);
|
|
}
|
|
else
|
|
return TYPE_sizeof_memory(ctype.id);
|
|
}
|
|
|
|
TYPE CLASS_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)
|
|
return (TYPE)CARRAY_get_array_class(class, class->load->array[ctype.value]->ctype);
|
|
else if (ctype.id == TC_STRUCT)
|
|
return (TYPE)(class->load->class_ref[ctype.value]);
|
|
else
|
|
return (TYPE)(ctype.id);
|
|
}
|
|
|
|
|
|
static void conv_ctype(CTYPE *ctype)
|
|
{
|
|
//if (ctype->id == TC_POINTER)
|
|
// ctype->id = T_POINTER;
|
|
}
|
|
|
|
|
|
static void conv_type(CLASS *class, void *ptype)
|
|
{
|
|
CTYPE ctype = *(CTYPE *)ptype;
|
|
|
|
if (_swap)
|
|
{
|
|
SWAP_int((int *)&ctype);
|
|
SWAP_type(&ctype);
|
|
}
|
|
|
|
_last_ctype_is_static = CTYPE_is_static(ctype);
|
|
*((TYPE *)ptype) = CLASS_ctype_to_type(class, ctype);
|
|
}
|
|
|
|
|
|
static void conv_type_simple(CLASS *class, int *ptype)
|
|
{
|
|
CTYPE ctype = *(CTYPE *)ptype;
|
|
|
|
if (_swap)
|
|
SWAP_int((int *)&ctype);
|
|
|
|
*ptype = ctype.id;
|
|
}
|
|
|
|
|
|
static void check_version(CLASS *class, int loaded)
|
|
{
|
|
if (loaded > GAMBAS_PCODE_VERSION)
|
|
THROW_CLASS(class, "Bytecode too recent. Please upgrade Gambas.", "");
|
|
if (loaded < GAMBAS_PCODE_VERSION_MIN)
|
|
THROW_CLASS(class, "Bytecode too old. Please recompile the project.", "");
|
|
}
|
|
|
|
|
|
static char *get_section(char *sec_name, char **section, short *pcount, const char *desc)
|
|
{
|
|
static void *jump_swap[] = { &&__SWAP_END, &&__SWAP_BYTE, &&__SWAP_SHORT, &&__SWAP_INT, &&__SWAP_POINTER, &&__SWAP_CTYPE, &&__SWAP_TYPE };
|
|
static size_t sizeof_32[] = { 0, 1, 2, 4, 4, 4, 4 };
|
|
#ifdef OS_64BITS
|
|
static void *jump_trans[] = { &&__TRANS_END, &&__TRANS_BYTE, &&__TRANS_SHORT, &&__TRANS_INT, &&__TRANS_POINTER, &&__TRANS_CTYPE, &&__TRANS_TYPE };
|
|
static size_t sizeof_64[] = { 0, 1, 2, 4, 8, 4, 8 };
|
|
#endif
|
|
|
|
char *current = *section + sizeof(int);
|
|
int section_size = *((int *)(*section));
|
|
int i;
|
|
char *p;
|
|
const char *pdesc;
|
|
short size;
|
|
size_t size_one = 0;
|
|
#ifdef OS_64BITS
|
|
size_t size_one_64 = 0;
|
|
char *alloc = NULL;
|
|
char *pa = NULL;
|
|
#endif
|
|
|
|
if (_swap)
|
|
SWAP_int(§ion_size);
|
|
|
|
#ifdef DEBUG
|
|
NSection++;
|
|
fprintf(stderr, "Section #%d %s %08lX %d %d\n", NSection + 1, sec_name, (int)(current - (char *)Class->data), (int)size_one, (int)section_size);
|
|
#endif
|
|
|
|
*section += section_size + sizeof(int);
|
|
|
|
if (desc)
|
|
{
|
|
pdesc = desc;
|
|
while (*pdesc)
|
|
{
|
|
size_one += sizeof_32[(int)*pdesc];
|
|
#ifdef OS_64BITS
|
|
size_one_64 += sizeof_64[(int)*pdesc];
|
|
#endif
|
|
pdesc++;
|
|
}
|
|
|
|
if (section_size % size_one)
|
|
THROW(E_CLASS, _class_name, "Bad format in section: ", sec_name);
|
|
|
|
size = section_size / size_one;
|
|
if (pcount) *pcount = size;
|
|
if (!size)
|
|
return NULL;
|
|
|
|
if (_swap)
|
|
{
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
p = current + i * size_one;
|
|
pdesc = desc;
|
|
|
|
__SWAP_NEXT:
|
|
goto *jump_swap[(int)(*pdesc++)];
|
|
|
|
__SWAP_BYTE:
|
|
p++;
|
|
goto __SWAP_NEXT;
|
|
|
|
__SWAP_SHORT:
|
|
SWAP_short((short *)p);
|
|
p += sizeof(short);
|
|
goto __SWAP_NEXT;
|
|
|
|
__SWAP_INT:
|
|
__SWAP_POINTER:
|
|
SWAP_int((int *)p);
|
|
p += sizeof(int);
|
|
goto __SWAP_NEXT;
|
|
|
|
__SWAP_CTYPE:
|
|
__SWAP_TYPE:
|
|
SWAP_type((CTYPE *)p);
|
|
p += sizeof(CTYPE);
|
|
goto __SWAP_NEXT;
|
|
|
|
__SWAP_END:
|
|
continue;
|
|
}
|
|
}
|
|
|
|
#ifdef OS_64BITS
|
|
|
|
if (size_one_64 != size_one)
|
|
{
|
|
ALLOC(&alloc, size_one_64 * size);
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
p = current + i * size_one;
|
|
pa = alloc + i * size_one_64;
|
|
pdesc = desc;
|
|
|
|
__TRANS_NEXT:
|
|
goto *jump_trans[(int)(*pdesc++)];
|
|
|
|
__TRANS_BYTE:
|
|
*pa++ = *p++;
|
|
goto __TRANS_NEXT;
|
|
|
|
__TRANS_SHORT:
|
|
*((short *)pa) = *((short *)p);
|
|
pa += sizeof(short);
|
|
p += sizeof(short);
|
|
goto __TRANS_NEXT;
|
|
|
|
__TRANS_INT:
|
|
__TRANS_CTYPE:
|
|
*((int *)pa) = *((int *)p);
|
|
pa += sizeof(int);
|
|
p += sizeof(int);
|
|
goto __TRANS_NEXT;
|
|
|
|
__TRANS_TYPE:
|
|
*((int *)pa) = *((int *)p);
|
|
pa += sizeof(int);
|
|
p += sizeof(int);
|
|
*((int *)pa) = 0;
|
|
pa += sizeof(int);
|
|
goto __TRANS_NEXT;
|
|
|
|
__TRANS_POINTER:
|
|
*((int64_t *)pa) = *((int *)p);
|
|
pa += sizeof(int64_t);
|
|
p += sizeof(int);
|
|
goto __TRANS_NEXT;
|
|
|
|
__TRANS_END:
|
|
continue;
|
|
}
|
|
|
|
return alloc;
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
#define RELOCATE(_ptr) (_ptr = (char *)&class->string[(int)(intptr_t)(_ptr)])
|
|
|
|
static void load_structure(CLASS *class, int *structure, int nfield)
|
|
{
|
|
char *name;
|
|
char *field;
|
|
CLASS *sclass;
|
|
int i, pos, size, len;
|
|
CTYPE ctype;
|
|
CLASS_DESC *desc;
|
|
CLASS_VAR *var;
|
|
GLOBAL_SYMBOL *global = NULL;
|
|
|
|
name = (char *)(intptr_t)(*structure++);
|
|
RELOCATE(name);
|
|
#if DEBUG_STRUCT
|
|
fprintf(stderr, "Loading structure %s\n", name);
|
|
#endif
|
|
|
|
if (class->global)
|
|
sclass = CLASS_find_global(name);
|
|
else
|
|
sclass = CLASS_find(name);
|
|
|
|
if (CLASS_is_loaded(sclass))
|
|
{
|
|
if (!sclass->is_struct)
|
|
THROW_CLASS(class, "Class already exists: ", name);
|
|
|
|
// Check compatibility with previous declaration
|
|
|
|
if (sclass->load->n_dyn != nfield)
|
|
goto __MISMATCH;
|
|
|
|
desc = (CLASS_DESC *)sclass->data;
|
|
|
|
for (i = 0; i < nfield; i++)
|
|
{
|
|
field = (char *)(intptr_t)(*structure++);
|
|
RELOCATE(field);
|
|
len = strlen(field);
|
|
ctype = *((CTYPE *)structure);
|
|
structure++;
|
|
|
|
if (CLASS_ctype_to_type(class, ctype) != desc[i].variable.type)
|
|
goto __MISMATCH;
|
|
|
|
if (TABLE_compare_ignore_case_len(field, strlen(field), sclass->table[i].name, sclass->table[i].len))
|
|
goto __MISMATCH;
|
|
}
|
|
|
|
// OK, they are the same!
|
|
return;
|
|
}
|
|
|
|
sclass->swap = class->swap;
|
|
sclass->component = class->component;
|
|
sclass->debug = class->debug;
|
|
|
|
ALLOC_ZERO(&sclass->load, sizeof(CLASS_LOAD));
|
|
|
|
ALLOC(&var, sizeof(CLASS_VAR) * nfield);
|
|
sclass->load->dyn = var;
|
|
sclass->load->n_dyn = nfield;
|
|
sclass->load->class_ref = class->load->class_ref;
|
|
sclass->load->array = class->load->array;
|
|
|
|
if (sclass->debug)
|
|
{
|
|
ALLOC(&global, sizeof(GLOBAL_SYMBOL) * nfield);
|
|
sclass->load->global = global;
|
|
sclass->load->n_global = nfield;
|
|
}
|
|
|
|
sclass->n_desc = nfield;
|
|
ALLOC(&sclass->table, sizeof(CLASS_DESC_SYMBOL) * nfield);
|
|
ALLOC(&desc, sizeof(CLASS_DESC) * nfield);
|
|
sclass->data = (char *)desc;
|
|
|
|
pos = 0; //sizeof(CSTRUCT);
|
|
|
|
for (i = 0; i < nfield; i++)
|
|
{
|
|
field = (char *)(intptr_t)(*structure++);
|
|
RELOCATE(field);
|
|
len = strlen(field);
|
|
ctype = *((CTYPE *)structure);
|
|
structure++;
|
|
|
|
size = CLASS_sizeof_ctype(class, ctype);
|
|
pos = align_pos(pos, size);
|
|
|
|
desc[i].variable.name = "f";
|
|
desc[i].variable.type = CLASS_ctype_to_type(class, ctype);
|
|
desc[i].variable.ctype = ctype;
|
|
desc[i].variable.offset = pos; // This the position relative to the data, NOT the object!
|
|
desc[i].variable.class = sclass;
|
|
|
|
var[i].type = ctype;
|
|
var[i].pos = pos;
|
|
|
|
if (sclass->debug)
|
|
{
|
|
global[i].sym.name = field;
|
|
global[i].sym.len = len;
|
|
global[i].ctype = ctype;
|
|
global[i].value = i;
|
|
}
|
|
|
|
#if DEBUG_STRUCT
|
|
fprintf(stderr, " %d: %s As %s (%d) pos = %d\n", i, field, TYPE_get_name(desc[i].variable.type), CLASS_sizeof_ctype(class, ctype), pos);
|
|
#endif
|
|
|
|
sclass->table[i].desc = &desc[i];
|
|
sclass->table[i].name = field;
|
|
sclass->table[i].len = len;
|
|
|
|
pos += size; //sizeof_ctype(class, var->type);
|
|
}
|
|
|
|
#ifdef OS_64BITS
|
|
size = align_pos(pos, 8);
|
|
#else
|
|
size = align_pos(pos, 4);
|
|
#endif
|
|
|
|
size += sizeof(CSTRUCT);
|
|
|
|
#if DEBUG_STRUCT
|
|
fprintf(stderr, " --> size = %d\n", size);
|
|
#endif
|
|
|
|
CLASS_calc_info(sclass, 0, size, TRUE, 0);
|
|
|
|
CLASS_sort(sclass);
|
|
|
|
if (sclass->debug)
|
|
sclass->load->sort = sclass->sort;
|
|
|
|
CLASS_search_special(sclass);
|
|
/*for (i = 0; i < MAX_SPEC; i++)
|
|
sclass->special[i] = NO_SYMBOL;*/
|
|
|
|
sclass->is_struct = TRUE;
|
|
|
|
sclass->loaded = TRUE;
|
|
sclass->ready = TRUE;
|
|
return;
|
|
|
|
__MISMATCH:
|
|
|
|
THROW_CLASS(class, "Structure is declared elsewhere differently: ", CLASS_get_name(sclass));
|
|
}
|
|
|
|
|
|
static void load_and_relocate(CLASS *class, int len_data, CLASS_DESC **pstart, int *pndesc)
|
|
{
|
|
char *section;
|
|
CLASS_INFO *info;
|
|
CLASS_HEADER *header;
|
|
CLASS_DESC *start;
|
|
CLASS_PARAM *local;
|
|
CLASS_EVENT *event;
|
|
CLASS_EXTERN *ext;
|
|
CLASS_VAR *var;
|
|
FUNCTION *func;
|
|
FUNC_DEBUG *debug;
|
|
int i, j, pos;
|
|
int offset;
|
|
short n_desc, n_class_ref, n_unknown, n_array, n_struct;
|
|
CLASS_STRUCT *structure = NULL;
|
|
int size;
|
|
char *name;
|
|
int len;
|
|
uchar flag;
|
|
|
|
ALLOC_ZERO(&class->load, sizeof(CLASS_LOAD));
|
|
|
|
/* header */
|
|
|
|
section = class->data;
|
|
|
|
header = (CLASS_HEADER *)section;
|
|
section += sizeof(CLASS_HEADER);
|
|
|
|
class->swap = header->endian != OUTPUT_ENDIAN;
|
|
_swap = class->swap;
|
|
if (_swap)
|
|
fprintf(stderr, "Swapping class %s\n", class->name);
|
|
|
|
if (_swap)
|
|
{
|
|
SWAP_int((int *)&header->magic);
|
|
SWAP_int((int *)&header->version);
|
|
SWAP_int((int *)&header->flag);
|
|
}
|
|
|
|
if (header->magic != OUTPUT_MAGIC)
|
|
{
|
|
int fd;
|
|
|
|
fd = open("/tmp/gambas-bad-header.dump", O_CREAT | O_WRONLY, 0666);
|
|
if (fd >= 0)
|
|
{
|
|
if (write(fd, class->data, len_data) != len_data)
|
|
fprintf(stderr, "Cannot dump bad class file.\n");
|
|
else
|
|
fprintf(stderr, "Bad class file dumped at /tmp/gambas-bad-header.dump\n");
|
|
close(fd);
|
|
}
|
|
|
|
THROW_CLASS(class, "Bad header", "");
|
|
}
|
|
|
|
check_version(class, header->version);
|
|
|
|
class->debug = header->flag & CF_DEBUG;
|
|
|
|
info = (CLASS_INFO *)get_section("info", §ion, NULL, _s _s _i _i _s _s );
|
|
#ifdef OS_64BITS
|
|
class->load->desc =
|
|
#endif
|
|
start = (CLASS_DESC *)get_section("description", §ion, &n_desc, _p _t _p _p _p _p );
|
|
class->load->cst = (CLASS_CONST *)get_section("constant", §ion, &class->load->n_cst, _i _p _i ); // A special process is needed later
|
|
class->load->class_ref = (CLASS **)get_section("reference", §ion, &n_class_ref, _p );
|
|
class->load->unknown = (char **)get_section("unknown", §ion, &n_unknown, _p );
|
|
class->load->stat = (CLASS_VAR *)get_section("static", §ion, &class->load->n_stat, _c _i );
|
|
class->load->dyn = (CLASS_VAR *)get_section("dynamic", §ion, &class->load->n_dyn, _c _i );
|
|
class->load->event = (CLASS_EVENT *)get_section("event", §ion, &class->n_event, _t _s _s _p _p );
|
|
class->load->ext = (CLASS_EXTERN *)get_section("extern", §ion, &class->load->n_ext, _t _s _s _p _p _p );
|
|
class->load->func = (FUNCTION *)get_section("function", §ion, &class->load->n_func, _t _b _b _b _b _s _s _s _s _p _p _p _p );
|
|
#ifdef OS_64BITS
|
|
class->load->local =
|
|
#endif
|
|
local = (CLASS_PARAM *)get_section("local", §ion, NULL, _t);
|
|
class->load->array = (CLASS_ARRAY **)get_section("array", §ion, &n_array, _i); // A special process is needed later
|
|
|
|
// Structure descriptions
|
|
|
|
if (info->nstruct)
|
|
{
|
|
ALLOC(&structure, sizeof(CLASS_STRUCT) * info->nstruct);
|
|
for (i = 0; i < info->nstruct; i++)
|
|
{
|
|
structure[i].desc = (int *)get_section("structure", §ion, &n_struct, _i);
|
|
structure[i].nfield = (n_struct - 1) / 2;
|
|
}
|
|
}
|
|
|
|
// Loading code
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
{
|
|
func = &class->load->func[i];
|
|
func->code = (ushort *)get_section("code", §ion, NULL, _s);
|
|
|
|
flag = ((FUNCTION_FLAG *)func)->flag;
|
|
|
|
func->fast = (flag & 1) != 0;
|
|
func->optional = (func->npmin < func->n_param);
|
|
func->use_is_missing = (flag & 2) != 0;
|
|
func->unsafe = (flag & 4) != 0;
|
|
func->fast_linked = FALSE;
|
|
|
|
if (func->use_is_missing)
|
|
{
|
|
func->stack_usage++;
|
|
func->n_ctrl++;
|
|
}
|
|
|
|
func->_reserved = 0;
|
|
}
|
|
|
|
/* Creation flags */
|
|
|
|
class->auto_create = (info->flag & CI_AUTOCREATE) != 0;
|
|
class->no_create = (info->flag & CI_NOCREATE) != 0;
|
|
//fprintf(stderr, "%s: info->flag = %d auto_create = %d no_create = %d\n", class->name, info->flag, class->auto_create, class->no_create);
|
|
|
|
/* Debugging information */
|
|
|
|
if (class->debug)
|
|
{
|
|
class->load->global = (GLOBAL_SYMBOL *)get_section("debug global", §ion, &class->load->n_global, _p _i _c _i );
|
|
class->load->sort = (ushort *)get_section("debug global sort", §ion, NULL, _s);
|
|
#ifdef OS_64BITS
|
|
class->load->debug =
|
|
#endif
|
|
debug = (FUNC_DEBUG *)get_section("debug method", §ion, NULL, _s _s _p _p _p _s _s );
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
{
|
|
func = &class->load->func[i];
|
|
func->debug = &debug[i];
|
|
func->debug->index = i;
|
|
}
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
{
|
|
func = &class->load->func[i];
|
|
func->debug->pos = (ushort *)get_section("debug line", §ion, NULL, _s );
|
|
}
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
{
|
|
func = &class->load->func[i];
|
|
func->debug->local = (LOCAL_SYMBOL *)get_section("debug local", §ion, &func->debug->n_local, _p _i _i );
|
|
}
|
|
}
|
|
|
|
// Profile information
|
|
|
|
if (EXEC_profile)
|
|
ALLOC_ZERO(&class->load->prof, sizeof(uint) * (class->debug ? (1 + class->load->n_func) : 1));
|
|
|
|
/* Source file path, ignored now! */
|
|
|
|
if (class->debug)
|
|
get_section("debug file name", §ion, NULL, NULL);
|
|
|
|
/* Strings */
|
|
|
|
class->string = (char *)get_section("string", §ion, NULL, NULL);
|
|
|
|
/* Referenced classes */
|
|
|
|
for (i = 0; i < n_class_ref; i++)
|
|
{
|
|
offset = (int)(intptr_t)class->load->class_ref[i];
|
|
|
|
// The compiler does not know if an array class is global or not, we must check now.
|
|
|
|
if (offset >= 0)
|
|
{
|
|
name = &class->string[offset];
|
|
len = strlen(name);
|
|
|
|
if (len >= 3 && name[len - 2] == '[')
|
|
{
|
|
do
|
|
{
|
|
len -= 2;
|
|
}
|
|
while (len >= 3 && name[len - 2] == '[');
|
|
|
|
if (CLASS_look_global(name, len))
|
|
offset = (- offset);
|
|
}
|
|
}
|
|
|
|
{
|
|
CLASS *ref;
|
|
|
|
if (offset >= 0)
|
|
{
|
|
ref = CLASS_find(&class->string[offset]);
|
|
//fprintf(stderr, "%s: %s -> %p (%s)\n", class->name, &class->string[offset], ref, ref->component ? ref->component->name : "NULL");
|
|
}
|
|
else if (offset < -1)
|
|
{
|
|
ref = CLASS_find_global(&class->string[-offset]);
|
|
//fprintf(stderr, "%s: %s -> %p (%s)\n", class->name, &class->string[-offset], ref, ref->component ? ref->component->name : "NULL");
|
|
}
|
|
else
|
|
ref = 0; //0x31415926; //CLASS_find(&class->string[-offset]);
|
|
|
|
class->load->class_ref[i] = ref;
|
|
}
|
|
}
|
|
|
|
/* Datatype conversion */
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
{
|
|
func = &class->load->func[i];
|
|
|
|
conv_type(class, &func->type);
|
|
func->is_static = _last_ctype_is_static;
|
|
|
|
if (func->n_param > 0)
|
|
{
|
|
func->param = (CLASS_PARAM *)local;
|
|
|
|
for (j = 0; j < func->n_param; j++)
|
|
conv_type(class, &func->param[j].type);
|
|
|
|
local += func->n_param;
|
|
}
|
|
|
|
if (func->n_local > 0)
|
|
{
|
|
func->local = (CLASS_LOCAL *)local;
|
|
|
|
#ifdef OS_64BITS
|
|
// The local variable descriptions are CTYPE that are 32 bits only.
|
|
// We must transform a 64 bits integer array into a 32 bits integer array.
|
|
for (j = 0; j < func->n_local; j++)
|
|
{
|
|
func->local[j] = func->local[j * 2];
|
|
}
|
|
#endif
|
|
|
|
// As the 'local' section is a mix of CLASS_PARAM and CLASS_LOCAL,
|
|
// we swap endianness there and not during get_section()
|
|
|
|
if (_swap)
|
|
{
|
|
for (j = 0; j < func->n_local; j++)
|
|
{
|
|
SWAP_int((int *)&func->local[j].type);
|
|
SWAP_type(&func->local[j].type);
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < func->n_local; j++)
|
|
conv_ctype(&func->local[j].type);
|
|
|
|
local += func->n_local;
|
|
}
|
|
}
|
|
|
|
/* Events information */
|
|
|
|
for (i = 0; i < class->n_event; i++)
|
|
{
|
|
event = &class->load->event[i];
|
|
|
|
conv_type(class, &event->type);
|
|
|
|
if (event->n_param > 0)
|
|
{
|
|
event->param = (CLASS_PARAM *)local;
|
|
|
|
for (j = 0; j < event->n_param; j++)
|
|
conv_type(class, &event->param[j].type);
|
|
|
|
local += event->n_param;
|
|
}
|
|
}
|
|
|
|
/* Extern calls information */
|
|
|
|
for (i = 0; i < class->load->n_ext; i++)
|
|
{
|
|
ext = &class->load->ext[i];
|
|
|
|
conv_type(class, &ext->type);
|
|
|
|
if (ext->n_param > 0)
|
|
{
|
|
ext->param = (CLASS_PARAM *)local;
|
|
|
|
for (j = 0; j < ext->n_param; j++)
|
|
conv_type(class, &ext->param[j].type);
|
|
|
|
local += ext->n_param;
|
|
}
|
|
}
|
|
|
|
/* End of file reached ? */
|
|
|
|
if (section != &class->data[len_data])
|
|
{
|
|
/*printf("%d\n", &class->load[BUFFER_length(class->load)] - section);*/
|
|
THROW_CLASS(class, "Unknown section", "");
|
|
}
|
|
|
|
|
|
/* Static array definition relocation */
|
|
|
|
if (n_array > 0)
|
|
{
|
|
#ifdef OS_64BITS
|
|
CLASS_ARRAY **array = class->load->array;
|
|
n_array = *((int *)array) / sizeof(int);
|
|
ALLOC(&class->load->array, sizeof(void *) * n_array);
|
|
#else
|
|
n_array = *((int *)class->load->array) / sizeof(int);
|
|
#endif
|
|
|
|
for (i = 0; i < n_array; i++)
|
|
{
|
|
#ifdef OS_64BITS
|
|
class->load->array[i] = (CLASS_ARRAY *)((char *)array + ((int *)array)[i]);
|
|
#else
|
|
class->load->array[i] = (CLASS_ARRAY *)((char *)class->load->array + ((int *)class->load->array)[i]);
|
|
#endif
|
|
//conv_type(class, &class->load->array[i]->type);
|
|
}
|
|
}
|
|
|
|
// Create structures (we may need the structure size to compute the variable sizes)
|
|
|
|
if (info->nstruct)
|
|
{
|
|
for (i = 0; i < info->nstruct; i++)
|
|
load_structure(class, structure[i].desc, structure[i].nfield);
|
|
FREE(&structure);
|
|
}
|
|
|
|
// Computes and align the position of each static and dynamic variables.
|
|
// Computes the total size needed accordingly.
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Compute variable position for %s\n", class->name);
|
|
#endif
|
|
|
|
pos = 0;
|
|
for (i = 0; i < class->load->n_stat; i++)
|
|
{
|
|
var = &class->load->stat[i];
|
|
conv_ctype(&var->type);
|
|
size = CLASS_sizeof_ctype(class, var->type);
|
|
pos = align_pos(pos, size);
|
|
var->pos = pos;
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Static #%d: %d\n", i, var->pos);
|
|
#endif
|
|
pos += size;
|
|
}
|
|
#ifdef OS_64BITS
|
|
info->s_static = align_pos(pos, 8);
|
|
#else
|
|
info->s_static = align_pos(pos, 4);
|
|
#endif
|
|
|
|
pos = 0;
|
|
for (i = 0; i < class->load->n_dyn; i++)
|
|
{
|
|
var = &class->load->dyn[i];
|
|
conv_ctype(&var->type);
|
|
size = CLASS_sizeof_ctype(class, var->type);
|
|
pos = align_pos(pos, size);
|
|
var->pos = pos;
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Dynamic #%d: %d\n", i, var->pos);
|
|
#endif
|
|
pos += size; //sizeof_ctype(class, var->type);
|
|
}
|
|
#ifdef OS_64BITS
|
|
info->s_dynamic = align_pos(pos, 8);
|
|
#else
|
|
info->s_dynamic = align_pos(pos, 4);
|
|
#endif
|
|
|
|
/* String relocation */
|
|
|
|
for (i = 0; i < n_desc; i++)
|
|
RELOCATE(start[i].gambas.name);
|
|
|
|
for (i = 0; i < n_unknown; i++)
|
|
RELOCATE(class->load->unknown[i]);
|
|
|
|
for (i = 0; i < class->n_event; i++)
|
|
RELOCATE(class->load->event[i].name);
|
|
|
|
for (i = 0; i < class->load->n_ext; i++)
|
|
{
|
|
RELOCATE(class->load->ext[i].library);
|
|
RELOCATE(class->load->ext[i].alias);
|
|
}
|
|
|
|
if (class->debug)
|
|
{
|
|
for (i = 0; i < class->load->n_global; i++)
|
|
{
|
|
RELOCATE(class->load->global[i].sym.name);
|
|
/*conv_type(class, &(class->load->global[i].type));*/
|
|
}
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
{
|
|
func = &class->load->func[i];
|
|
RELOCATE(func->debug->name);
|
|
|
|
for (j = 0; j < func->debug->n_local; j++)
|
|
RELOCATE(func->debug->local[j].sym.name);
|
|
}
|
|
}
|
|
|
|
/* Inheritance */
|
|
|
|
if (info->parent >= 0)
|
|
{
|
|
//printf("%s inherits %s\n", class->name, (class->load->class_ref[info->parent])->name);
|
|
CLASS_inheritance(class, class->load->class_ref[info->parent]);
|
|
}
|
|
|
|
/* If there is no dynamic variable, then the class is not instanciable */
|
|
//if (info->s_dynamic == 0)
|
|
// class->no_create = TRUE;
|
|
|
|
/* Class size and offsets */
|
|
|
|
CLASS_calc_info(class, class->n_event, info->s_dynamic, FALSE, info->s_static);
|
|
|
|
*pstart = start;
|
|
*pndesc = n_desc;
|
|
}
|
|
|
|
|
|
static void load_without_inits(CLASS *class)
|
|
{
|
|
int i;
|
|
FUNCTION *func;
|
|
CLASS_DESC *desc;
|
|
CLASS_CONST *cc;
|
|
CLASS_VAR *var;
|
|
int len;
|
|
CLASS_EVENT *event;
|
|
CLASS_EXTERN *ext;
|
|
VALUE value;
|
|
int len_data;
|
|
int n_desc;
|
|
int offset;
|
|
int first;
|
|
int first_event;
|
|
COMPONENT *save;
|
|
CLASS_DESC *start;
|
|
char kind;
|
|
|
|
//size_t alloc = MEMORY_size;
|
|
|
|
if (CLASS_is_loaded(class))
|
|
return;
|
|
|
|
if (class->error)
|
|
THROW_CLASS(class, "Loading has already failed", "");
|
|
|
|
if (CLASS_exiting)
|
|
THROW_CLASS(class, "Program is exiting", "");
|
|
|
|
class->error = TRUE;
|
|
|
|
#if DEBUG_LOAD
|
|
fprintf(stderr, "Loading class %s (%p)...\n", class->name, class);
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
Class = class;
|
|
NSection = 0;
|
|
#endif
|
|
|
|
_class_name = class->name;
|
|
|
|
if (class->in_load)
|
|
THROW_CLASS(class, "Circular reference", "");
|
|
|
|
if (!class->component)
|
|
{
|
|
if (CP)
|
|
{
|
|
class->component = CP->component;
|
|
#if DEBUG_COMP
|
|
fprintf(stderr, "Load class %s -> component %s from CP\n", class->name, class->component ? class->component->name : "NULL");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
class->component = COMPONENT_current;
|
|
#if DEBUG_COMP
|
|
fprintf(stderr, "Load class %s -> component %s from COMPONENT_current\n", class->name, class->component ? class->component->name : "NULL");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if DEBUG_COMP
|
|
if (class->component)
|
|
fprintf(stderr, "Load class %s -> component %s\n", class->name, class->component->name);
|
|
else
|
|
fprintf(stderr, "Load class %s -> no component\n", class->name);
|
|
#endif
|
|
|
|
save = COMPONENT_current;
|
|
COMPONENT_current = class->component;
|
|
#if DEBUG_LOAD
|
|
fprintf(stderr, "COMPONENT_current = %s\n", COMPONENT_current ? COMPONENT_current->name : "NULL");
|
|
#endif
|
|
|
|
len = strlen(class->name);
|
|
|
|
{
|
|
char name[len + 9];
|
|
char *p;
|
|
|
|
strcpy(name, ".gambas/");
|
|
p = &name[8];
|
|
|
|
for (i = 0; i < len; i++)
|
|
*p++ = toupper(class->name[i]);
|
|
*p = 0;
|
|
|
|
TRY
|
|
{
|
|
//class->mmapped = !STREAM_map(name, &class->data, &len_data);
|
|
STREAM_load(name, &class->data, &len_data);
|
|
}
|
|
CATCH
|
|
{
|
|
COMPONENT_current = save;
|
|
THROW_CLASS(class, "Unable to load class file", "");
|
|
}
|
|
END_TRY
|
|
|
|
/*if (BUFFER_load_file(&class->data, FILE_get(name)))
|
|
THROW(E_CLASS, _class_name, "Unable to load class file", "");*/
|
|
}
|
|
|
|
COMPONENT_current = save;
|
|
#if DEBUG_LOAD
|
|
fprintf(stderr, "COMPONENT_current = %s\n", COMPONENT_current ? COMPONENT_current->name : "NULL");
|
|
#endif
|
|
|
|
class->in_load = TRUE;
|
|
|
|
class->init_dynamic = TRUE;
|
|
|
|
load_and_relocate(class, len_data, &start, &n_desc);
|
|
|
|
// Information on static and dynamic variables
|
|
|
|
if (class->parent)
|
|
offset = class->parent->off_event;
|
|
else
|
|
offset = sizeof(OBJECT);
|
|
|
|
for (i = 0; i < class->load->n_dyn; i++)
|
|
{
|
|
var = &class->load->dyn[i];
|
|
var->pos += offset;
|
|
}
|
|
|
|
// Constant conversion & relocation
|
|
|
|
for (i = 0; i < class->load->n_cst; i++)
|
|
{
|
|
cc = &class->load->cst[i];
|
|
conv_type_simple(class, &(cc->type));
|
|
|
|
switch (cc->type)
|
|
{
|
|
case T_BOOLEAN: case T_BYTE: case T_SHORT: case T_INTEGER:
|
|
#ifdef OS_64BITS
|
|
// Special process for integer constants
|
|
cc->_integer.value = (int)(intptr_t)cc->_string.addr;
|
|
#endif
|
|
break;
|
|
|
|
case T_LONG:
|
|
#ifdef OS_64BITS
|
|
// Special process for long constants: the first 32 bits part of the LONG constant
|
|
// has been extended to 64 bits
|
|
//cc->_swap.val[0] = (int)(*((int64_t *)(void *)&cc->_string.addr));
|
|
cc->_swap.val[0] = (int)(intptr_t)cc->_string.addr;
|
|
cc->_swap.val[1] = cc->_string.len;
|
|
#endif
|
|
/*
|
|
The two 32 bits parts of the LONG value have been already swapped independently.
|
|
So we just have to swap the two parts again.
|
|
*/
|
|
if (_swap)
|
|
{
|
|
int val;
|
|
|
|
val = cc->_swap.val[0];
|
|
cc->_swap.val[0] = cc->_swap.val[1];
|
|
cc->_swap.val[1] = val;
|
|
}
|
|
break;
|
|
|
|
case T_STRING: case T_CSTRING:
|
|
if (cc->_string.len)
|
|
cc->_string.addr += (intptr_t)class->string;
|
|
break;
|
|
|
|
case T_FLOAT: case T_SINGLE:
|
|
cc->_string.addr += (intptr_t)class->string;
|
|
if (NUMBER_from_string(NB_READ_FLOAT, cc->_string.addr, strlen(cc->_string.addr), &value))
|
|
THROW_CLASS(class, "Bad constant", "");
|
|
if (cc->type == T_SINGLE)
|
|
cc->_single.value = (float)value._float.value;
|
|
else
|
|
cc->_float.value = value._float.value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Event description
|
|
|
|
CLASS_make_event(class, &first_event);
|
|
|
|
if (class->free_event && class->n_event > first_event)
|
|
memcpy(&class->event[first_event], class->load->event, (class->n_event - first_event) * sizeof(CLASS_EVENT));
|
|
|
|
// Class public description
|
|
|
|
for (i = 0; i < n_desc; i++)
|
|
{
|
|
desc = &start[i]; //class->table[i].desc;
|
|
|
|
//desc->gambas.name = (char *)CLASS_DESC_get_type_name(desc);
|
|
|
|
conv_type(class, &desc->gambas.type);
|
|
|
|
kind = *CLASS_DESC_get_type_name(desc);
|
|
|
|
if (!desc->gambas.val1 && index(CD_CALL_SOMETHING_LIST, kind) != NULL)
|
|
fprintf(stderr, "load_without_inits: '%s.%s' gambas.val1 == 0\n", class->name, desc->gambas.name);
|
|
|
|
switch (kind)
|
|
{
|
|
case CD_METHOD:
|
|
case CD_STATIC_METHOD:
|
|
|
|
func = &class->load->func[desc->gambas.val1];
|
|
desc->method.exec = (void (*)())desc->gambas.val1;
|
|
desc->method.npmin = func->npmin;
|
|
desc->method.npmax = func->n_param;
|
|
desc->method.npvar = func->vararg;
|
|
desc->method.signature = (TYPE *)func->param;
|
|
//desc->method.help = NULL;
|
|
desc->method.native = FALSE;
|
|
|
|
break;
|
|
|
|
case CD_PROPERTY:
|
|
case CD_STATIC_PROPERTY:
|
|
case CD_PROPERTY_READ:
|
|
case CD_STATIC_PROPERTY_READ:
|
|
|
|
desc->property.read = (void (*)())desc->gambas.val1;
|
|
desc->property.write = (void (*)())desc->gambas.val2;
|
|
//if ((intptr_t)desc->property.write == -1L)
|
|
// desc->gambas.name = *desc->gambas.name == 'p' ? "r" : "R";
|
|
desc->property.native = FALSE;
|
|
|
|
break;
|
|
|
|
case CD_VARIABLE:
|
|
case CD_STATIC_VARIABLE:
|
|
|
|
if (kind == CD_STATIC_VARIABLE)
|
|
var = &class->load->stat[desc->gambas.val1];
|
|
else
|
|
var = &class->load->dyn[desc->gambas.val1];
|
|
|
|
desc->variable.ctype = var->type;
|
|
desc->variable.offset = var->pos;
|
|
|
|
break;
|
|
|
|
case CD_CONSTANT:
|
|
|
|
cc = &class->load->cst[desc->gambas.val1];
|
|
|
|
if (TYPE_is_integer(desc->constant.type))
|
|
desc->constant.value._integer = cc->_integer.value;
|
|
else if (desc->constant.type == T_FLOAT)
|
|
desc->constant.value._float = cc->_float.value;
|
|
else if (desc->constant.type == T_LONG)
|
|
desc->constant.value._long = cc->_long.value;
|
|
else if (desc->constant.type == T_SINGLE)
|
|
desc->constant.value._single = cc->_single.value;
|
|
else
|
|
{
|
|
desc->constant.type = T_CSTRING;
|
|
desc->constant.value._string = cc->_string.addr;
|
|
desc->constant.translate = (cc->type == T_CSTRING);
|
|
}
|
|
|
|
break;
|
|
|
|
case CD_EVENT:
|
|
|
|
//fprintf(stderr, "event %s.%s: %d %d\n", class->name, desc->event.name, first_event, (int)desc->event.index);
|
|
|
|
event = &class->load->event[desc->event.index];
|
|
if (class->parent)
|
|
desc->event.index += class->parent->n_event;
|
|
desc->event.npmin = event->n_param;
|
|
desc->event.npmax = event->n_param;
|
|
desc->event.signature = (TYPE *)event->param;
|
|
//desc->event.help = NULL;
|
|
//desc->event.index = first_event++;
|
|
break;
|
|
|
|
case CD_EXTERN:
|
|
|
|
ext = &class->load->ext[desc->gambas.val1];
|
|
desc->ext.npmin = ext->n_param;
|
|
desc->ext.npmax = ext->n_param;
|
|
desc->ext.npmin = ext->n_param;
|
|
desc->ext.signature = (TYPE *)ext->param;
|
|
//desc->event.help = NULL;
|
|
break;
|
|
|
|
default:
|
|
|
|
THROW_CLASS(class, "Bad description", "");
|
|
}
|
|
}
|
|
|
|
// Inheritance
|
|
|
|
CLASS_make_description(class, start, n_desc, &first);
|
|
|
|
// Transfer symbol kind into symbol name (which is stored in the symbol table now), like native classes
|
|
// Define event index
|
|
|
|
for (i = 0; i < n_desc; i++)
|
|
{
|
|
desc = &start[i];
|
|
desc->gambas.name = (char *)CLASS_DESC_get_type_name(desc);
|
|
desc->method.class = class;
|
|
}
|
|
|
|
// Sort the class description
|
|
|
|
CLASS_sort(class);
|
|
|
|
// Special methods
|
|
|
|
CLASS_search_special(class);
|
|
|
|
// JIT compilation
|
|
|
|
for (i = 0; i < class->load->n_func; i++)
|
|
{
|
|
if (class->load->func[i].fast)
|
|
{
|
|
ARCHIVE *arch = class->component ? class->component->archive : NULL;
|
|
|
|
if (JIT_can_compile(arch))
|
|
JIT_compile(arch);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Class is loaded...
|
|
|
|
class->in_load = FALSE;
|
|
|
|
// ...and usable !
|
|
|
|
class->loaded = TRUE;
|
|
class->error = FALSE;
|
|
|
|
// Init breakpoints
|
|
|
|
if (EXEC_debug)
|
|
DEBUG.InitBreakpoints(class);
|
|
|
|
//total += MEMORY_size - alloc;
|
|
//printf("%s: %d TOTAL = %d\n", class->name, MEMORY_size - alloc, total);
|
|
}
|
|
|
|
#if 0
|
|
void CLASS_load_without_init(CLASS *class)
|
|
{
|
|
load_without_inits(class, FALSE);
|
|
|
|
/* Call the static initializer */
|
|
|
|
EXEC.native = FALSE;
|
|
EXEC.class = class;
|
|
EXEC.object = NULL;
|
|
EXEC.nparam = 0;
|
|
EXEC.index = FUNC_INIT_STATIC;
|
|
//EXEC.func = &class->load->func[FUNC_INIT_STATIC];
|
|
|
|
EXEC_function();
|
|
}
|
|
#endif
|
|
|
|
void CLASS_run_inits(CLASS *class)
|
|
{
|
|
COMPONENT *current = COMPONENT_current;
|
|
COMPONENT_current = NULL;
|
|
/* Call the static initializer */
|
|
|
|
EXEC.native = FALSE;
|
|
EXEC.class = class;
|
|
EXEC.object = NULL;
|
|
EXEC.nparam = 0;
|
|
EXEC.index = FUNC_INIT_STATIC;
|
|
//EXEC.func = &class->load->func[FUNC_INIT_STATIC];
|
|
|
|
EXEC_function();
|
|
|
|
/* _init */
|
|
EXEC_public(class, NULL, "_init", 0);
|
|
|
|
COMPONENT_current = current;
|
|
}
|
|
|
|
|
|
void CLASS_load_real(CLASS *class)
|
|
{
|
|
bool load_without_init = _load_without_init;
|
|
char *name = class->name;
|
|
int len = strlen(name);
|
|
|
|
_load_without_init = FALSE;
|
|
|
|
if (!CLASS_is_loaded(class))
|
|
{
|
|
if (len >= 3 && name[len - 2] == '[' && name[len - 1] == ']' && !class->array_type)
|
|
{
|
|
CLASS_create_array_class(class);
|
|
return;
|
|
}
|
|
}
|
|
|
|
load_without_inits(class);
|
|
class->loaded = TRUE;
|
|
class->ready = FALSE;
|
|
|
|
if (load_without_init)
|
|
return;
|
|
|
|
class->ready = TRUE;
|
|
CLASS_run_inits(class);
|
|
}
|
|
|
|
void CLASS_load_without_init(CLASS *class)
|
|
{
|
|
if (CLASS_is_loaded(class))
|
|
return;
|
|
|
|
_load_without_init = TRUE;
|
|
CLASS_load_real(class);
|
|
}
|