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

864 lines
25 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 <hl.h>
#include <hlmodule.h>
#ifdef HL_WIN
# include <windows.h>
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
# define dlopen(l,p) (void*)( (l) ? LoadLibraryA(l) : (HMODULE)&__ImageBase)
# define dlsym(h,n) GetProcAddress((HANDLE)h,n)
#else
# include <dlfcn.h>
#endif
#define HOT_RELOAD_EXTRA_GLOBALS 4096
HL_API void hl_prim_not_loaded( const uchar *err );
static hl_module **cur_modules = NULL;
static int modules_count = 0;
static bool module_resolve_pos( hl_module *m, void *addr, int *fidx, int *fpos ) {
int code_pos = ((int)(int_val)((unsigned char*)addr - (unsigned char*)m->jit_code));
int min, max;
hl_debug_infos *dbg;
hl_function *fdebug;
if( m->jit_debug == NULL )
return false;
// lookup function from code pos
min = 0;
max = m->code->nfunctions;
while( min < max ) {
int mid = (min + max) >> 1;
hl_debug_infos *p = m->jit_debug + mid;
if( p->start <= code_pos )
min = mid + 1;
else
max = mid;
}
if( min == 0 )
return false; // hl_callback
do {
min--;
*fidx = min;
dbg = m->jit_debug + min;
fdebug = m->code->functions + min;
} while( !dbg->offsets );
// lookup inside function
min = 0;
max = fdebug->nops;
code_pos -= dbg->start;
while( min < max ) {
int mid = (min + max) >> 1;
int offset = dbg->large ? ((int*)dbg->offsets)[mid] : ((unsigned short*)dbg->offsets)[mid];
if( offset <= code_pos )
min = mid + 1;
else
max = mid;
}
if( min == 0 )
return false; // ???
*fpos = min - 1;
return true;
}
uchar *hl_module_resolve_symbol_full( void *addr, uchar *out, int *outSize, int **r_debug_addr ) {
int *debug_addr;
int file, line;
int pos = 0;
int fidx, fpos;
hl_function *fdebug;
int i;
hl_module *m = NULL;
for(i=0;i<modules_count;i++) {
m = cur_modules[i];
if( addr >= m->jit_code && addr <= (void*)((char*)m->jit_code + m->codesize) ) break;
}
if( i == modules_count )
return NULL;
if( !module_resolve_pos(m,addr,&fidx,&fpos) )
return NULL;
// extract debug info
fdebug = m->code->functions + fidx;
debug_addr = fdebug->debug + ((fpos&0xFFFF) * 2);
file = debug_addr[0];
line = debug_addr[1];
if( r_debug_addr ) {
*r_debug_addr = debug_addr;
if( file < 0 ) return NULL; // already cached
}
if( !out )
return NULL;
int size = *outSize;
if( fdebug->obj )
pos += usprintf(out,size - pos,USTR("%s.%s("),fdebug->obj->name,fdebug->field.name);
else if( fdebug->field.ref )
pos += usprintf(out,size - pos,USTR("%s.~%s.%d("),fdebug->field.ref->obj->name, fdebug->field.ref->field.name, fdebug->ref);
else
pos += usprintf(out,size - pos,USTR("fun$%d("),fdebug->findex);
pos += hl_from_utf8(out + pos,size - pos,m->code->debugfiles[file&0x7FFFFFFF]);
pos += usprintf(out + pos, size - pos, USTR(":%d)"), line);
*outSize = pos;
return out;
}
static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
return hl_module_resolve_symbol_full(addr,out,outSize,NULL);
}
int hl_module_capture_stack_range( void *stack_top, void **stack_ptr, void **out, int size ) {
#if defined(HL_64) && defined(HL_WIN)
#else
void *stack_bottom = stack_ptr;
#endif
int count = 0;
if( modules_count == 1 ) {
hl_module *m = cur_modules[0];
unsigned char *code = m->jit_code;
int code_size = m->codesize;
if( m->jit_debug ) {
int s = m->jit_debug[0].start;
code += s;
code_size -= s;
}
while( stack_ptr < (void**)stack_top ) {
#if defined(HL_64) && defined(HL_WIN)
void *module_addr = *stack_ptr++; // EIP
if( module_addr >= (void*)code && module_addr < (void*)(code + code_size) ) {
if( out ) {
if( count == size ) break;
out[count++] = module_addr;
} else
count++;
}
#else
void *stack_addr = *stack_ptr++; // EBP
if( stack_addr > stack_bottom && stack_addr < stack_top ) {
void *module_addr = *stack_ptr; // EIP
if( module_addr >= (void*)code && module_addr < (void*)(code + code_size) ) {
if( out ) {
if( count == size ) break;
out[count++] = module_addr;
} else {
count++;
}
}
}
#endif
}
} else {
while( stack_ptr < (void**)stack_top ) {
#if defined(HL_64) && defined(HL_WIN)
void *module_addr = *stack_ptr++; // EIP
{
#else
void *stack_addr = *stack_ptr++; // EBP
if( stack_addr > stack_bottom && stack_addr < stack_top ) {
void *module_addr = *stack_ptr; // EIP
#endif
int i;
for(i=0;i<modules_count;i++) {
hl_module *m = cur_modules[i];
unsigned char *code = m->jit_code;
int code_size = m->codesize;
if( module_addr >= (void*)code && module_addr < (void*)(code + code_size) ) {
if( out && count == size ) {
stack_ptr = stack_top;
break;
}
if( m->jit_debug ) {
int s = m->jit_debug[0].start;
code += s;
code_size -= s;
if( module_addr < (void*)code || module_addr >= (void*)(code + code_size) ) continue;
}
if( out )
out[count++] = module_addr;
else
count++;
break;
}
}
}
}
}
return count;
}
static int module_capture_stack( void **stack, int size ) {
return hl_module_capture_stack_range(hl_get_thread()->stack_top, (void**)&stack, stack, size);
}
static void hl_module_types_dump( void (*fdump)( void *, int) ) {
int ntypes = 0;
int i, j, fcount = 0;
for(i=0;i<modules_count;i++)
ntypes += cur_modules[i]->code->ntypes;
fdump(&ntypes,4);
for(i=0;i<modules_count;i++) {
hl_module *m = cur_modules[i];
for(j=0;j<m->code->ntypes;j++) {
hl_type *t = m->code->types + j;
fdump(&t,sizeof(void*));
if( t->kind == HFUN ) fcount++;
}
}
fdump(&fcount,4);
for(i=0;i<modules_count;i++) {
hl_module *m = cur_modules[i];
for(j=0;j<m->code->ntypes;j++) {
hl_type *t = m->code->types + j;
if( t->kind == HFUN ) {
hl_type *ct = (hl_type*)&t->fun->closure_type;
fdump(&ct,sizeof(void*));
}
}
}
}
hl_module *hl_module_alloc( hl_code *c ) {
int i;
int gsize = 0;
hl_module *m = (hl_module*)malloc(sizeof(hl_module));
if( m == NULL )
return NULL;
memset(m,0,sizeof(hl_module));
m->code = c;
m->globals_indexes = (int*)malloc(sizeof(int)*c->nglobals);
if( m->globals_indexes == NULL ) {
hl_module_free(m);
return NULL;
}
for(i=0;i<c->nglobals;i++) {
gsize += hl_pad_size(gsize, c->globals[i]);
m->globals_indexes[i] = gsize;
gsize += hl_type_size(c->globals[i]);
}
m->globals_size = gsize;
m->globals_data = (unsigned char*)malloc(gsize);
if( m->globals_data == NULL ) {
hl_module_free(m);
return NULL;
}
memset(m->globals_data,0,gsize);
m->functions_ptrs = (void**)malloc(sizeof(void*)*(c->nfunctions + c->nnatives));
m->functions_indexes = (int*)malloc(sizeof(int)*(c->nfunctions + c->nnatives));
m->ctx.functions_types = (hl_type**)malloc(sizeof(void*)*(c->nfunctions + c->nnatives));
if( m->functions_ptrs == NULL || m->functions_indexes == NULL || m->ctx.functions_types == NULL ) {
hl_module_free(m);
return NULL;
}
memset(m->functions_ptrs,0,sizeof(void*)*(c->nfunctions + c->nnatives));
memset(m->functions_indexes,0xFF,sizeof(int)*(c->nfunctions + c->nnatives));
memset(m->ctx.functions_types,0,sizeof(void*)*(c->nfunctions + c->nnatives));
hl_alloc_init(&m->ctx.alloc);
m->ctx.functions_ptrs = m->functions_ptrs;
return m;
}
static void null_function() {
hl_error("Null function ptr");
}
static void append_fields( char **p, hl_type *t );
static void append_type( char **p, hl_type *t ) {
*(*p)++ = TYPE_STR[t->kind];
switch( t->kind ) {
case HFUN:
{
int i;
for(i=0;i<t->fun->nargs;i++)
append_type(p,t->fun->args[i]);
*(*p)++ = '_';
append_type(p,t->fun->ret);
break;
}
case HREF:
case HNULL:
append_type(p,t->tparam);
break;
case HOBJ:
{
append_fields(p, t);
*(*p)++ = '_';
}
break;
case HABSTRACT:
*p += utostr(*p,100,t->abs_name);
*(*p)++ = '_';
break;
default:
break;
}
}
static void append_fields( char **p, hl_type *t ) {
int i;
if( t->obj->super )
append_fields(p, t->obj->super);
for(i=0;i<t->obj->nfields;i++)
append_type(p,t->obj->fields[i].t);
}
#define DISABLED_LIB_PTR ((void*)(int_val)2)
static void *resolve_library( const char *lib, bool is_opt ) {
char tmp[256];
void *h;
# ifndef HL_CONSOLE
static char *DISABLED_LIBS = NULL;
if( !DISABLED_LIBS ) {
DISABLED_LIBS = getenv("HL_DISABLED_LIBS");
if( !DISABLED_LIBS ) DISABLED_LIBS = "";
}
char *disPart = strstr(DISABLED_LIBS, lib);
if( disPart ) {
disPart += strlen(lib);
if( *disPart == 0 || *disPart == ',' )
return DISABLED_LIB_PTR;
}
# endif
if( strcmp(lib,"builtin") == 0 )
return dlopen(NULL,RTLD_LAZY);
if( strcmp(lib,"std") == 0 ) {
# ifdef HL_WIN
# ifdef HL_64
h = dlopen("libhl64.dll",RTLD_LAZY);
if( h == NULL ) h = dlopen("libhl.dll",RTLD_LAZY);
# else
h = dlopen("libhl.dll",RTLD_LAZY);
# endif
if( h == NULL && !is_opt ) hl_fatal1("Failed to load library %s","libhl.dll");
return h;
# else
return RTLD_DEFAULT;
# endif
}
strcpy(tmp,lib);
# ifdef HL_64
strcpy(tmp+strlen(lib),"64.hdll");
h = dlopen(tmp,RTLD_LAZY);
if( h != NULL ) return h;
# endif
strcpy(tmp+strlen(lib),".hdll");
h = dlopen(tmp,RTLD_LAZY);
if( h == NULL && !is_opt )
hl_fatal1("Failed to load library %s",tmp);
return h;
}
static void disabled_primitive() {
hl_error("This library primitive has been disabled");
}
static void hl_module_init_indexes( hl_module *m ) {
int i;
for(i=0;i<m->code->nfunctions;i++) {
hl_function *f = m->code->functions + i;
m->functions_indexes[f->findex] = i;
m->ctx.functions_types[f->findex] = f->type;
}
for(i=0;i<m->code->nnatives;i++) {
hl_native *n = m->code->natives + i;
m->functions_indexes[n->findex] = i + m->code->nfunctions;
m->ctx.functions_types[n->findex] = n->t;
}
for(i=0;i<m->code->ntypes;i++) {
hl_type *t = m->code->types + i;
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
t->obj->m = &m->ctx;
t->obj->global_value = ((int)(int_val)t->obj->global_value) ? (void**)(int_val)(m->globals_data + m->globals_indexes[(int)(int_val)t->obj->global_value-1]) : NULL;
{
int j;
for(j=0;j<t->obj->nproto;j++) {
hl_obj_proto *p = t->obj->proto + j;
hl_function *f = m->code->functions + m->functions_indexes[p->findex];
f->obj = t->obj;
f->field.name = p->name;
}
for(j=0;j<t->obj->nbindings;j++) {
int fid = t->obj->bindings[j<<1];
int mid = t->obj->bindings[(j<<1)|1];
hl_obj_field *of = hl_obj_field_fetch(t,fid);
switch( of->t->kind ) {
case HFUN:
case HDYN:
{
hl_function *f = m->code->functions + m->functions_indexes[mid];
f->obj = t->obj;
f->field.name = of->name;
}
break;
default:
break;
}
}
}
break;
case HENUM:
hl_init_enum(t,&m->ctx);
t->tenum->global_value = ((int)(int_val)t->tenum->global_value) ? (void**)(int_val)(m->globals_data + m->globals_indexes[(int)(int_val)t->tenum->global_value-1]) : NULL;
break;
case HVIRTUAL:
hl_init_virtual(t,&m->ctx);
break;
default:
break;
}
}
for(i=0;i<m->code->nfunctions;i++) {
int k;
hl_function *f = m->code->functions + i;
hl_function *real_f = f;
while( real_f && !real_f->obj ) real_f = real_f->field.ref;
if( real_f == NULL ) continue;
for(k=0;k<f->nops;k++) {
hl_opcode *op = f->ops + k;
switch( op->op ) {
case OCall0:
case OCall1:
case OCall2:
case OCall3:
case OCall4:
case OCallN:
case OStaticClosure:
case OInstanceClosure:
if( m->functions_indexes[op->p2] < m->code->nfunctions ) {
hl_function *floc = m->code->functions + m->functions_indexes[op->p2];
if( floc->obj ) continue;
floc->field.ref = real_f;
floc->ref = real_f->ref++;
}
break;
default:
break;
}
}
}
static hl_type_obj obj_entry = {0};
hl_function *fent = m->code->functions + m->functions_indexes[m->code->entrypoint];
obj_entry.name = USTR("");
fent->obj = &obj_entry;
fent->field.name = USTR("init");
}
static void hl_module_init_natives( hl_module *m ) {
char tmp[256];
int i;
void *libHandler = NULL;
const char *curlib = NULL, *sign;
for(i=0;i<m->code->nnatives;i++) {
hl_native *n = m->code->natives + i;
const char *lib = n->lib;
bool is_opt = *lib == '?';
char *p = tmp;
void *f;
if( is_opt ) lib++;
if( curlib != lib ) {
curlib = lib;
libHandler = resolve_library(lib, is_opt);
}
if( libHandler == DISABLED_LIB_PTR ) {
m->functions_ptrs[n->findex] = disabled_primitive;
continue;
}
strcpy(p,"hlp_");
p += 4;
strcpy(p,n->name);
p += strlen(n->name);
*p++ = 0;
f = dlsym(libHandler,tmp);
if( f == NULL ) {
if( is_opt ) {
m->functions_ptrs[n->findex] = hl_prim_not_loaded;
continue;
}
hl_fatal2("Failed to load function %s@%s",n->lib,n->name);
}
m->functions_ptrs[n->findex] = ((void *(*)( const char **p ))f)(&sign);
p = tmp;
append_type(&p,n->t);
*p++ = 0;
if( memcmp(sign,tmp,strlen(sign)+1) != 0 )
hl_fatal4("Invalid signature for function %s@%s : %s required but %s found in hdll",n->lib,n->name,tmp,sign);
}
}
static void hl_module_init_constant( hl_module *m, hl_constant *c ) {
hl_type *t = m->code->globals[c->global];
hl_runtime_obj *rt;
vdynamic **global = (vdynamic**)(m->globals_data + m->globals_indexes[c->global]);
vdynamic *v = NULL;
switch (t->kind) {
case HOBJ:
case HSTRUCT:
rt = hl_get_obj_rt(t);
v = (vdynamic*)hl_malloc(&m->ctx.alloc,rt->size);
v->t = t;
for(int i=0;i<c->nfields;i++) {
int idx = c->fields[i];
hl_type *ft = t->obj->fields[i].t;
void *addr = (char*)v + rt->fields_indexes[i];
switch (ft->kind) {
case HI32:
*(int*)addr = m->code->ints[idx];
break;
case HBOOL:
*(bool*)addr = idx != 0;
break;
case HF64:
*(double*)addr = m->code->floats[idx];
break;
case HBYTES:
*(const void**)addr = hl_get_ustring(m->code, idx);
break;
case HTYPE:
*(hl_type**)addr = m->code->types + idx;
break;
default:
*(void**)addr = *(void**)(m->globals_data + m->globals_indexes[idx]);
break;
}
}
break;
default:
hl_fatal("assert");
}
*global = v;
hl_remove_root(global);
}
static void hl_module_add( hl_module *m ) {
hl_module **old_modules = cur_modules;
hl_module **new_modules = (hl_module**)malloc(sizeof(void*)*(modules_count + 1));
memcpy(new_modules, old_modules, sizeof(void*)*modules_count);
new_modules[modules_count] = m;
cur_modules = new_modules;
modules_count++;
free(old_modules);
}
int hl_module_init( hl_module *m, h_bool hot_reload ) {
int i;
jit_ctx *ctx;
// expand globals
if( hot_reload ) {
int nsize = m->globals_size + HOT_RELOAD_EXTRA_GLOBALS * sizeof(void*);
int *nindexes = malloc(sizeof(int) * (m->code->nglobals + HOT_RELOAD_EXTRA_GLOBALS));
memcpy(nindexes,m->globals_indexes,sizeof(int)*m->code->nglobals);
memset(nindexes + m->code->nglobals,0xFF,HOT_RELOAD_EXTRA_GLOBALS * sizeof(int));
free(m->globals_indexes);
free(m->globals_data);
m->globals_indexes = nindexes;
m->globals_data = malloc(nsize);
memset(m->globals_data,0,m->globals_size);
memset(m->globals_data + m->globals_size,0xFF,HOT_RELOAD_EXTRA_GLOBALS * sizeof(void*));
}
// RESET globals
for(i=0;i<m->code->nglobals;i++) {
hl_type *t = m->code->globals[i];
if( t->kind == HFUN ) *(void**)(m->globals_data + m->globals_indexes[i]) = null_function;
if( hl_is_ptr(t) )
hl_add_root(m->globals_data+m->globals_indexes[i]);
}
// inits
if( hot_reload ) m->hash = hl_code_hash_alloc(m->code);
hl_module_init_natives(m);
hl_module_init_indexes(m);
// JIT
ctx = hl_jit_alloc();
if( ctx == NULL )
return 0;
hl_jit_init(ctx, m);
for(i=0;i<m->code->nfunctions;i++) {
hl_function *f = m->code->functions + i;
int fpos = hl_jit_function(ctx, m, f);
if( fpos < 0 ) {
hl_jit_free(ctx, false);
return 0;
}
m->functions_ptrs[f->findex] = (void*)(int_val)fpos;
}
m->jit_code = hl_jit_code(ctx, m, &m->codesize, &m->jit_debug, NULL);
for(i=0;i<m->code->nfunctions;i++) {
hl_function *f = m->code->functions + i;
m->functions_ptrs[f->findex] = ((unsigned char*)m->jit_code) + ((int_val)m->functions_ptrs[f->findex]);
}
// INIT constants
for(i=0;i<m->code->nconstants;i++) {
hl_constant *c = m->code->constants + i;
hl_module_init_constant(m, c);
}
hl_module_add(m);
hl_setup_exception(module_resolve_symbol, module_capture_stack);
hl_gc_set_dump_types(hl_module_types_dump);
hl_jit_free(ctx, hot_reload);
if( hot_reload ) {
hl_code_hash_finalize(m->hash);
m->jit_ctx = ctx;
}
return 1;
}
h_bool hl_module_patch( hl_module *m1, hl_code *c ) {
int i,i1,i2;
bool has_changes = false;
int changes_count = 0;
jit_ctx *ctx = m1->jit_ctx;
hl_module *m2 = hl_module_alloc(c);
m2->hash = hl_code_hash_alloc(c);
hl_code_hash_remap_globals(m2->hash,m1->hash);
// share global data
free(m2->globals_data);
free(m2->globals_indexes);
m2->globals_data = m1->globals_data;
m2->globals_indexes = m1->globals_indexes;
int gsize = m1->globals_size;
for(i=m1->code->nglobals;i<m2->code->nglobals;i++) {
hl_type *t = c->globals[i];
gsize += hl_pad_size(gsize, t);
m2->globals_indexes[i] = gsize;
gsize += hl_type_size(t);
if( hl_is_ptr(t) )
hl_add_root(m2->globals_data+m2->globals_indexes[i]);
}
memset(m2->globals_data+m1->globals_size,0,gsize - m1->globals_size);
m2->globals_size = gsize;
hl_module_init_natives(m2);
hl_module_init_indexes(m2);
hl_jit_reset(ctx, m2);
hl_code_hash_finalize(m2->hash);
for(i=0;i<m2->code->nconstants;i++) {
hl_constant *c = m2->code->constants + i;
if( c->global >= m1->code->nglobals )
hl_module_init_constant(m2, c);
}
for(i2=0;i2<m2->code->nfunctions;i2++) {
hl_function *f2 = m2->code->functions + i2;
int sign2 = m2->hash->functions_signs[i2];
if( f2->field.name == NULL ) {
m2->hash->functions_hashes[i2] = -1;
continue;
}
for(i1=0;i1<m1->code->nfunctions;i1++) {
int sign1 = m1->hash->functions_signs[i1];
if( sign1 == sign2 ) {
hl_function *f1 = m1->code->functions + i1;
if( (f1->obj != NULL) != (f2->obj != NULL) || !f1->field.name || !f2->field.name ) {
printf("[HotReload] Signature conflict\n");
continue;
}
if( ucmp(fun_obj(f1)->name,fun_obj(f2)->name) != 0 || ucmp(fun_field_name(f1),fun_field_name(f2)) != 0 ) {
printf("[HotReload] Signature conflict\n");
continue;
}
int hash2 = m2->hash->functions_hashes[i2];
int hash1 = m1->hash->functions_hashes[i1];
m2->hash->functions_hashes[i2] = i1; // index reference
if( hash1 == hash2 )
break;
# ifdef HL_DEBUG
uprintf(USTR("%s."), fun_obj(f1)->name);
uprintf(USTR("%s"), fun_field_name(f1));
if( !f1->obj )
printf("~%d", f1->ref);
printf(" has been modified [%d]\n", f1->nops);
# endif
changes_count++;
m1->hash->functions_hashes[i1] = hash2; // update hash
int fpos = hl_jit_function(ctx, m2, f2);
if( fpos < 0 ) return false;
m2->functions_ptrs[f2->findex] = (void*)(int_val)fpos;
has_changes = true;
break;
}
}
if( i1 == m1->code->nfunctions ) {
// not found (signature changed or new method) : inject new method!
int fpos = hl_jit_function(ctx, m2, f2);
if( fpos < 0 ) return false;
m2->hash->functions_hashes[i2] = -1;
m2->functions_ptrs[f2->findex] = (void*)(int_val)fpos;
# ifdef HL_DEBUG
uprintf(USTR("%s."), fun_obj(f2)->name);
uprintf(USTR("%s"), fun_field_name(f2));
if( !f2->obj )
printf("~%d", f2->ref);
printf(" has been added\n");
# endif
changes_count++;
has_changes = true;
// should be added to m1 functions for later reload?
}
}
if( !has_changes ) {
printf("[HotReload] No changes found\n");
fflush(stdout);
hl_jit_free(ctx, true);
return false;
}
// patch same types
for(i1=0;i1<m1->code->ntypes;i1++) {
hl_type *p = m1->code->types + i1;
switch( p->kind ) {
case HOBJ:
case HSTRUCT:
break;
case HENUM:
if( !p->tenum->global_value ) continue;
break;
default:
continue;
}
for(i2=0;i2<c->ntypes;i2++) {
hl_type *t = c->types + i2;
if( p->kind != t->kind ) continue;
switch( p->kind ) {
case HOBJ:
case HSTRUCT:
if( ucmp(p->obj->name,t->obj->name) != 0 ) continue;
if( hl_code_hash_type(m1->hash,p) == hl_code_hash_type(m2->hash,t) ) {
t->obj = p->obj; // alias the types ! they are different pointers but have the same layout
t->vobj_proto = p->vobj_proto;
} else {
uprintf(USTR("[HotReload] Type %s has changed\n"),t->obj->name);
changes_count++;
}
break;
case HENUM:
if( ucmp(p->tenum->name,t->tenum->name) != 0 ) continue;
if( hl_code_hash_type(m1->hash,p) == hl_code_hash_type(m2->hash,t) ) {
t->tenum = p->tenum; // alias the types ! they are different pointers but have the same layout
} else {
uprintf(USTR("[HotReload] Type %s has changed\n"),t->tenum->name);
changes_count++;
}
break;
default:
break;
}
break;
}
}
m2->jit_code = hl_jit_code(ctx, m2, &m2->codesize, &m2->jit_debug, m1);
// patch missing debug info
int start = -1;
if( m2->jit_debug ) {
for(i=0;i<c->nfunctions;i++) {
if( m2->jit_debug[i].start < 0 ) {
m2->jit_debug[i].start = start;
m2->jit_debug[i].offsets = NULL;
} else {
start = m2->jit_debug[i].start;
}
}
}
hl_jit_free(ctx,true);
if( m2->jit_code == NULL ) {
printf("[HotReload] Couldn't JIT result\n");
fflush(stdout);
return false;
}
for(i=0;i<m2->code->nfunctions;i++) {
hl_function *f2 = m2->code->functions + i;
if( m2->hash->functions_hashes[i] < -1 ) continue;
if( m2->functions_ptrs[f2->findex] == NULL ) continue;
void *ptr = ((unsigned char*)m2->jit_code) + ((int_val)m2->functions_ptrs[f2->findex]);
m2->functions_ptrs[f2->findex] = ptr;
// update real function ptr
if( m2->hash->functions_hashes[i] < 0 ) continue;
hl_function *f1 = m1->code->functions + m2->hash->functions_hashes[i];
hl_jit_patch_method(m1->functions_ptrs[f1->findex], m1->functions_ptrs + f1->findex);
m1->functions_ptrs[f1->findex] = ptr;
}
for(i=0;i<m1->code->ntypes;i++) {
hl_type *t = m1->code->types + i;
if( t->kind == HOBJ || t->kind == HSTRUCT ) hl_flush_proto(t);
}
if( changes_count > 0 ) {
printf("[HotReload] %d changes\n", changes_count);
fflush(stdout);
}
hl_module_add(m2);
// call entry point (will only update types)
if( m2->functions_ptrs[c->entrypoint] ) {
vclosure cl;
cl.t = c->functions[m2->functions_indexes[c->entrypoint]].type;
cl.fun = m2->functions_ptrs[c->entrypoint];
cl.hasValue = 0;
hl_dyn_call(&cl,NULL,0);
}
return true;
}
void hl_module_free( hl_module *m ) {
for(int i=0;i<m->code->nglobals;i++) {
if( hl_is_ptr(m->code->globals[i]) )
hl_remove_root(m->globals_data+m->globals_indexes[i]);
}
hl_free(&m->ctx.alloc);
hl_free_executable_memory(m->code, m->codesize);
if( m->hash ) hl_code_hash_free(m->hash);
free(m->functions_indexes);
free(m->functions_ptrs);
free(m->ctx.functions_types);
free(m->globals_indexes);
free(m->globals_data);
if( m->jit_debug ) {
int i;
for(i=0;i<m->code->nfunctions;i++)
free(m->jit_debug[i].offsets);
free(m->jit_debug);
}
if( m->jit_ctx )
hl_jit_free(m->jit_ctx,false);
free(m);
}