浏览代码

more work on hot reload

Nicolas Cannasse 6 年之前
父节点
当前提交
370ca96023
共有 7 个文件被更改,包括 378 次插入75 次删除
  1. 157 1
      src/code.c
  2. 1 0
      src/hl.h
  3. 9 5
      src/hlmodule.h
  4. 64 17
      src/jit.c
  5. 4 3
      src/main.c
  6. 126 48
      src/module.c
  7. 17 1
      src/std/obj.c

+ 157 - 1
src/code.c

@@ -532,4 +532,160 @@ hl_code *hl_code_read( const unsigned char *data, int size, char **error_msg ) {
 
 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); }
+
+int hl_code_hash_fun( hl_code *c, hl_function *f ) {
+	int hash = -1;
+	int k;
+	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;
+		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:
+					{
+						int i;
+						H32(o->p1);
+						H32(o->p2);
+						H32(o->p3);
+						for(i=0;i<o->p3;i++)
+							H32(o->extra[i]);
+					}
+					break;
+				case OSwitch:
+					{
+						int i;
+						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 i, 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 ^ -1;
+}

+ 1 - 0
src/hl.h

@@ -426,6 +426,7 @@ HL_API int hl_pad_struct( int size, hl_type *t );
 
 HL_API hl_runtime_obj *hl_get_obj_rt( hl_type *ot );
 HL_API hl_runtime_obj *hl_get_obj_proto( hl_type *ot );
+HL_API void hl_flush_proto( hl_type *ot );
 HL_API void hl_init_enum( hl_type *et, hl_module_context *m );
 
 /* -------------------- VALUES ------------------------------ */

+ 9 - 5
src/hlmodule.h

@@ -94,6 +94,8 @@ typedef struct {
 	bool large;
 } hl_debug_infos;
 
+typedef struct jit_ctx jit_ctx;
+
 typedef struct {
 	hl_code *code;
 	int codesize;
@@ -101,26 +103,28 @@ typedef struct {
 	unsigned char *globals_data;
 	void **functions_ptrs;
 	int *functions_indexes;
+	int *functions_hashes;
 	void *jit_code;
 	hl_debug_infos *jit_debug;
+	jit_ctx *jit_ctx;
 	hl_module_context ctx;
 } hl_module;
 
-typedef struct jit_ctx jit_ctx;
-
 hl_code *hl_code_read( const unsigned char *data, int size, char **error_msg );
+int hl_code_hash_fun( hl_code *c, hl_function *f );
 void hl_code_free( hl_code *c );
 const uchar *hl_get_ustring( hl_code *c, int index );
 const char* hl_op_name( int op );
 
 hl_module *hl_module_alloc( hl_code *code );
 int hl_module_init( hl_module *m, bool hot_reload );
-void hl_module_patch( hl_module *m, hl_code *code );
+bool hl_module_patch( hl_module *m, hl_code *code );
 void hl_module_free( hl_module *m );
 bool hl_module_debug( hl_module *m, int port, bool wait );
 
 jit_ctx *hl_jit_alloc();
-void hl_jit_free( jit_ctx *ctx );
+void hl_jit_free( jit_ctx *ctx, bool can_reset );
+void hl_jit_reset( jit_ctx *ctx, hl_module *m );
 void hl_jit_init( jit_ctx *ctx, hl_module *m );
 int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f );
-void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **debug );
+void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **debug, hl_module *previous );

+ 64 - 17
src/jit.c

@@ -297,7 +297,7 @@ struct jit_ctx {
 	int c2hl;
 	int hl2c;
 	int longjump;
-	int static_functions[8];
+	void *static_functions[8];
 };
 
 #define jit_exit() { hl_debug_break(); exit(-1); }
@@ -2205,13 +2205,23 @@ jit_ctx *hl_jit_alloc() {
 	return ctx;
 }
 
-void hl_jit_free( jit_ctx *ctx ) {
+void hl_jit_free( jit_ctx *ctx, bool can_reset ) {
 	free(ctx->vregs);
 	free(ctx->opsPos);
 	free(ctx->startBuf);
+	ctx->maxRegs = 0;
+	ctx->vregs = NULL;
+	ctx->maxOps = 0;
+	ctx->opsPos = NULL;
+	ctx->startBuf = NULL;
+	ctx->bufSize = 0;
+	ctx->buf.b = NULL;
+	ctx->calls = NULL;
+	ctx->switchs = NULL;
+	ctx->closure_list = NULL;
 	hl_free(&ctx->falloc);
 	hl_free(&ctx->galloc);
-	free(ctx);
+	if( !can_reset ) free(ctx);
 }
 
 static void jit_nops( jit_ctx *ctx ) {
@@ -2601,7 +2611,7 @@ static int jit_build( jit_ctx *ctx, void (*fbuild)( jit_ctx *) ) {
 	return pos;
 }
 
-void hl_jit_init( jit_ctx *ctx, hl_module *m ) {
+static void hl_jit_init_module( jit_ctx *ctx, hl_module *m ) {
 	int i;
 	ctx->m = m;
 	if( m->code->hasdebug )
@@ -2610,13 +2620,22 @@ void hl_jit_init( jit_ctx *ctx, hl_module *m ) {
 		jit_buf(ctx);
 		*ctx->buf.d++ = m->code->floats[i];
 	}
+}
+
+void hl_jit_init( jit_ctx *ctx, hl_module *m ) {
+	hl_jit_init_module(ctx,m);
 	ctx->c2hl = jit_build(ctx, jit_c2hl);
 	ctx->hl2c = jit_build(ctx, jit_hl2c);
 #	ifdef JIT_CUSTOM_LONGJUMP
 	ctx->longjump = jit_build(ctx, jit_longjump);
 #	endif
-	ctx->static_functions[0] = jit_build(ctx,jit_null_access);
-	ctx->static_functions[1] = jit_build(ctx,jit_assert);
+	ctx->static_functions[0] = (void*)(int_val)jit_build(ctx,jit_null_access);
+	ctx->static_functions[1] = (void*)(int_val)jit_build(ctx,jit_assert);
+}
+
+void hl_jit_reset( jit_ctx *ctx, hl_module *m ) {
+	ctx->debug = NULL;
+	hl_jit_init_module(ctx,m);
 }
 
 static void *get_dyncast( hl_type *t ) {
@@ -4083,7 +4102,7 @@ static void *get_wrapper( hl_type *t ) {
 	return call_jit_hl2c;
 }
 
-void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **debug ) {
+void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **debug, hl_module *previous ) {
 	jlist *c;
 	int size = BUF_POS();
 	unsigned char *code;
@@ -4093,17 +4112,48 @@ void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **d
 	memcpy(code,ctx->startBuf,BUF_POS());
 	*codesize = size;
 	*debug = ctx->debug;
-	call_jit_c2hl = code + ctx->c2hl;
-	call_jit_hl2c = code + ctx->hl2c;
-	hl_setup_callbacks(callback_c2hl, get_wrapper);
+	if( !call_jit_c2hl ) {
+		call_jit_c2hl = code + ctx->c2hl;
+		call_jit_hl2c = code + ctx->hl2c;
+		hl_setup_callbacks(callback_c2hl, get_wrapper);
+#		ifdef JIT_CUSTOM_LONGJUMP
+		hl_setup_longjump(code + ctx->longjump);
+#		endif
+		int i;
+		for(i=0;i<sizeof(ctx->static_functions)/sizeof(void*);i++)
+			ctx->static_functions[i] = (void*)(code + (int)(int_val)ctx->static_functions[i]);
+	} else {
+		if( ctx->calls )
+			printf("TODO:CALLS\n");
+		if( ctx->closure_list )
+			printf("TODO:CALLS\n");
+	}
 	// patch calls
 	c = ctx->calls;
 	while( c ) {
-		int fpos = c->target < 0 ? ctx->static_functions[-c->target-1] : (int)(int_val)m->functions_ptrs[c->target];
+		int_val fabs;
+		if( c->target < 0 )
+			fabs = (int_val)ctx->static_functions[-c->target-1];
+		else {
+			fabs = (int_val)m->functions_ptrs[c->target];
+			if( fabs == 0 ) {
+				// todo : read absolute address from previous module
+				return NULL;
+			} else {
+				fabs += (int_val)code;
+			}
+		}
 		if( (code[c->pos]&~3) == (IS_64?0x48:0xB8) || code[c->pos] == 0x68 ) // MOV : absolute | PUSH
-			*(int_val*)(code + c->pos + (IS_64?2:1)) = (int_val)(code + fpos);
-		else
-			*(int*)(code + c->pos + 1) = fpos - (c->pos + 5);
+			*(int_val*)(code + c->pos + (IS_64?2:1)) = fabs;
+		else {
+			int_val delta = fabs - (int_val)code - (c->pos + 5);
+			int rpos = (int)delta;
+			if( (int_val)rpos != delta ) {
+				printf("Target code too far too rebase\n");
+				return NULL;
+			}
+			*(int*)(code + c->pos + 1) = rpos;
+		}
 		c = c->next;
 	}
 	// patch switchs
@@ -4124,9 +4174,6 @@ void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **d
 			c = next;
 		}
 	}
-#	ifdef JIT_CUSTOM_LONGJUMP
-	hl_setup_longjump(code + ctx->longjump);
-#	endif
 	return code;
 }
 

+ 4 - 3
src/main.c

@@ -48,7 +48,7 @@ typedef struct {
 	int file_time;
 } main_context;
 
-static int pfiletime( uchar *file )	{
+static int pfiletime( pchar *file )	{
 #ifdef HL_WIN
 	struct _stat32 st;
 	_wstat32(file,&st);
@@ -90,16 +90,17 @@ static hl_code *load_code( const pchar *file, char **error_msg, bool print_error
 
 static bool check_reload( main_context *m ) {
 	int time = pfiletime(m->file);
+	bool changed;
 	if( time == m->file_time )
 		return false;
 	char *error_msg = NULL;
 	hl_code *code = load_code(m->file, &error_msg, false);
 	if( code == NULL )
 		return false;
-	hl_module_patch(m->m, code);
+	changed = hl_module_patch(m->m, code);
 	m->file_time = time;
 	hl_code_free(code);
-	return true;
+	return changed;
 }
 
 #ifdef HL_VCC

+ 126 - 48
src/module.c

@@ -320,51 +320,8 @@ static void disabled_primitive() {
 	hl_error("This library primitive has been disabled");
 }
 
-int hl_module_init( hl_module *m, bool hot_reload ) {
+static void hl_module_init_indexes( hl_module *m ) {
 	int i;
-	jit_ctx *ctx;
-	// 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]);
-	}
-	// INIT natives
-	{
-		char tmp[256];
-		void *libHandler = NULL;
-		const char *curlib = NULL, *sign;
-		for(i=0;i<m->code->nnatives;i++) {
-			hl_native *n = m->code->natives + i;
-			char *p = tmp;
-			void *f;
-			if( curlib != n->lib ) {
-				curlib = n->lib;
-				libHandler = resolve_library(n->lib);
-			}
-			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 )
-				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);
-		}
-	}
-	// INIT indexes
 	for(i=0;i<m->code->nfunctions;i++) {
 		hl_function *f = m->code->functions + i;
 		m->functions_indexes[f->findex] = i;
@@ -419,6 +376,63 @@ int hl_module_init( hl_module *m, bool hot_reload ) {
 			break;
 		}
 	}
+}
+
+static void hl_module_hash( hl_module *m ) {
+	int i;
+	m->functions_hashes = malloc(sizeof(int) * m->code->nfunctions);
+	for(i=0;i<m->code->nfunctions;i++) {
+		hl_function *f = m->code->functions + i;
+		m->functions_hashes[i] = hl_code_hash_fun(m->code,f);
+	}
+}
+
+int hl_module_init( hl_module *m, bool hot_reload ) {
+	int i;
+	jit_ctx *ctx;
+	// 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]);
+	}
+	// INIT natives
+	{
+		char tmp[256];
+		void *libHandler = NULL;
+		const char *curlib = NULL, *sign;
+		for(i=0;i<m->code->nnatives;i++) {
+			hl_native *n = m->code->natives + i;
+			char *p = tmp;
+			void *f;
+			if( curlib != n->lib ) {
+				curlib = n->lib;
+				libHandler = resolve_library(n->lib);
+			}
+			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 )
+				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);
+		}
+	}
+	// INIT indexes
+	hl_module_init_indexes(m);
 	// JIT
 	ctx = hl_jit_alloc();
 	if( ctx == NULL )
@@ -428,12 +442,12 @@ int hl_module_init( hl_module *m, bool hot_reload ) {
 		hl_function *f = m->code->functions + i;
 		int fpos = hl_jit_function(ctx, m, f);
 		if( fpos < 0 ) {
-			hl_jit_free(ctx);
+			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);
+	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]);
@@ -495,11 +509,72 @@ int hl_module_init( hl_module *m, bool hot_reload ) {
 
 	hl_setup_exception(module_resolve_symbol, module_capture_stack);
 	hl_gc_set_dump_types(hl_module_types_dump);
-	hl_jit_free(ctx);
+	hl_jit_free(ctx, hot_reload);
+	if( hot_reload ) {
+		hl_module_hash(m);
+		m->jit_ctx = ctx;
+	}
 	return 1;
 }
 
-void hl_module_patch( hl_module *m, hl_code *c ) {
+bool hl_module_patch( hl_module *m1, hl_code *c ) {
+	int i1,i2;
+	bool has_changes = false;
+	jit_ctx *ctx = m1->jit_ctx;
+
+	hl_module *m2 = hl_module_alloc(c);
+	hl_module_init_indexes(m2);
+	hl_module_hash(m2);
+	
+	hl_jit_reset(ctx, m2);
+
+	for(i2=0;i2<m2->code->nfunctions;i2++) {
+		hl_function *f2 = m2->code->functions + i2;
+		if( f2->obj == NULL ) {
+			m2->functions_hashes[i2] = -1;
+			continue;
+		}
+		for(i1=0;i1<m1->code->nfunctions;i1++) {
+			hl_function *f1 = m1->code->functions + i1;
+			if( f1->obj && ucmp(f1->obj->name, f2->obj->name) == 0 && ucmp(f1->field,f2->field) == 0 ) {
+				int hash1 = m1->functions_hashes[i1];
+				int hash2 = m2->functions_hashes[i2];
+				if( hash1 == hash2 )
+					break;
+				uprintf(USTR("%s.%s has been modified\n"), f1->obj->name, f1->field);
+				m1->functions_hashes[i1] = hash2; // update hash
+				int fpos = hl_jit_function(ctx, m2, f2);
+				if( fpos < 0 ) break;
+				m2->functions_ptrs[f2->findex] = (void*)(int_val)fpos;
+				has_changes = true;
+				break;
+			}
+		}
+		m2->functions_hashes[i2] = i1 == m1->code->nfunctions ? -1 : i1;
+	}
+	if( !has_changes ) {
+		printf("No changes found\n");
+		hl_jit_free(ctx, true);
+		return false;
+	}
+	m2->jit_code = hl_jit_code(ctx, m2, &m2->codesize, &m2->jit_debug, m1);
+	
+	int i;
+	for(i=0;i<m2->code->nfunctions;i++) {
+		hl_function *f2 = m2->code->functions + i;
+		if( m2->functions_hashes[i] < 0 ) continue;
+		if( (int_val)m2->functions_ptrs[f2->findex] == 0 ) 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
+		hl_function *f1 = m1->code->functions + m2->functions_hashes[i];
+		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 ) hl_flush_proto(t);
+	}
+	return true;
 }
 
 void hl_module_free( hl_module *m ) {
@@ -510,11 +585,14 @@ void hl_module_free( hl_module *m ) {
 	free(m->ctx.functions_types);
 	free(m->globals_indexes);
 	free(m->globals_data);
+	free(m->functions_hashes);
 	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);
 }

+ 17 - 1
src/std/obj.c

@@ -385,7 +385,23 @@ HL_API hl_runtime_obj *hl_get_obj_proto( hl_type *ot ) {
 	return t;
 }
 
-void hl_init_virtual( hl_type *vt, hl_module_context *ctx ) {
+HL_API void hl_flush_proto( hl_type *ot ) {
+	int i;
+	hl_type_obj *o = ot->obj;
+	hl_runtime_obj *rt = ot->obj->rt;
+	hl_module_context *m = o->m;
+	if( !rt ) return;
+	for(i=0;i<o->nbindings;i++) {
+		hl_runtime_binding *b = rt->bindings + i;
+		int mid = o->bindings[(i<<1)|1];
+		if( b->closure )
+			b->ptr = m->functions_ptrs[mid];
+		else
+			((vclosure*)b->ptr)->fun = m->functions_ptrs[mid];
+	}
+}
+
+HL_API void hl_init_virtual( hl_type *vt, hl_module_context *ctx ) {
 	int i;
 	int vsize = sizeof(vvirtual) + sizeof(void*) * vt->virt->nfields;
 	int size = vsize;