Browse Source

wip hot reloading, put basic infrastructure into place (--hot-reload, check hl file changes, etc.)

Nicolas Cannasse 6 năm trước cách đây
mục cha
commit
b8938a1f5f
5 tập tin đã thay đổi với 72 bổ sung17 xóa
  1. 2 2
      src/code.c
  2. 1 0
      src/hl.h
  3. 2 2
      src/hlmodule.h
  4. 55 13
      src/main.c
  5. 12 0
      src/std/sys.c

+ 2 - 2
src/code.c

@@ -344,7 +344,7 @@ static void hl_read_function( hl_reader *r, hl_function *f ) {
 }
 
 #undef CHK_ERROR
-#define CHK_ERROR() if( r->error ) { if( c ) hl_free(&c->alloc); printf("%s\n", r->error); return NULL; }
+#define CHK_ERROR() if( r->error ) { if( c ) hl_free(&c->alloc); *error_msg = 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))
 
@@ -420,7 +420,7 @@ static int *hl_read_debug_infos( hl_reader *r, int nops ) {
 	return debug;
 }
 
-hl_code *hl_code_read( const unsigned char *data, int size ) {
+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;

+ 1 - 0
src/hl.h

@@ -804,6 +804,7 @@ HL_API void *hl_fatal_error( const char *msg, const char *file, int line );
 HL_API void hl_fatal_fmt( const char *file, int line, const char *fmt, ...);
 HL_API void hl_sys_init(void **args, int nargs, void *hlfile);
 HL_API void hl_setup_callbacks(void *sc, void *gw);
+HL_API void hl_setup_reload_check( void *freload, void *param );
 
 #include <setjmp.h>
 typedef struct _hl_trap_ctx hl_trap_ctx;

+ 2 - 2
src/hlmodule.h

@@ -108,13 +108,13 @@ typedef struct {
 
 typedef struct jit_ctx jit_ctx;
 
-hl_code *hl_code_read( const unsigned char *data, int size );
+hl_code *hl_code_read( const unsigned char *data, int size, const char **error_msg );
 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 );
+int hl_module_init( hl_module *m, bool hot_reload );
 void hl_module_free( hl_module *m );
 bool hl_module_debug( hl_module *m, int port, bool wait );
 

+ 55 - 13
src/main.c

@@ -39,13 +39,34 @@ typedef char pchar;
 #define PSTR(x) x
 #endif
 
-static hl_code *load_code( const pchar *file ) {
+typedef struct {
+	hl_code *code;
+	hl_module *m;
+	vdynamic *ret;
+	vclosure c;
+	pchar *file;
+	int file_time;
+} main_context;
+
+static int pfiletime( uchar *file )	{
+#ifdef HL_WIN
+	struct _stat32 st;
+	_wstat32(file,&st);
+	return (int)st.st_mtime;
+#else
+	struct stat st;
+	stat(file,&st);
+	return (int)st.st_mtime;
+#endif
+}
+
+static hl_code *load_code( const pchar *file, char **error_msg, bool print_errors ) {
 	hl_code *code;
 	FILE *f = pfopen(file,"rb");
 	int pos, size;
 	char *fdata;
 	if( f == NULL ) {
-		pprintf("File not found '%s'\n",file);
+		if( print_errors ) pprintf("File not found '%s'\n",file);
 		return NULL;
 	}
 	fseek(f, 0, SEEK_END);
@@ -56,17 +77,30 @@ static hl_code *load_code( const pchar *file ) {
 	while( pos < size ) {
 		int r = (int)fread(fdata + pos, 1, size-pos, f);
 		if( r <= 0 ) {
-			pprintf("Failed to read '%s'\n",file);
+			if( print_errors ) pprintf("Failed to read '%s'\n",file);
 			return NULL;
 		}
 		pos += r;
 	}
 	fclose(f);
-	code = hl_code_read((unsigned char*)fdata, size);
+	code = hl_code_read((unsigned char*)fdata, size, error_msg);
 	free(fdata);
 	return code;
 }
 
+static bool check_reload( main_context *m ) {
+	int time = pfiletime(m->file);
+	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;
+	m->file_time = time;
+	hl_code_free(code);
+	return true;
+}
+
 #ifdef HL_VCC
 // this allows some runtime detection to switch to high performance mode
 __declspec(dllexport) DWORD NvOptimusEnablement = 1;
@@ -102,14 +136,11 @@ int wmain(int argc, pchar *argv[]) {
 int main(int argc, pchar *argv[]) {
 #endif
 	pchar *file = NULL;
+	char *error_msg = NULL;
 	int debug_port = -1;
 	bool debug_wait = false;
-	struct {
-		hl_code *code;
-		hl_module *m;
-		vdynamic *ret;
-		vclosure c;
-	} ctx;
+	bool hot_reload = false;
+	main_context ctx;
 	bool isExc = false;
 	int first_boot_arg = -1;
 	argv++;
@@ -131,6 +162,10 @@ int main(int argc, pchar *argv[]) {
 			printf("%d.%d.%d",HL_VERSION>>8,(HL_VERSION>>4)&15,HL_VERSION&15);
 			return 0;
 		}
+		if( pcompare(arg,PSTR("--hot-reload")) == 0 ) {
+			hot_reload = true;
+			continue;
+		}
 		if( *arg == '-' || *arg == '+' ) {
 			if( first_boot_arg < 0 ) first_boot_arg = argc + 1;
 			// skip value
@@ -160,14 +195,21 @@ int main(int argc, pchar *argv[]) {
 	hl_global_init();
 	hl_sys_init((void**)argv,argc,file);
 	hl_register_thread(&ctx);
-	ctx.code = load_code(file);
-	if( ctx.code == NULL )
+	ctx.file = file;
+	ctx.code = load_code(file, &error_msg, true);
+	if( ctx.code == NULL ) {
+		if( error_msg ) printf("%s\n", error_msg);
 		return 1;
+	}
 	ctx.m = hl_module_alloc(ctx.code);
 	if( ctx.m == NULL )
 		return 2;
-	if( !hl_module_init(ctx.m) )
+	if( !hl_module_init(ctx.m,hot_reload) )
 		return 3;
+	if( hot_reload ) {
+		ctx.file_time = pfiletime(ctx.file);
+		hl_setup_reload_check(check_reload,&ctx);
+	}
 	hl_code_free(ctx.code);
 	if( debug_port > 0 && !hl_module_debug(ctx.m,debug_port,debug_wait) ) {
 		fprintf(stderr,"Could not start debugger on port %d",debug_port);

+ 12 - 0
src/std/sys.c

@@ -604,6 +604,17 @@ HL_PRIM vbyte *hl_sys_hl_file() {
 	return (vbyte*)hl_file;
 }
 
+static void *reload_fun = NULL;
+static void *reload_param = NULL;
+HL_PRIM void hl_setup_reload_check( void *freload, void *param ) {
+	reload_fun = freload;
+	reload_param = param;
+}
+
+HL_PRIM bool hl_sys_check_reload() {
+	return reload_fun && ((bool(*)(void*))reload_fun)(reload_param);
+}
+
 #ifndef HL_MOBILE
 const char *hl_sys_special( const char *key ) {
 	 hl_error("Unknown sys_special key");
@@ -643,3 +654,4 @@ DEFINE_PRIM(_BYTES, sys_exe_path, _NO_ARG);
 DEFINE_PRIM(_I32, sys_get_char, _BOOL);
 DEFINE_PRIM(_ARR, sys_args, _NO_ARG);
 DEFINE_PRIM(_I32, sys_getpid, _NO_ARG);
+DEFINE_PRIM(_BOOL, sys_check_reload, _NO_ARG);