/* * 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 #include #ifdef HL_WIN # include 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 #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= 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;ijit_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;icode->ntypes; fdump(&ntypes,4); for(i=0;icode->ntypes;j++) { hl_type *t = m->code->types + j; fdump(&t,sizeof(void*)); if( t->kind == HFUN ) fcount++; } } fdump(&fcount,4); for(i=0;icode->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;inglobals;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;ifun->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;iobj->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;icode->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;icode->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;icode->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;jobj->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;jobj->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;icode->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;knops;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;icode->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;infields;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;icode->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;icode->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;icode->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;icode->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;icode->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;icode->nconstants;i++) { hl_constant *c = m2->code->constants + i; if( c->global >= m1->code->nglobals ) hl_module_init_constant(m2, c); } for(i2=0;i2code->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;i1code->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;i1code->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;i2ntypes;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;infunctions;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;icode->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;icode->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;icode->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;icode->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); }