2025-01-22 16:18:30 +01:00

1103 lines
28 KiB
C

/*
* Copyright (C)2015-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "hlmodule.h"
#define OP(_,n) n,
#define OP_BEGIN static int hl_op_nargs[] = {
#define OP_END };
#include "opcodes.h"
#define OP(n,_) #n,
#define OP_BEGIN static const char *hl_op_names[] = {
#define OP_END };
#include "opcodes.h"
typedef struct {
const unsigned char *b;
int size;
int pos;
const char *error;
hl_code *code;
} hl_reader;
#undef ERROR
#define READ() hl_read_b(r)
#define INDEX() hl_read_index(r)
#define UINDEX() hl_read_uindex(r)
#define ERROR(msg) if( !r->error ) { r->error = msg; hl_debug_break(); }
#define CHK_ERROR() if( r->error ) return
static unsigned char hl_read_b( hl_reader *r ) {
if( r->pos >= r->size ) {
ERROR("No more data");
return 0;
}
return r->b[r->pos++];
}
static void hl_read_bytes( hl_reader *r, void *data, int size ) {
if( size < 0 ) {
ERROR("Invalid size");
return;
}
if( r->pos + size > r->size ) {
ERROR("No more data");
return;
}
memcpy(data,r->b + r->pos, size);
r->pos += size;
}
static double hl_read_double( hl_reader *r ) {
double d = 0.;
hl_read_bytes(r, &d, 8);
return d;
}
static int hl_read_i32( hl_reader *r ) {
unsigned char a, b, c, d;
if( r->pos + 4 > r->size ) {
ERROR("No more data");
return 0;
}
a = r->b[r->pos++];
b = r->b[r->pos++];
c = r->b[r->pos++];
d = r->b[r->pos++];
return a | (b<<8) | (c<<16) | (d<<24);
}
static int hl_read_index( hl_reader *r ) {
unsigned char b = READ();
if( (b & 0x80) == 0 )
return b & 0x7F;
if( (b & 0x40) == 0 ) {
int v = READ() | ((b & 31) << 8);
return (b & 0x20) == 0 ? v : -v;
}
{
int c = READ();
int d = READ();
int e = READ();
int v = ((b & 31) << 24) | (c << 16) | (d << 8) | e;
return (b & 0x20) == 0 ? v : -v;
}
}
static int hl_read_uindex( hl_reader *r ) {
int i = hl_read_index(r);
if( i < 0 ) {
ERROR("Negative index");
return 0;
}
return i;
}
static hl_type *hl_get_type( hl_reader *r ) {
int i = INDEX();
if( i < 0 || i >= r->code->ntypes ) {
ERROR("Invalid type index");
i = 0;
}
return r->code->types + i;
}
static const char *hl_read_string( hl_reader *r ) {
int i = INDEX();
if( i < 0 || i >= r->code->nstrings ) {
ERROR("Invalid string index");
return "";
}
return r->code->strings[i];
}
const uchar *hl_get_ustring( hl_code *code, int index ) {
uchar *str = code->ustrings[index];
if( str == NULL ) {
int size = hl_utf8_length((vbyte*)code->strings[index],0);
str = hl_malloc(&code->alloc,(size+1)<<1);
hl_from_utf8(str,size,code->strings[index]);
code->ustrings[index] = str;
}
return str;
}
static const uchar *hl_read_ustring( hl_reader *r ) {
int i = INDEX();
if( i < 0 || i >= r->code->nstrings ) {
ERROR("Invalid string index");
i = 0;
}
return hl_get_ustring(r->code,i);
}
static void hl_read_type( hl_reader *r, hl_type *t ) {
t->kind = READ();
switch( (int)t->kind ) {
case HFUN:
case HMETHOD:
{
int i;
int nargs = READ();
t->fun = (hl_type_fun*)hl_zalloc(&r->code->alloc,sizeof(hl_type_fun));
t->fun->nargs = nargs;
t->fun->args = (hl_type**)hl_malloc(&r->code->alloc,sizeof(hl_type*)*nargs);
for(i=0;i<nargs;i++)
t->fun->args[i] = hl_get_type(r);
t->fun->ret = hl_get_type(r);
}
break;
case HOBJ:
case HSTRUCT:
{
int i;
const uchar *name = hl_read_ustring(r);
int super = INDEX();
int global = UINDEX();
int nfields = UINDEX();
int nproto = UINDEX();
int nbindings = UINDEX();
t->obj = (hl_type_obj*)hl_malloc(&r->code->alloc,sizeof(hl_type_obj));
t->obj->name = name;
t->obj->super = super < 0 ? NULL : r->code->types + super;
t->obj->global_value = (void**)(int_val)global;
t->obj->nfields = nfields;
t->obj->nproto = nproto;
t->obj->nbindings = nbindings;
t->obj->fields = (hl_obj_field*)hl_malloc(&r->code->alloc,sizeof(hl_obj_field)*nfields);
t->obj->proto = (hl_obj_proto*)hl_malloc(&r->code->alloc,sizeof(hl_obj_proto)*nproto);
t->obj->bindings = (int*)hl_malloc(&r->code->alloc,sizeof(int)*nbindings*2);
t->obj->rt = NULL;
for(i=0;i<nfields;i++) {
hl_obj_field *f = t->obj->fields + i;
f->name = hl_read_ustring(r);
f->hashed_name = hl_hash_gen(f->name,true);
f->t = hl_get_type(r);
}
for(i=0;i<nproto;i++) {
hl_obj_proto *p = t->obj->proto + i;
p->name = hl_read_ustring(r);
p->hashed_name = hl_hash_gen(p->name,true);
p->findex = UINDEX();
p->pindex = INDEX();
}
for(i=0;i<nbindings;i++) {
t->obj->bindings[i<<1] = UINDEX();
t->obj->bindings[(i<<1)|1] = UINDEX();
}
}
break;
case HREF:
t->tparam = hl_get_type(r);
break;
case HVIRTUAL:
{
int i;
int nfields = UINDEX();
t->virt = (hl_type_virtual*)hl_malloc(&r->code->alloc,sizeof(hl_type_virtual));
t->virt->nfields = nfields;
t->virt->fields = (hl_obj_field*)hl_malloc(&r->code->alloc,sizeof(hl_obj_field)*nfields);
for(i=0;i<nfields;i++) {
hl_obj_field *f = t->virt->fields + i;
f->name = hl_read_ustring(r);
f->hashed_name = hl_hash_gen(f->name,true);
f->t = hl_get_type(r);
}
}
break;
case HABSTRACT:
t->abs_name = hl_read_ustring(r);
break;
case HENUM:
{
int i,j;
t->tenum = hl_malloc(&r->code->alloc,sizeof(hl_type_enum));
t->tenum->name = hl_read_ustring(r);
t->tenum->global_value = (void**)(int_val)UINDEX();
t->tenum->nconstructs = UINDEX();
t->tenum->constructs = (hl_enum_construct*)hl_malloc(&r->code->alloc, sizeof(hl_enum_construct)*t->tenum->nconstructs);
for(i=0;i<t->tenum->nconstructs;i++) {
hl_enum_construct *c = t->tenum->constructs + i;
c->name = hl_read_ustring(r);
c->nparams = UINDEX();
c->params = (hl_type**)hl_malloc(&r->code->alloc,sizeof(hl_type*)*c->nparams);
c->offsets = (int*)hl_malloc(&r->code->alloc,sizeof(int)*c->nparams);
for(j=0;j<c->nparams;j++)
c->params[j] = hl_get_type(r);
}
}
break;
case HNULL:
case HPACKED:
t->tparam = hl_get_type(r);
break;
default:
if( t->kind >= HLAST ) ERROR("Invalid type");
break;
}
}
static void hl_read_opcode( hl_reader *r, hl_function *f, hl_opcode *o ) {
o->op = (hl_op)READ();
if( o->op >= OLast ) {
ERROR("Invalid opcode");
return;
}
switch( hl_op_nargs[o->op] ) {
case 0:
break;
case 1:
o->p1 = INDEX();
break;
case 2:
o->p1 = INDEX();
o->p2 = INDEX();
break;
case 3:
o->p1 = INDEX();
o->p2 = INDEX();
o->p3 = INDEX();
break;
case 4:
o->p1 = INDEX();
o->p2 = INDEX();
o->p3 = INDEX();
o->extra = (int*)(int_val)INDEX();
break;
case -1:
switch( o->op ) {
case OCallN:
case OCallClosure:
case OCallMethod:
case OCallThis:
case OMakeEnum:
{
int i;
o->p1 = INDEX();
o->p2 = INDEX();
o->p3 = READ();
o->extra = (int*)hl_malloc(&r->code->falloc,sizeof(int) * o->p3);
for(i=0;i<o->p3;i++)
o->extra[i] = INDEX();
}
break;
case OSwitch:
{
int i;
o->p1 = UINDEX();
o->p2 = UINDEX();
o->extra = (int*)hl_malloc(&r->code->falloc,sizeof(int) * o->p2);
for(i=0;i<o->p2;i++)
o->extra[i] = UINDEX();
o->p3 = UINDEX();
}
break;
default:
ERROR("Don't know how to process opcode");
break;
}
break;
default:
{
int i, size = hl_op_nargs[o->op] - 3;
o->p1 = INDEX();
o->p2 = INDEX();
o->p3 = INDEX();
o->extra = (int*)hl_malloc(&r->code->falloc,sizeof(int) * size);
for(i=0;i<size;i++)
o->extra[i] = INDEX();
}
break;
}
}
static void hl_read_function( hl_reader *r, hl_function *f ) {
int i;
f->type = hl_get_type(r);
f->findex = UINDEX();
f->nregs = UINDEX();
f->nops = UINDEX();
f->regs = (hl_type**)hl_malloc(&r->code->falloc, f->nregs * sizeof(hl_type*));
for(i=0;i<f->nregs;i++)
f->regs[i] = hl_get_type(r);
CHK_ERROR();
f->ops = (hl_opcode*)hl_malloc(&r->code->falloc, f->nops * sizeof(hl_opcode));
for(i=0;i<f->nops;i++)
hl_read_opcode(r, f, f->ops+i);
}
#undef CHK_ERROR
#define CHK_ERROR() if( r->error ) { if( c ) hl_free(&c->alloc); *error_msg = (char*)r->error; return NULL; }
#define EXIT(msg) { ERROR(msg); CHK_ERROR(); }
#define ALLOC(v,ptr,count) v = (ptr *)hl_zalloc(&c->alloc,(count)*sizeof(ptr))
const char *hl_op_name( int op ) {
if( op < 0 || op >= OLast )
return "UnknownOp";
return hl_op_names[op];
}
static char **hl_read_strings( hl_reader *r, int nstrings, int **out_lens ) {
int size = hl_read_i32(r);
hl_code *c = r->code;
char *sbase = (char*)hl_malloc(&c->alloc,sizeof(char) * size);
char *sdata = sbase;
char **strings;
int *lens;
int i;
hl_read_bytes(r, sdata, size);
ALLOC(strings, char*, nstrings);
ALLOC(lens, int, nstrings);
for(i=0;i<nstrings;i++) {
int sz = UINDEX();
strings[i] = sdata;
lens[i] = sz;
sdata += sz;
if( sdata >= sbase + size || *sdata ) {
ERROR("Invalid string");
return NULL;
}
sdata++;
}
*out_lens = lens;
return strings;
}
static int *hl_read_debug_infos( hl_reader *r, int nops ) {
int curfile = -1, curline = 0;
hl_code *code = r->code;
int *debug = (int*)hl_malloc(&code->alloc, sizeof(int) * nops * 2);
int i = 0;
while( i < nops ) {
int c = READ();
if( c & 1 ) {
c >>= 1;
curfile = (c << 8) | READ();
if( curfile >= code->ndebugfiles )
ERROR("Invalid debug file");
} else if( c & 2 ) {
int delta = c >> 6;
int count = (c >> 2) & 15;
if( i + count > nops )
ERROR("Outside range");
while( count-- ) {
debug[i<<1] = curfile;
debug[(i<<1)|1] = curline;
i++;
}
curline += delta;
} else if( c & 4 ) {
curline += c >> 3;
debug[i<<1] = curfile;
debug[(i<<1)|1] = curline;
i++;
} else {
unsigned char b2 = READ();
unsigned char b3 = READ();
curline = (c >> 3) | (b2 << 5) | (b3 << 13);
debug[i<<1] = curfile;
debug[(i<<1)|1] = curline;
i++;
}
}
return debug;
}
hl_code *hl_code_read( const unsigned char *data, int size, char **error_msg ) {
hl_reader _r = { data, size, 0, 0, NULL };
hl_reader *r = &_r;
hl_code *c;
hl_alloc alloc;
int i;
int flags;
int max_version = 5;
hl_alloc_init(&alloc);
c = hl_zalloc(&alloc,sizeof(hl_code));
c->alloc = alloc;
hl_alloc_init(&c->falloc);
if( READ() != 'H' || READ() != 'L' || READ() != 'B' )
EXIT("Invalid HL bytecode header");
r->code = c;
c->version = READ();
if( c->version <= 1 || c->version > max_version ) {
printf("Found version %d while HL %d.%d supports up to %d\n",c->version,HL_VERSION>>16,(HL_VERSION>>8)&0xFF,max_version);
EXIT("Unsupported bytecode version");
}
flags = UINDEX();
c->nints = UINDEX();
c->nfloats = UINDEX();
c->nstrings = UINDEX();
if( c->version >= 5 )
c->nbytes = UINDEX();
c->ntypes = UINDEX();
c->nglobals = UINDEX();
c->nnatives = UINDEX();
c->nfunctions = UINDEX();
c->nconstants = c->version >= 4 ? UINDEX() : 0;
c->entrypoint = UINDEX();
c->hasdebug = flags & 1;
CHK_ERROR();
ALLOC(c->ints, int, c->nints);
for(i=0;i<c->nints;i++)
c->ints[i] = hl_read_i32(r);
CHK_ERROR();
ALLOC(c->floats, double, c->nfloats);
for(i=0;i<c->nfloats;i++)
c->floats[i] = hl_read_double(r);
CHK_ERROR();
c->strings = hl_read_strings(r, c->nstrings, &c->strings_lens);
ALLOC(c->ustrings,uchar*,c->nstrings);
CHK_ERROR();
if( c->version >= 5 ) {
int size = hl_read_i32(r);
c->bytes = hl_malloc(&c->alloc,size);
hl_read_bytes(r,c->bytes,size);
ALLOC(c->bytes_pos,int,c->nbytes);
CHK_ERROR();
for(i=0;i<c->nbytes;i++)
c->bytes_pos[i] = UINDEX();
CHK_ERROR();
}
if( c->hasdebug ) {
c->ndebugfiles = UINDEX();
c->debugfiles = hl_read_strings(r, c->ndebugfiles, &c->debugfiles_lens);
CHK_ERROR();
}
ALLOC(c->types, hl_type, c->ntypes);
for(i=0;i<c->ntypes;i++) {
hl_read_type(r, c->types + i);
CHK_ERROR();
}
ALLOC(c->globals, hl_type*, c->nglobals);
for(i=0;i<c->nglobals;i++)
c->globals[i] = hl_get_type(r);
CHK_ERROR();
ALLOC(c->natives, hl_native, c->nnatives);
for(i=0;i<c->nnatives;i++) {
hl_native *n = c->natives + i;
n->lib = hl_read_string(r);
n->name = hl_read_string(r);
n->t = hl_get_type(r);
n->findex = UINDEX();
}
CHK_ERROR();
ALLOC(c->functions, hl_function, c->nfunctions);
for(i=0;i<c->nfunctions;i++) {
hl_read_function(r,c->functions+i);
CHK_ERROR();
if( c->hasdebug ) {
c->functions[i].debug = hl_read_debug_infos(r,c->functions[i].nops);
if( c->version >= 3 ) {
// skip assigns (no need here)
int nassigns = UINDEX();
int j;
for(j=0;j<nassigns;j++) {
UINDEX();
INDEX();
}
}
}
}
CHK_ERROR();
ALLOC(c->constants, hl_constant, c->nconstants);
for (i = 0; i < c->nconstants; i++) {
int j;
hl_constant *k = c->constants + i;
k->global = UINDEX();
k->nfields = UINDEX();
ALLOC(k->fields, int, k->nfields);
for (j = 0; j < k->nfields; j++)
k->fields[j] = UINDEX();
CHK_ERROR();
}
return c;
}
void hl_code_free( hl_code *c ) {
hl_free(&c->falloc);
}
static const unsigned int crc32_table[] =
{
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
#define H(b) hash = (hash >> 8) ^ crc32_table[(hash ^ (b)) & 0xFF]
#define H32(i) { H(i&0xFF); H((i>>8)&0xFF); H((i>>16)&0xFF); H(((unsigned int)i)>>24); }
#define HFUN(idx) H32(h->functions_signs[h->functions_indexes[idx]]);
#define HSTR(s) { const char *_c = s; while( *_c ) H(*_c++); }
#define HUSTR(s) { const uchar *_c = s; while( *_c ) H(*_c++); }
#define HTYPE(t) if( !isrec ) H32(hash_type_first(t,true))
// hash with only partial recursion
static int hash_type_first( hl_type *t, bool isrec ) {
int hash = -1;
int i;
H(t->kind);
switch( t->kind ) {
case HFUN:
case HMETHOD:
H(t->fun->nargs);
for(i=0;i<t->fun->nargs;i++)
HTYPE(t->fun->args[i]);
HTYPE(t->fun->ret);
break;
case HOBJ:
case HSTRUCT:
HUSTR(t->obj->name);
H32(t->obj->nfields);
H32(t->obj->nproto);
for(i=0;i<t->obj->nfields;i++) {
hl_obj_field *f = t->obj->fields + i;
H32(f->hashed_name);
HTYPE(f->t);
}
break;
case HREF:
case HNULL:
HTYPE(t->tparam);
break;
case HVIRTUAL:
H32(t->virt->nfields);
for(i=0;i<t->virt->nfields;i++) {
hl_obj_field *f = t->virt->fields + i;
H32(f->hashed_name);
HTYPE(f->t);
}
break;
case HENUM:
HUSTR(t->tenum->name);
for(i=0;i<t->tenum->nconstructs;i++) {
hl_enum_construct *c = t->tenum->constructs + i;
int k;
H(c->nparams);
HUSTR(c->name);
for(k=0;k<c->nparams;k++)
HTYPE(c->params[k]);
}
break;
case HABSTRACT:
HUSTR(t->abs_name);
break;
default:
break;
}
return hash;
}
#undef HTYPE
#define HTYPE(t) H32(h->types_hashes[t - h->code->types])
static int hash_type_rec( hl_code_hash *h, hl_type *t ) {
int hash = -1;
int i;
switch( t->kind ) {
case HFUN:
case HMETHOD:
for(i=0;i<t->fun->nargs;i++)
HTYPE(t->fun->args[i]);
HTYPE(t->fun->ret);
break;
case HOBJ:
case HSTRUCT:
for(i=0;i<t->obj->nfields;i++) {
hl_obj_field *f = t->obj->fields + i;
HTYPE(f->t);
}
break;
case HREF:
case HNULL:
HTYPE(t->tparam);
break;
case HVIRTUAL:
for(i=0;i<t->virt->nfields;i++) {
hl_obj_field *f = t->virt->fields + i;
HTYPE(f->t);
}
break;
case HENUM:
for(i=0;i<t->tenum->nconstructs;i++) {
hl_enum_construct *c = t->tenum->constructs + i;
int k;
for(k=0;k<c->nparams;k++)
HTYPE(c->params[k]);
}
break;
default:
break;
}
return hash;
}
static int hash_native( hl_code_hash *h, hl_native *n ) {
int hash = -1;
HSTR(n->lib);
HSTR(n->name);
HTYPE(n->t);
return hash;
}
static int hash_fun_sign( hl_code_hash *h, hl_function *f ) {
int hash = -1;
HTYPE(f->type);
if( f->obj ) {
HUSTR(f->obj->name);
HUSTR(f->field.name);
} else if( f->field.ref ) {
HUSTR(f->field.ref->obj->name);
HUSTR(f->field.ref->field.name);
H32(f->ref);
}
return hash;
}
static int hash_fun( hl_code_hash *h, hl_function *f ) {
int hash = -1;
hl_code *c = h->code;
int i, k;
for(i=0;i<f->nregs;i++)
HTYPE(f->regs[i]);
for(k=0;k<f->nops;k++) {
hl_opcode *o = f->ops + k;
H(o->op);
switch( o->op ) {
case OInt:
H32(o->p1);
H32(c->ints[o->p2]);
break;
case OFloat:
H32(o->p1);
H32( ((int*)c->floats)[o->p2<<1] );
H32( ((int*)c->floats)[(o->p2<<1)|1] );
break;
case OString:
H32(o->p1);
HSTR(c->strings[o->p2]);
break;
//case OBytes:
case OType:
H32(o->p1);
HTYPE(c->types + o->p2);
break;
case OCall0:
H32(o->p1);
HFUN(o->p2);
break;
case OCall1:
H32(o->p1);
HFUN(o->p2);
H32(o->p3);
break;
case OCall2:
H32(o->p1);
HFUN(o->p2);
H32(o->p3);
H32((int)(int_val)o->extra);
break;
case OCall3:
H32(o->p1);
HFUN(o->p2);
H32(o->p3);
H32(o->extra[0]);
H32(o->extra[1]);
break;
case OCall4:
H32(o->p1);
HFUN(o->p2);
H32(o->p3);
H32(o->extra[0]);
H32(o->extra[1]);
H32(o->extra[2]);
break;
case OCallN:
H32(o->p1);
HFUN(o->p2);
H32(o->p3);
for(i=0;i<o->p3;i++)
H32(o->extra[i]);
break;
case OStaticClosure:
H32(o->p1);
HFUN(o->p2);
break;
case OInstanceClosure:
H32(o->p1);
HFUN(o->p2);
H32(o->p3);
break;
case ODynGet:
H32(o->p1);
H32(o->p2);
HSTR(c->strings[o->p3]);
break;
case ODynSet:
H32(o->p1);
HSTR(c->strings[o->p2]);
H32(o->p3);
break;
default:
switch( hl_op_nargs[o->op] ) {
case 0:
break;
case 1:
H32(o->p1);
break;
case 2:
H32(o->p1);
H32(o->p2);
break;
case 3:
H32(o->p1);
H32(o->p2);
H32(o->p3);
break;
case 4:
H32(o->p1);
H32(o->p2);
H32(o->p3);
H32((int)(int_val)o->extra);
break;
case -1:
switch( o->op ) {
case OCallN:
case OCallClosure:
case OCallMethod:
case OCallThis:
case OMakeEnum:
H32(o->p1);
H32(o->p2);
H32(o->p3);
for(i=0;i<o->p3;i++)
H32(o->extra[i]);
break;
case OSwitch:
H32(o->p1);
H32(o->p2);
for(i=0;i<o->p2;i++)
H32(o->extra[i]);
H32(o->p3);
break;
default:
printf("Don't know how to process opcode %d",o->op);
break;
}
break;
default:
{
int size = hl_op_nargs[o->op] - 3;
H32(o->p1);
H32(o->p2);
H32(o->p3);
for(i=0;i<size;i++)
H32(o->extra[i]);
}
break;
}
}
}
return hash;
}
int hl_code_hash_type( hl_code_hash *h, hl_type *t ) {
int hash = -1;
HTYPE(t);
return hash;
}
hl_code_hash *hl_code_hash_alloc( hl_code *c ) {
int i;
hl_code_hash *h = malloc(sizeof(hl_code_hash));
memset(h,0,sizeof(hl_code_hash));
h->code = c;
h->functions_indexes = malloc(sizeof(int) * (c->nfunctions + c->nnatives));
for(i=0;i<c->nfunctions;i++) {
hl_function *f = c->functions + i;
h->functions_indexes[f->findex] = i;
}
for(i=0;i<c->nnatives;i++) {
hl_native *n = c->natives + i;
h->functions_indexes[n->findex] = i + c->nfunctions;
}
h->types_hashes = malloc(sizeof(int) * c->ntypes);
for(i=0;i<c->ntypes;i++)
h->types_hashes[i] = hash_type_first(c->types + i, false);
int *types_hashes = malloc(sizeof(int) * c->ntypes); // use a second buffer for order-indepedent
for(i=0;i<c->ntypes;i++)
types_hashes[i] = h->types_hashes[i] ^ hash_type_rec(h, c->types + i);
free(h->types_hashes);
h->types_hashes = types_hashes;
h->globals_signs = malloc(sizeof(int) * c->nglobals);
for(i=0;i<c->nglobals;i++) {
hl_type *t = c->globals[i];
h->globals_signs[i] = i | 0x80000000;
if( t->kind == HABSTRACT )
h->globals_signs[i] = hl_code_hash_type(h,t); // some global abstracts allocated by compiler
}
for(i=0;i<c->ntypes;i++) {
hl_type *t = c->types + i;
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
if( t->obj->global_value )
h->globals_signs[(int)(int_val)t->obj->global_value - 1] = hl_code_hash_type(h,t);
break;
case HENUM:
if( t->tenum->global_value )
h->globals_signs[(int)(int_val)t->tenum->global_value - 1] = hl_code_hash_type(h,t);
break;
default:
break;
}
}
for(i=0;i<c->nconstants;i++) {
hl_constant *k = c->constants + i;
hl_type *t = c->globals[k->global];
int hash = -1;
int j;
for(j=0;j<k->nfields;j++) {
int index = k->fields[j];
switch( t->obj->fields[j].t->kind ) {
case HI32:
H32(c->ints[index]);
break;
case HBYTES:
HSTR(c->strings[index]);
break;
default:
break;
}
}
h->globals_signs[k->global] = hash;
}
// look into boot code to identify globals that are constant enum constructors
// this is a bit hackish but we need them for remap and there's no metatada
hl_function *f = c->functions + h->functions_indexes[c->entrypoint];
for(i=4;i<f->nops;i++) {
hl_opcode *op = f->ops + i;
hl_type *t;
switch( op->op ) {
case OSetGlobal:
t = c->globals[op->p1];
if( t->kind == HENUM && f->ops[i-2].op == OGetArray && f->ops[i-3].op == OInt )
h->globals_signs[op->p1] = c->ints[f->ops[i-3].p2];
break;
default:
break;
}
}
for(i=0;i<c->nglobals;i++)
h->globals_signs[i] ^= hl_code_hash_type(h,c->globals[i]);
return h;
}
void hl_code_hash_remap_globals( hl_code_hash *hnew, hl_code_hash *hold ) {
hl_code *c = hnew->code;
int i;
int old_start = 0;
int count = c->nglobals;
int old_count = hold->code->nglobals;
int extra = old_count - count;
if( extra < 0 ) extra = 0;
int *remap = malloc(sizeof(int) * count);
for(i=0;i<count;i++) {
int k;
int h = hnew->globals_signs[i];
remap[i] = -1;
for(k=old_start;k<old_count;k++) {
if( hold->globals_signs[k] == h ) {
if( k == old_start ) old_start++;
remap[i] = k;
break;
}
}
}
// new globals
for(i=0;i<count;i++)
if( remap[i] == -1 )
remap[i] = old_count + extra++;
hl_type **nglobals;
int new_count = old_count + extra;
ALLOC(nglobals,hl_type*,new_count);
for(i=0;i<new_count;i++)
nglobals[i] = i < old_count ? hold->code->globals[i] : &hlt_void;
for(i=0;i<count;i++)
nglobals[remap[i]] = c->globals[i];
c->globals = nglobals;
c->nglobals = new_count;
# ifdef HL_DEBUG
for(i=old_count;i<new_count;i++) {
hl_type *t = c->globals[i];
uprintf(USTR("New global %s\n"),hl_type_str(t));
}
# endif
int *nsigns = malloc(sizeof(int) * c->nglobals);
for(i=0;i<new_count;i++)
nsigns[i] = i < old_count ? hold->globals_signs[i] : -1;
for(i=0;i<count;i++)
nsigns[remap[i]] = hnew->globals_signs[i];
free(hnew->globals_signs);
hnew->globals_signs = nsigns;
for(i=0;i<c->ntypes;i++) {
hl_type *t = c->types + i;
switch( t->kind ) {
case HSTRUCT:
case HOBJ:
if( t->obj->global_value )
t->obj->global_value = (void*)(int_val)(remap[(int)(int_val)t->obj->global_value - 1] + 1);
break;
case HENUM:
if( t->tenum->global_value )
t->tenum->global_value = (void*)(int_val)(remap[(int)(int_val)t->tenum->global_value - 1] + 1);
break;
default:
break;
}
}
for(i=0;i<c->nconstants;i++)
c->constants[i].global = remap[c->constants[i].global];
for(i=0;i<c->nfunctions;i++) {
hl_function *f = c->functions + i;
int k;
for(k=0;k<f->nops;k++) {
hl_opcode *op = f->ops + k;
switch( op->op ) {
case OGetGlobal:
op->p2 = remap[op->p2];
break;
case OSetGlobal:
op->p1 = remap[op->p1];
break;
default:
break;
}
}
}
free(remap);
}
void hl_code_hash_finalize( hl_code_hash *h ) {
hl_code *c = h->code;
int i;
h->functions_signs = malloc(sizeof(int) * (c->nfunctions + c->nnatives));
for(i=0;i<c->nfunctions;i++) {
hl_function *f = c->functions + i;
h->functions_signs[i] = hash_fun_sign(h, f);
}
for(i=0;i<c->nnatives;i++) {
hl_native *n = c->natives + i;
h->functions_signs[i + c->nfunctions] = hash_native(h,n);
}
h->functions_hashes = malloc(sizeof(int) * c->nfunctions);
for(i=0;i<c->nfunctions;i++) {
hl_function *f = c->functions + i;
h->functions_hashes[i] = hash_fun(h,f);
}
}
void hl_code_hash_free( hl_code_hash *h ) {
free(h->functions_hashes);
free(h->functions_indexes);
free(h->functions_signs);
free(h->globals_signs);
free(h->types_hashes);
free(h);
}