浏览代码

more work on hot reload: types hashes, better handling for globals hashes

Nicolas Cannasse 5 年之前
父节点
当前提交
a7a317570a
共有 4 个文件被更改,包括 280 次插入55 次删除
  1. 204 14
      src/code.c
  2. 17 5
      src/hlmodule.h
  3. 2 2
      src/jit.c
  4. 57 34
      src/module.c

+ 204 - 14
src/code.c

@@ -605,39 +605,120 @@ static const unsigned int crc32_table[] =
 
 #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(functions_signs[functions_indexes[idx]]); 
+#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))
 
-int hl_code_hash_type( hl_type *t ) {
+// 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++)
-			H32(hl_code_hash_type(t->fun->args[i]));
-		H32(hl_code_hash_type(t->fun->ret));
+			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;
-	// TODO
 	default:
 		break;
 	}
-	H(t->kind);
 	return hash;
 }
 
-int hl_code_hash_native( hl_native *n ) {
+#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;
+	}
+	return hash;
+}
+
+static int hash_native( hl_code_hash *h, hl_native *n ) {
 	int hash = -1;
 	HSTR(n->lib);
 	HSTR(n->name);
-	H32(hl_code_hash_type(n->t));
+	HTYPE(n->t);
 	return hash;
 }
 
-int hl_code_hash_fun_sign( hl_function *f ) {
+static int hash_fun_sign( hl_code_hash *h, hl_function *f ) {
 	int hash = -1;
-	H32(hl_code_hash_type(f->type));
+	HTYPE(f->type);
 	if( f->obj ) {
 		HUSTR(f->obj->name);
 		HUSTR(f->field.name);
@@ -649,11 +730,12 @@ int hl_code_hash_fun_sign( hl_function *f ) {
 	return hash;
 }
 
-int hl_code_hash_fun( hl_code *c, hl_function *f, int *functions_indexes, int *functions_signs ) {
+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++)
-		H32(hl_code_hash_type(f->regs[i]));
+		HTYPE(f->regs[i]);
 	for(k=0;k<f->nops;k++) {
 		hl_opcode *o = f->ops + k;
 		H(o->op);
@@ -667,11 +749,14 @@ int hl_code_hash_fun( hl_code *c, hl_function *f, int *functions_indexes, int *f
 			H32( ((int*)c->floats)[o->p2<<1] );
 			H32( ((int*)c->floats)[(o->p2<<1)|1] );
 			break;
-		//case OString:
+		case OString:
+			H32(o->p1);
+			HSTR(c->strings[o->p2]);
+			break;
 		//case OBytes:
 		case OType:
 			H32(o->p1);
-			H32(hl_code_hash_type(c->types + o->p2));
+			HTYPE(c->types + o->p2);
 			break;
 		case OCall0:
 			H32(o->p1);
@@ -729,6 +814,10 @@ int hl_code_hash_fun( hl_code *c, hl_function *f, int *functions_indexes, int *f
 			HSTR(c->strings[o->p2]);
 			H32(o->p3);
 			break;
+		case OGetGlobal:
+			H32(o->p1);
+			H32(h->globals_signs[o->p2]);
+			break;
 		default:
 			switch( hl_op_nargs[o->op] ) {
 			case 0:
@@ -791,3 +880,104 @@ int hl_code_hash_fun( hl_code *c, hl_function *f, int *functions_indexes, int *f
 	}
 	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++)
+		h->globals_signs[i] = i | 0x80000000;
+	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;
+		}
+	}
+	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;
+	}
+	return h;
+}
+
+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);
+}
+

+ 17 - 5
src/hlmodule.h

@@ -105,6 +105,16 @@ typedef struct {
 
 typedef struct jit_ctx jit_ctx;
 
+
+typedef struct {
+	hl_code *code;
+	int *types_hashes;
+	int *globals_signs;
+	int *functions_signs;
+	int *functions_hashes;
+	int *functions_indexes;
+} hl_code_hash;
+
 typedef struct {
 	hl_code *code;
 	int codesize;
@@ -112,19 +122,21 @@ typedef struct {
 	unsigned char *globals_data;
 	void **functions_ptrs;
 	int *functions_indexes;
-	int *functions_signs;
-	int *functions_hashes;
 	void *jit_code;
+	hl_code_hash *hash;
 	hl_debug_infos *jit_debug;
 	jit_ctx *jit_ctx;
 	hl_module_context ctx;
 } hl_module;
 
 hl_code *hl_code_read( const unsigned char *data, int size, char **error_msg );
-int hl_code_hash_fun_sign( hl_function *f );
-int hl_code_hash_fun( hl_code *c, hl_function *f, int *functions_indexes, int *functions_signs );
-int hl_code_hash_native( hl_native *n );
+
+hl_code_hash *hl_code_hash_alloc( hl_code *c );
+void hl_code_hash_finalize( hl_code_hash *h );
+void hl_code_hash_free( hl_code_hash *h );
 void hl_code_free( hl_code *c );
+int hl_code_hash_type( hl_code_hash *h, hl_type *t );
+
 const uchar *hl_get_ustring( hl_code *c, int index );
 const char* hl_op_name( int op );
 

+ 2 - 2
src/jit.c

@@ -4162,7 +4162,7 @@ void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **d
 			fabs = m->functions_ptrs[c->target];
 			if( fabs == NULL ) {
 				// read absolute address from previous module
-				int old_idx = m->functions_hashes[m->functions_indexes[c->target]];
+				int old_idx = m->hash->functions_hashes[m->functions_indexes[c->target]];
 				if( old_idx < 0 )
 					return NULL;
 				fabs = previous->functions_ptrs[(previous->code->functions + old_idx)->findex];
@@ -4199,7 +4199,7 @@ void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **d
 			void *fabs = m->functions_ptrs[fidx];
 			if( fabs == NULL ) {
 				// read absolute address from previous module
-				int old_idx = m->functions_hashes[m->functions_indexes[fidx]];
+				int old_idx = m->hash->functions_hashes[m->functions_indexes[fidx]];
 				if( old_idx < 0 )
 					return NULL;
 				fabs = previous->functions_ptrs[(previous->code->functions + old_idx)->findex];

+ 57 - 34
src/module.c

@@ -430,24 +430,6 @@ static void hl_module_init_indexes( hl_module *m ) {
 	}
 }
 
-static void hl_module_hash( hl_module *m ) {
-	int i;
-	m->functions_signs = malloc(sizeof(int) * (m->code->nfunctions + m->code->nnatives));
-	for(i=0;i<m->code->nfunctions;i++) {
-		hl_function *f = m->code->functions + i;
-		m->functions_signs[i] = hl_code_hash_fun_sign(f);
-	}
-	for(i=0;i<m->code->nnatives;i++) {
-		hl_native *n = m->code->natives + i;
-		m->functions_signs[i + m->code->nfunctions] = hl_code_hash_native(n);
-	}
-	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, m->functions_indexes, m->functions_signs);
-	}
-}
-
 static void hl_module_init_natives( hl_module *m ) {
 	char tmp[256];
 	int i;
@@ -493,6 +475,7 @@ int hl_module_init( hl_module *m, h_bool hot_reload ) {
 			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
@@ -574,7 +557,7 @@ int hl_module_init( hl_module *m, h_bool hot_reload ) {
 	hl_gc_set_dump_types(hl_module_types_dump);
 	hl_jit_free(ctx, hot_reload);
 	if( hot_reload ) {
-		hl_module_hash(m);
+		hl_code_hash_finalize(m->hash);
 		m->jit_ctx = ctx;
 	}
 	return 1;
@@ -583,23 +566,25 @@ int hl_module_init( hl_module *m, h_bool hot_reload ) {
 h_bool hl_module_patch( hl_module *m1, hl_code *c ) {
 	int 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_module_init_natives(m2);
 	hl_module_init_indexes(m2);
-	hl_module_hash(m2);	
 	hl_jit_reset(ctx, m2);
+	hl_code_hash_finalize(m2->hash);
 
 	for(i2=0;i2<m2->code->nfunctions;i2++) {
 		hl_function *f2 = m2->code->functions + i2;
-		int sign2 = m2->functions_signs[i2];
+		int sign2 = m2->hash->functions_signs[i2];
 		if( f2->field.name == NULL ) {
-			m2->functions_hashes[i2] = -1;
+			m2->hash->functions_hashes[i2] = -1;
 			continue;
 		}
 		for(i1=0;i1<m1->code->nfunctions;i1++) {
-			int sign1 = m1->functions_signs[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 ) {
@@ -611,17 +596,21 @@ h_bool hl_module_patch( hl_module *m1, hl_code *c ) {
 					continue;
 				}
 
-				int hash2 = m2->functions_hashes[i2];
-				int hash1 = m1->functions_hashes[i1];
-				m2->functions_hashes[i2] = i1; // index reference
+				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\n");
-				m1->functions_hashes[i1] = hash2; // update hash
+				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;
@@ -633,40 +622,70 @@ h_bool hl_module_patch( hl_module *m1, hl_code *c ) {
 			// not found (signature changed or new method) : inject new method!
 			int fpos = hl_jit_function(ctx, m2, f2);
 			if( fpos < 0 ) return false;
-			m2->functions_hashes[i2] = -1;
+			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("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;
+		if( p->kind != HOBJ && p->kind != HSTRUCT ) continue;
+		for(i2=0;i2<c->ntypes;i2++) {
+			hl_type *t = c->types + i2;
+			if( p->kind != t->kind ) continue;
+			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)  ) {
+				if( p->obj->global_value && t->obj->global_value ) {
+					// set old global value
+					*t->obj->global_value = *p->obj->global_value;
+					// point to old value address
+					t->obj->global_value = p->obj->global_value; 
+				}
+				t->obj = p->obj; // alias the types ! they are different pointers but have the same layout
+			} else {
+				uprintf(USTR("Type %s has changed\n"),t->obj->name);
+				changes_count++;
+			}
+			break;
+		}
+	}
+
 	m2->jit_code = hl_jit_code(ctx, m2, &m2->codesize, &m2->jit_debug, m1);
 	hl_jit_free(ctx,true);
 
 	if( m2->jit_code == NULL ) {
 		printf("Couldn't JIT result\n");
+		fflush(stdout);
 		return false;
 	}
 	
 	int i;
 	for(i=0;i<m2->code->nfunctions;i++) {
 		hl_function *f2 = m2->code->functions + i;
-		if( m2->functions_hashes[i] < -1 ) continue;
+		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->functions_hashes[i] < 0 ) continue;
-		hl_function *f1 = m1->code->functions + m2->functions_hashes[i];
+		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;
 	}
@@ -675,19 +694,23 @@ h_bool hl_module_patch( hl_module *m1, hl_code *c ) {
 		if( t->kind == HOBJ || t->kind == HSTRUCT ) hl_flush_proto(t);
 	}
 
+	if( changes_count > 0 ) {
+		printf("%d changes\n", changes_count);
+		fflush(stdout);
+	}
+
 	return true;
 }
 
 void hl_module_free( hl_module *m ) {
 	hl_free(&m->ctx.alloc);
 	hl_free_executable_memory(m->code, m->codesize);
+	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);
-	free(m->functions_hashes);
-	free(m->functions_signs);
 	if( m->jit_debug ) {
 		int i;
 		for(i=0;i<m->code->nfunctions;i++)