Sfoglia il codice sorgente

Merge branch 'development' into safe_com

Simon Krajewski 5 mesi fa
parent
commit
1d07ee4299

+ 4 - 1
src/compiler/args.ml

@@ -64,6 +64,7 @@ let parse_args com =
 		raise_usage = (fun () -> ());
 		raise_usage = (fun () -> ());
 		display_arg = None;
 		display_arg = None;
 		deprecations = [];
 		deprecations = [];
+		measure_times = false;
 	} in
 	} in
 	let add_deprecation s =
 	let add_deprecation s =
 		actx.deprecations <- s :: actx.deprecations
 		actx.deprecations <- s :: actx.deprecations
@@ -261,7 +262,9 @@ let parse_args com =
 			actx.hxb_out <- Some file;
 			actx.hxb_out <- Some file;
 		),"<file>", "generate haxe binary representation to target archive");
 		),"<file>", "generate haxe binary representation to target archive");
 		("Optimization",["--no-output"],[], Arg.Unit (fun() -> actx.no_output <- true),"","compiles but does not generate any file");
 		("Optimization",["--no-output"],[], Arg.Unit (fun() -> actx.no_output <- true),"","compiles but does not generate any file");
-		("Debug",["--times"],[], Arg.Unit (fun() -> com.timer_ctx.measure_times <- true),"","measure compilation times");
+		("Debug",["--times"],[], Arg.Unit (fun() ->
+			actx.measure_times <- true
+		),"","measure compilation times");
 		("Optimization",["--no-inline"],[],Arg.Unit (fun () ->
 		("Optimization",["--no-inline"],[],Arg.Unit (fun () ->
 			add_deprecation "--no-inline has been deprecated, use -D no-inline instead";
 			add_deprecation "--no-inline has been deprecated, use -D no-inline instead";
 			Common.define com Define.NoInline
 			Common.define com Define.NoInline

+ 1 - 0
src/compiler/compilationContext.ml

@@ -37,6 +37,7 @@ type arg_context = {
 	mutable raise_usage : unit -> unit;
 	mutable raise_usage : unit -> unit;
 	mutable display_arg : string option;
 	mutable display_arg : string option;
 	mutable deprecations : string list;
 	mutable deprecations : string list;
+	mutable measure_times : bool;
 }
 }
 
 
 type communication = {
 type communication = {

+ 2 - 1
src/compiler/compiler.ml

@@ -503,6 +503,7 @@ let catch_completion_and_exit ctx callbacks run =
 			i
 			i
 
 
 let process_actx ctx actx =
 let process_actx ctx actx =
+	ctx.timer_ctx.measure_times <- actx.measure_times;
 	DisplayProcessing.process_display_arg ctx actx;
 	DisplayProcessing.process_display_arg ctx actx;
 	List.iter (fun s ->
 	List.iter (fun s ->
 		ctx.com.warning WDeprecated [] s null_pos
 		ctx.com.warning WDeprecated [] s null_pos
@@ -703,7 +704,7 @@ module HighLevel = struct
 		end
 		end
 
 
 	let entry server_api comm args =
 	let entry server_api comm args =
-		let timer_ctx = Timer.make_context (Timer.make ["root"]) in
+		let timer_ctx = Timer.make_context (Timer.make ["other"]) in
 		let create = create_context comm server_api.cache timer_ctx in
 		let create = create_context comm server_api.cache timer_ctx in
 		let each_args = ref [] in
 		let each_args = ref [] in
 		let curdir = Unix.getcwd () in
 		let curdir = Unix.getcwd () in

+ 19 - 9
src/core/timer.ml

@@ -6,6 +6,7 @@ type timer = {
 }
 }
 
 
 type timer_context = {
 type timer_context = {
+	root_timer : timer;
 	mutable current : timer;
 	mutable current : timer;
 	mutable measure_times : bool;
 	mutable measure_times : bool;
 	start_time : float;
 	start_time : float;
@@ -19,12 +20,22 @@ let make id = {
 	calls = 0;
 	calls = 0;
 }
 }
 
 
-let make_context root_timer = {
-	current = root_timer;
-	timer_lut = Hashtbl.create 0;
-	measure_times = false;
-	start_time = Extc.time();
-}
+let make_context root_timer =
+	let ctx = {
+		root_timer = root_timer;
+		current = root_timer;
+		timer_lut = Hashtbl.create 0;
+		measure_times = true;
+		start_time = Extc.time();
+	} in
+	Hashtbl.add ctx.timer_lut root_timer.id root_timer;
+	ctx
+
+let update_timer timer start =
+	let now = Extc.time () in
+	let dt = now -. start in
+	timer.total <- timer.total +. dt -. timer.pauses;
+	dt
 
 
 let start_timer ctx id =
 let start_timer ctx id =
 	let start = Extc.time () in
 	let start = Extc.time () in
@@ -39,9 +50,7 @@ let start_timer ctx id =
 	timer.calls <- timer.calls + 1;
 	timer.calls <- timer.calls + 1;
 	ctx.current <- timer;
 	ctx.current <- timer;
 	(fun () ->
 	(fun () ->
-		let now = Extc.time () in
-		let dt = now -. start in
-		timer.total <- timer.total +. dt -. timer.pauses;
+		let dt = update_timer timer start in
 		timer.pauses <- 0.;
 		timer.pauses <- 0.;
 		old.pauses <- old.pauses +. dt;
 		old.pauses <- old.pauses +. dt;
 		ctx.current <- old
 		ctx.current <- old
@@ -85,6 +94,7 @@ type timer_node = {
 }
 }
 
 
 let build_times_tree ctx =
 let build_times_tree ctx =
+	ignore(update_timer ctx.root_timer ctx.start_time);
 	let nodes = Hashtbl.create 0 in
 	let nodes = Hashtbl.create 0 in
 	let rec root = {
 	let rec root = {
 		name = "";
 		name = "";

+ 25 - 15
src/generators/genhl.ml

@@ -86,6 +86,7 @@ type constval =
 
 
 type context = {
 type context = {
 	com : Gctx.t;
 	com : Gctx.t;
+	num_domains : int;
 	cglobals : (string, ttype) lookup;
 	cglobals : (string, ttype) lookup;
 	cstrings : (string, string) lookup;
 	cstrings : (string, string) lookup;
 	cbytes : (bytes, bytes) lookup;
 	cbytes : (bytes, bytes) lookup;
@@ -100,7 +101,6 @@ type context = {
 	w_null_compare : bool;
 	w_null_compare : bool;
 	overrides : (string * path, bool) Hashtbl.t;
 	overrides : (string * path, bool) Hashtbl.t;
 	defined_funs : (int,unit) Hashtbl.t;
 	defined_funs : (int,unit) Hashtbl.t;
-	mutable dump_out : (unit IO.output) option;
 	mutable cached_types : (string list, ttype) PMap.t;
 	mutable cached_types : (string list, ttype) PMap.t;
 	mutable m : method_context;
 	mutable m : method_context;
 	mutable anons_cache : (tanon, ttype) PMap.t;
 	mutable anons_cache : (tanon, ttype) PMap.t;
@@ -3262,6 +3262,7 @@ and gen_method_wrapper ctx rt t p =
 			code = DynArray.to_array ctx.m.mops;
 			code = DynArray.to_array ctx.m.mops;
 			debug = make_debug ctx ctx.m.mdebug;
 			debug = make_debug ctx ctx.m.mdebug;
 			assigns = Array.of_list (List.rev ctx.m.massign);
 			assigns = Array.of_list (List.rev ctx.m.massign);
+			need_opt = false;
 		} in
 		} in
 		ctx.m <- old;
 		ctx.m <- old;
 		DynArray.add ctx.cfunctions f;
 		DynArray.add ctx.cfunctions f;
@@ -3428,18 +3429,11 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 		code = DynArray.to_array ctx.m.mops;
 		code = DynArray.to_array ctx.m.mops;
 		debug = make_debug ctx ctx.m.mdebug;
 		debug = make_debug ctx ctx.m.mdebug;
 		assigns = Array.of_list (List.sort (fun (_,p1) (_,p2) -> p1 - p2) (List.rev ctx.m.massign));
 		assigns = Array.of_list (List.sort (fun (_,p1) (_,p2) -> p1 - p2) (List.rev ctx.m.massign));
+		need_opt = (gen_content = None || name <> ("",""));
 	} in
 	} in
 	ctx.m <- old;
 	ctx.m <- old;
 	Hashtbl.add ctx.defined_funs fidx ();
 	Hashtbl.add ctx.defined_funs fidx ();
-	let f = if ctx.optimize && (gen_content = None || name <> ("","")) then begin
-		let t = Timer.start_timer ctx.com.timer_ctx ["generate";"hl";"opt"] in
-		let f = Hlopt.optimize ctx.dump_out (DynArray.get ctx.cstrings.arr) hlf f in
-		t();
-		f
-	end else
-		hlf
-	in
-	DynArray.add ctx.cfunctions f;
+	DynArray.add ctx.cfunctions hlf;
 	capt
 	capt
 
 
 let generate_static ctx c f =
 let generate_static ctx c f =
@@ -4105,7 +4099,7 @@ let write_code ch code debug =
 
 
 (* --------------------------------------------------------------------------------------------------------------------- *)
 (* --------------------------------------------------------------------------------------------------------------------- *)
 
 
-let create_context com dump =
+let create_context com =
 	let get_type name =
 	let get_type name =
 		try
 		try
 			List.find (fun t -> (t_infos t).mt_path = (["hl"],name)) com.types
 			List.find (fun t -> (t_infos t).mt_path = (["hl"],name)) com.types
@@ -4129,7 +4123,7 @@ let create_context com dump =
 		hl_ver = Gctx.defined_value_safe ~default:"" com Define.HlVer;
 		hl_ver = Gctx.defined_value_safe ~default:"" com Define.HlVer;
 		optimize = not (Gctx.raw_defined com "hl_no_opt");
 		optimize = not (Gctx.raw_defined com "hl_no_opt");
 		w_null_compare = Gctx.raw_defined com "hl_w_null_compare";
 		w_null_compare = Gctx.raw_defined com "hl_w_null_compare";
-		dump_out = if dump then Some (IO.output_channel (open_out_bin "dump/hlopt.txt")) else None;
+		num_domains = Domain.recommended_domain_count ();
 		m = method_context 0 HVoid null_capture false;
 		m = method_context 0 HVoid null_capture false;
 		cints = new_lookup();
 		cints = new_lookup();
 		cstrings = new_lookup();
 		cstrings = new_lookup();
@@ -4259,12 +4253,28 @@ let generate com =
 		close_out ch;
 		close_out ch;
 	end else
 	end else
 
 
-	let ctx = create_context com dump in
+	let ctx = create_context com in
 	add_types ctx com.types;
 	add_types ctx com.types;
+
 	let code = build_code ctx com.types com.main.main_expr in
 	let code = build_code ctx com.types com.main.main_expr in
 	Array.sort (fun (lib1,_,_,_) (lib2,_,_,_) -> lib1 - lib2) code.natives;
 	Array.sort (fun (lib1,_,_,_) (lib2,_,_,_) -> lib1 - lib2) code.natives;
+
+	if ctx.optimize then begin
+		let t = Timer.start_timer com.timer_ctx ["generate";"hl";"opt"] in
+		let dump_out = if dump then Some (IO.output_channel (open_out_bin "dump/hlopt.txt")) else None in
+		Parallel.run_parallel_for ctx.num_domains ~chunk_size:16 (DynArray.length ctx.cfunctions) (fun idx ->
+			let f = DynArray.get ctx.cfunctions idx in
+			if f.need_opt then begin
+				let f, dumpstr = Hlopt.optimize dump (Array.get code.strings) f "todosign" in
+				(match dump_out with None -> () | Some ch -> IO.nwrite_string ch dumpstr);
+				code.functions.(idx) <- f;
+			end;
+		);
+		(match dump_out with None -> () | Some ch -> IO.close_out ch);
+		t();
+	end;
+
 	if dump then begin
 	if dump then begin
-		(match ctx.dump_out with None -> () | Some ch -> IO.close_out ch);
 		let ch = open_out_bin "dump/hlcode.txt" in
 		let ch = open_out_bin "dump/hlcode.txt" in
 		Hlcode.dump (fun s -> output_string ch (s ^ "\n")) code;
 		Hlcode.dump (fun s -> output_string ch (s ^ "\n")) code;
 		close_out ch;
 		close_out ch;
@@ -4301,7 +4311,7 @@ let generate com =
 			let version_revision = com.version.revision in
 			let version_revision = com.version.revision in
 			Gctx.define_value com Define.SourceHeader (Printf.sprintf "Generated by HLC %d.%d.%d (HL v%d)" version_major version_minor version_revision code.version);
 			Gctx.define_value com Define.SourceHeader (Printf.sprintf "Generated by HLC %d.%d.%d (HL v%d)" version_major version_minor version_revision code.version);
 		end;
 		end;
-		Hl2c.write_c com com.file code gnames;
+		Hl2c.write_c com com.file code gnames ctx.num_domains;
 		let t = Timer.start_timer com.timer_ctx ["nativecompile";"hl"] in
 		let t = Timer.start_timer com.timer_ctx ["nativecompile";"hl"] in
 		if not (Gctx.defined com Define.NoCompilation) && com.run_command_args "haxelib" ["run";"hashlink";"build";escape_command com.file] <> 0 then failwith "Build failed";
 		if not (Gctx.defined com Define.NoCompilation) && com.run_command_args "haxelib" ["run";"hashlink";"build";escape_command com.file] <> 0 then failwith "Build failed";
 		t();
 		t();

+ 229 - 168
src/generators/hl2c.ml

@@ -56,29 +56,34 @@ and function_entry = {
 	mutable fe_calling : function_entry list;
 	mutable fe_calling : function_entry list;
 }
 }
 
 
-type context = {
+type global_context = {
 	version : int;
 	version : int;
-	out : Buffer.t;
-	mutable tabs : string;
+	hash_mutex : Mutex.t;
 	hash_cache : (int, int32) Hashtbl.t;
 	hash_cache : (int, int32) Hashtbl.t;
 	hash_mem : (int32, bool) Hashtbl.t;
 	hash_mem : (int32, bool) Hashtbl.t;
 	mutable hash_cache_list : int list;
 	mutable hash_cache_list : int list;
 	hlcode : code;
 	hlcode : code;
 	dir : string;
 	dir : string;
-	mutable curfile : string;
 	mutable cfiles : string list;
 	mutable cfiles : string list;
 	ftable : function_entry array;
 	ftable : function_entry array;
 	htypes : (ttype, string) PMap.t;
 	htypes : (ttype, string) PMap.t;
 	gnames : string array;
 	gnames : string array;
 	bytes_names : string array;
 	bytes_names : string array;
+	mutable type_module : (ttype, code_module) PMap.t;
+	gcon : Gctx.t;
+}
+
+type file_context = {
+	out : Buffer.t;
+	mutable tabs : string;
+	dir : string;
+	curfile : string;
 	mutable defines : string list;
 	mutable defines : string list;
 	defined_funs : (int, unit) Hashtbl.t;
 	defined_funs : (int, unit) Hashtbl.t;
 	hdefines : (string, unit) Hashtbl.t;
 	hdefines : (string, unit) Hashtbl.t;
 	mutable defined_types : (ttype, unit) PMap.t;
 	mutable defined_types : (ttype, unit) PMap.t;
-	mutable file_prefix : string;
 	mutable fun_index : int;
 	mutable fun_index : int;
-	mutable type_module : (ttype, code_module) PMap.t;
-	gcon : Gctx.t;
+	file_prefix : string;
 }
 }
 
 
 let sprintf = Printf.sprintf
 let sprintf = Printf.sprintf
@@ -216,8 +221,10 @@ let unblock ctx =
 	ctx.tabs <- String.sub ctx.tabs 0 (String.length ctx.tabs - 1)
 	ctx.tabs <- String.sub ctx.tabs 0 (String.length ctx.tabs - 1)
 
 
 let hash ctx sid =
 let hash ctx sid =
+	Mutex.protect ctx.hash_mutex (fun () ->
 	try
 	try
-		Hashtbl.find ctx.hash_cache sid
+		let h = Hashtbl.find ctx.hash_cache sid in
+		h
 	with Not_found ->
 	with Not_found ->
 		let rec loop h =
 		let rec loop h =
 			if Hashtbl.mem ctx.hash_mem h then loop (Int32.add h Int32.one) else h
 			if Hashtbl.mem ctx.hash_mem h then loop (Int32.add h Int32.one) else h
@@ -227,6 +234,7 @@ let hash ctx sid =
 		Hashtbl.add ctx.hash_mem h true;
 		Hashtbl.add ctx.hash_mem h true;
 		ctx.hash_cache_list <- sid :: ctx.hash_cache_list;
 		ctx.hash_cache_list <- sid :: ctx.hash_cache_list;
 		h
 		h
+	)
 
 
 let type_name ctx t =
 let type_name ctx t =
 	try PMap.find t ctx.htypes with Not_found -> Globals.die (tstr t) __LOC__
 	try PMap.find t ctx.htypes with Not_found -> Globals.die (tstr t) __LOC__
@@ -237,38 +245,38 @@ let define ctx s =
 		Hashtbl.add ctx.hdefines s ();
 		Hashtbl.add ctx.hdefines s ();
 	end
 	end
 
 
-let rec define_type ctx t =
+let rec define_type gctx ctx t =
 	match t with
 	match t with
 	| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray _ | HType | HDynObj | HNull _ | HRef _ | HGUID -> ()
 	| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray _ | HType | HDynObj | HNull _ | HRef _ | HGUID -> ()
 	| HAbstract _ ->
 	| HAbstract _ ->
 		define ctx "#include <hl/natives.h>";
 		define ctx "#include <hl/natives.h>";
 	| HFun (args,ret) | HMethod (args,ret) ->
 	| HFun (args,ret) | HMethod (args,ret) ->
-		List.iter (define_type ctx) args;
-		define_type ctx ret
+		List.iter (define_type gctx ctx) args;
+		define_type gctx ctx ret
 	| HEnum _ | HObj _ | HStruct _ when not (PMap.exists t ctx.defined_types) ->
 	| HEnum _ | HObj _ | HStruct _ when not (PMap.exists t ctx.defined_types) ->
 		ctx.defined_types <- PMap.add t () ctx.defined_types;
 		ctx.defined_types <- PMap.add t () ctx.defined_types;
-		define ctx (sprintf "#include <%s.h>" (try PMap.find t ctx.type_module with Not_found -> Globals.die "" __LOC__).m_name)
+		define ctx (sprintf "#include <%s.h>" (try PMap.find t gctx.type_module with Not_found -> Globals.die "" __LOC__).m_name)
 	| HVirtual vp when not (PMap.exists t ctx.defined_types) ->
 	| HVirtual vp when not (PMap.exists t ctx.defined_types) ->
 		ctx.defined_types <- PMap.add t () ctx.defined_types;
 		ctx.defined_types <- PMap.add t () ctx.defined_types;
-		Array.iter (fun (_,_,t) -> define_type ctx t) vp.vfields
+		Array.iter (fun (_,_,t) -> define_type gctx ctx t) vp.vfields
 	| HPacked t ->
 	| HPacked t ->
-		define_type ctx t
+		define_type gctx ctx t
 	| HEnum _ | HObj _ | HStruct _ | HVirtual _ ->
 	| HEnum _ | HObj _ | HStruct _ | HVirtual _ ->
 		()
 		()
 
 
-let type_value ctx t =
-	let n = type_name ctx t in
+let type_value gctx ctx t =
+	let n = type_name gctx t in
 	define ctx (sprintf "extern hl_type %s;" n);
 	define ctx (sprintf "extern hl_type %s;" n);
 	"&" ^ n
 	"&" ^ n
 
 
-let enum_constr_type ctx e i =
-	define_type ctx (HEnum e);
+let enum_constr_type gctx ctx e i =
+	define_type gctx ctx (HEnum e);
 	let cname,_, tl = e.efields.(i) in
 	let cname,_, tl = e.efields.(i) in
 	if Array.length tl = 0 then
 	if Array.length tl = 0 then
 		"venum"
 		"venum"
 	else
 	else
 	let name = if e.eid = 0 then
 	let name = if e.eid = 0 then
-		let name = (try PMap.find (HEnum e) ctx.htypes with Not_found -> Globals.die "" __LOC__) in
+		let name = (try PMap.find (HEnum e) gctx.htypes with Not_found -> Globals.die "" __LOC__) in
 		"Enum" ^ name
 		"Enum" ^ name
 	else
 	else
 		String.concat "_" (ExtString.String.nsplit e.ename ".")
 		String.concat "_" (ExtString.String.nsplit e.ename ".")
@@ -284,12 +292,12 @@ let output ctx str =
 let output_char ctx c =
 let output_char ctx c =
 	Buffer.add_char ctx.out c
 	Buffer.add_char ctx.out c
 
 
-let line ctx str =
+let linec ctx str =
 	output ctx ctx.tabs;
 	output ctx ctx.tabs;
 	output ctx str;
 	output ctx str;
 	output_char ctx '\n'
 	output_char ctx '\n'
 
 
-let expr ctx str =
+let exprc ctx str =
 	output ctx ctx.tabs;
 	output ctx ctx.tabs;
 	output ctx str;
 	output ctx str;
 	output ctx ";\n"
 	output ctx ";\n"
@@ -301,6 +309,11 @@ let obj_field fid name =
 
 
 let bom = "\xEF\xBB\xBF"
 let bom = "\xEF\xBB\xBF"
 
 
+let save_cfile gctx file =
+	if String.sub file (String.length file - 2) 2 = ".c" then begin
+		gctx.cfiles <- file :: gctx.cfiles;
+	end
+
 let close_file ctx =
 let close_file ctx =
 	let out = Buffer.contents ctx.out in
 	let out = Buffer.contents ctx.out in
 	let defines = List.rev ctx.defines in
 	let defines = List.rev ctx.defines in
@@ -312,23 +325,20 @@ let close_file ctx =
 	Hashtbl.clear ctx.defined_funs;
 	Hashtbl.clear ctx.defined_funs;
 	Buffer.reset ctx.out;
 	Buffer.reset ctx.out;
 	let fpath = ctx.dir ^ "/" ^ ctx.curfile in
 	let fpath = ctx.dir ^ "/" ^ ctx.curfile in
-	if String.sub ctx.curfile (String.length ctx.curfile - 2) 2 = ".c" then ctx.cfiles <- ctx.curfile :: ctx.cfiles;
-	ctx.curfile <- "";
 	let fcontent = (try Std.input_file ~bin:true fpath with _ -> "") in
 	let fcontent = (try Std.input_file ~bin:true fpath with _ -> "") in
 	if fcontent <> str then begin
 	if fcontent <> str then begin
-		Path.mkdir_recursive "" (ExtString.String.nsplit (Filename.dirname fpath) "/");
 		let ch = open_out_bin fpath in
 		let ch = open_out_bin fpath in
 		output_string ch str;
 		output_string ch str;
 		close_out ch;
 		close_out ch;
 	end
 	end
 
 
-let define_global ctx g =
-	let t = ctx.hlcode.globals.(g) in
-	define_type ctx t;
-	define ctx (sprintf "extern %s;" (var_type ctx.gnames.(g) t))
+let define_global gctx ctx g =
+	let t = gctx.hlcode.globals.(g) in
+	define_type gctx ctx t;
+	define ctx (sprintf "extern %s;" (var_type gctx.gnames.(g) t))
 
 
-let define_function ctx fid =
-	let ft = ctx.ftable.(fid) in
+let define_function gctx ctx fid =
+	let ft = gctx.ftable.(fid) in
 	let fid = if ft.fe_decl = None then -1 else fid in
 	let fid = if ft.fe_decl = None then -1 else fid in
 	if not (Hashtbl.mem ctx.defined_funs fid) then begin
 	if not (Hashtbl.mem ctx.defined_funs fid) then begin
 		Hashtbl.add ctx.defined_funs fid ();
 		Hashtbl.add ctx.defined_funs fid ();
@@ -336,7 +346,7 @@ let define_function ctx fid =
 		| None ->
 		| None ->
 			define ctx "#include <hl/natives.h>"
 			define ctx "#include <hl/natives.h>"
 		| Some f ->
 		| Some f ->
-			define_type ctx f.ftype;
+			define_type gctx ctx f.ftype;
 			ctx.defines <- sprintf "%s %s(%s);" (ctype ft.fe_ret) ft.fe_name (args_repr ft.fe_args) :: ctx.defines);
 			ctx.defines <- sprintf "%s %s(%s);" (ctype ft.fe_ret) ft.fe_name (args_repr ft.fe_args) :: ctx.defines);
 	end;
 	end;
 	ft.fe_name
 	ft.fe_name
@@ -344,18 +354,31 @@ let define_function ctx fid =
 let short_digest str =
 let short_digest str =
 	String.sub (Digest.to_hex (Digest.string str)) 0 7
 	String.sub (Digest.to_hex (Digest.string str)) 0 7
 
 
-let open_file ctx file =
-	if ctx.curfile <> "" then close_file ctx;
+let create_file_context dir file =
+	let ctx = {
+		out = Buffer.create 1024;
+		tabs = "";
+		dir = dir;
+		curfile = file;
+		defines = [];
+		hdefines = Hashtbl.create 0;
+		defined_funs = Hashtbl.create 0;
+		defined_types = PMap.empty;
+		fun_index = 0;
+		file_prefix = (short_digest file) ^ "_";
+	} in
+	ctx
+
+let open_file (gctx:global_context) file =
+	let ctx = create_file_context gctx.dir file in
 	if file <> "hlc.json" then
 	if file <> "hlc.json" then
-		Gctx.map_source_header ctx.gcon.defines (fun s -> define ctx (sprintf "// %s" s));
-	ctx.curfile <- file;
-	ctx.fun_index <- 0;
-	ctx.file_prefix <- (short_digest file) ^ "_"
+		Gctx.map_source_header gctx.gcon.defines (fun s -> define ctx (sprintf "// %s" s));
+	ctx
 
 
 let string_data_limit = 64
 let string_data_limit = 64
 
 
-let string ctx sid =
-	let s = ctx.hlcode.strings.(sid) in
+let string gctx ctx sid =
+	let s = gctx.hlcode.strings.(sid) in
 	if String.length s < string_data_limit then
 	if String.length s < string_data_limit then
 		sprintf "USTR(\"%s\")" (StringHelper.s_escape s)
 		sprintf "USTR(\"%s\")" (StringHelper.s_escape s)
 	else begin
 	else begin
@@ -364,8 +387,8 @@ let string ctx sid =
 		sprintf "string$%s" id
 		sprintf "string$%s" id
 	end
 	end
 
 
-let generate_reflection ctx =
-	let line = line ctx and expr = expr ctx in
+let generate_reflection gctx ctx =
+	let line = linec ctx and expr = exprc ctx in
 	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
 	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
 
 
 	let funByArgs = Hashtbl.create 0 in
 	let funByArgs = Hashtbl.create 0 in
@@ -400,8 +423,8 @@ let generate_reflection ctx =
 				| _ -> ())
 				| _ -> ())
 			| _ -> ()
 			| _ -> ()
 		) f.code
 		) f.code
-	) ctx.hlcode.functions;
-	Array.iter (fun f -> add_fun f.fe_args f.fe_ret) ctx.ftable;
+	) gctx.hlcode.functions;
+	Array.iter (fun f -> add_fun f.fe_args f.fe_ret) gctx.ftable;
 	let argsCounts = List.sort compare (Hashtbl.fold (fun i _ acc -> i :: acc) funByArgs []) in
 	let argsCounts = List.sort compare (Hashtbl.fold (fun i _ acc -> i :: acc) funByArgs []) in
 	sexpr "static int TKIND[] = {%s}" (String.concat "," (List.map (fun t -> string_of_int (type_kind_id (type_kind t))) core_types));
 	sexpr "static int TKIND[] = {%s}" (String.concat "," (List.map (fun t -> string_of_int (type_kind_id (type_kind t))) core_types));
 	line "";
 	line "";
@@ -519,13 +542,13 @@ let generate_reflection ctx =
 	line "}";
 	line "}";
 	line ""
 	line ""
 
 
-let generate_function ctx f =
-	let line = line ctx and expr = expr ctx in
+let generate_function gctx ctx f =
+	let line = linec ctx and expr = exprc ctx in
 	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
 	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
 	let define fmt = Printf.ksprintf (define ctx) fmt in
 	let define fmt = Printf.ksprintf (define ctx) fmt in
 	let block() = block ctx and unblock() = unblock ctx in
 	let block() = block ctx and unblock() = unblock ctx in
-	let type_value = type_value ctx in
-	let code = ctx.hlcode in
+	let type_value = type_value gctx in
+	let code = gctx.hlcode in
 
 
 	let rid = ref (-1) in
 	let rid = ref (-1) in
 	let cl_id = ref 0 in
 	let cl_id = ref 0 in
@@ -534,12 +557,12 @@ let generate_function ctx f =
 	let label p = sprintf "label$%s%d_%d" ctx.file_prefix ctx.fun_index p in
 	let label p = sprintf "label$%s%d_%d" ctx.file_prefix ctx.fun_index p in
 	ctx.fun_index <- ctx.fun_index + 1;
 	ctx.fun_index <- ctx.fun_index + 1;
 	Hashtbl.add ctx.defined_funs f.findex ();
 	Hashtbl.add ctx.defined_funs f.findex ();
-	Array.iter (define_type ctx) f.regs;
-	define_type ctx f.ftype;
+	Array.iter (define_type gctx ctx) f.regs;
+	define_type gctx ctx f.ftype;
 
 
 	let rtype r = f.regs.(r) in
 	let rtype r = f.regs.(r) in
 
 
-	let funname fid = define_function ctx fid in
+	let funname fid = define_function gctx ctx fid in
 
 
 	let rcast r t =
 	let rcast r t =
 		let rt = (rtype r) in
 		let rt = (rtype r) in
@@ -567,7 +590,7 @@ let generate_function ctx f =
 	in
 	in
 
 
 	let ocall r fid args =
 	let ocall r fid args =
-		let ft = ctx.ftable.(fid) in
+		let ft = gctx.ftable.(fid) in
 		let rstr = rassign r ft.fe_ret in
 		let rstr = rassign r ft.fe_ret in
 		sexpr "%s%s(%s)" rstr (funname fid) (String.concat "," (List.map2 rcast args ft.fe_args))
 		sexpr "%s%s(%s)" rstr (funname fid) (String.concat "," (List.map2 rcast args ft.fe_args))
 	in
 	in
@@ -582,7 +605,7 @@ let generate_function ctx f =
 	in
 	in
 
 
 	let type_value_opt t =
 	let type_value_opt t =
-		match t with HF32 | HF64 | HI64 -> "" | _ -> "," ^ type_value t
+		match t with HF32 | HF64 | HI64 -> "" | _ -> "," ^ type_value ctx t
 	in
 	in
 
 
 	let dyn_call r f pl =
 	let dyn_call r f pl =
@@ -596,7 +619,7 @@ let generate_function ctx f =
 				if is_dynamic t then
 				if is_dynamic t then
 					sprintf "(vdynamic*)%s" (reg p)
 					sprintf "(vdynamic*)%s" (reg p)
 				else
 				else
-					sprintf "hl_make_dyn(&%s,%s)" (reg p) (type_value t)
+					sprintf "hl_make_dyn(&%s,%s)" (reg p) (type_value ctx t)
 		) pl));
 		) pl));
 		let rt = rtype r in
 		let rt = rtype r in
 		let ret = if rt = HVoid then "" else if is_dynamic rt then sprintf "%s = (%s)" (reg r) (ctype rt) else "vdynamic *ret = " in
 		let ret = if rt = HVoid then "" else if is_dynamic rt then sprintf "%s = (%s)" (reg r) (ctype rt) else "vdynamic *ret = " in
@@ -629,7 +652,7 @@ let generate_function ctx f =
 				let rt = rtype r in
 				let rt = rtype r in
 				let ret = if rt = HVoid then "" else if is_ptr rt then sprintf "%s = (%s)" (reg r) (ctype rt) else begin sexpr "vdynamic ret"; ""; end in
 				let ret = if rt = HVoid then "" else if is_ptr rt then sprintf "%s = (%s)" (reg r) (ctype rt) else begin sexpr "vdynamic ret"; ""; end in
 				let fname, fid, ft = vp.vfields.(fid) in
 				let fname, fid, ft = vp.vfields.(fid) in
-				sexpr "%shl_dyn_call_obj(%s->value,%s,%ld/*%s*/,%s,%s)" ret (reg o) (type_value ft) (hash ctx fid) fname (if args = [] then "NULL" else "args") (if is_ptr rt || rt == HVoid then "NULL" else "&ret");
+				sexpr "%shl_dyn_call_obj(%s->value,%s,%ld/*%s*/,%s,%s)" ret (reg o) (type_value ctx ft) (hash gctx fid) fname (if args = [] then "NULL" else "args") (if is_ptr rt || rt == HVoid then "NULL" else "&ret");
 				if rt <> HVoid && not (is_ptr rt) then sexpr "%s = (%s)ret.v.%s" (reg r) (ctype rt) (dyn_prefix rt);
 				if rt <> HVoid && not (is_ptr rt) then sexpr "%s = (%s)ret.v.%s" (reg r) (ctype rt) (dyn_prefix rt);
 				unblock();
 				unblock();
 				sline "}"
 				sline "}"
@@ -644,7 +667,7 @@ let generate_function ctx f =
 			sexpr "%s->%s = %s" (reg obj) (obj_field fid name) (rcast v t)
 			sexpr "%s->%s = %s" (reg obj) (obj_field fid name) (rcast v t)
 		| HVirtual vp ->
 		| HVirtual vp ->
 			let name, nid, t = vp.vfields.(fid) in
 			let name, nid, t = vp.vfields.(fid) in
-			let dset = sprintf "hl_dyn_set%s(%s->value,%ld/*%s*/%s,%s)" (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt (rtype v)) (reg v) in
+			let dset = sprintf "hl_dyn_set%s(%s->value,%ld/*%s*/%s,%s)" (dyn_prefix t) (reg obj) (hash gctx nid) name (type_value_opt (rtype v)) (reg v) in
 			sexpr "if( hl_vfields(%s)[%d] ) *(%s*)(hl_vfields(%s)[%d]) = (%s)%s; else %s" (reg obj) fid (ctype t) (reg obj) fid (ctype t) (reg v) dset
 			sexpr "if( hl_vfields(%s)[%d] ) *(%s*)(hl_vfields(%s)[%d]) = (%s)%s; else %s" (reg obj) fid (ctype t) (reg obj) fid (ctype t) (reg v) dset
 		| _ ->
 		| _ ->
 			Globals.die "" __LOC__
 			Globals.die "" __LOC__
@@ -657,7 +680,7 @@ let generate_function ctx f =
 			sexpr "%s%s->%s" (rassign r t) (reg obj) (obj_field fid name)
 			sexpr "%s%s->%s" (rassign r t) (reg obj) (obj_field fid name)
 		| HVirtual v ->
 		| HVirtual v ->
 			let name, nid, t = v.vfields.(fid) in
 			let name, nid, t = v.vfields.(fid) in
-			let dget = sprintf "(%s)hl_dyn_get%s(%s->value,%ld/*%s*/%s)" (ctype t) (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt t) in
+			let dget = sprintf "(%s)hl_dyn_get%s(%s->value,%ld/*%s*/%s)" (ctype t) (dyn_prefix t) (reg obj) (hash gctx nid) name (type_value_opt t) in
 			sexpr "%shl_vfields(%s)[%d] ? (*(%s*)(hl_vfields(%s)[%d])) : %s" (rassign r t) (reg obj) fid (ctype t) (reg obj) fid dget
 			sexpr "%shl_vfields(%s)[%d] ? (*(%s*)(hl_vfields(%s)[%d])) : %s" (rassign r t) (reg obj) fid (ctype t) (reg obj) fid dget
 		| _ ->
 		| _ ->
 			Globals.die "" __LOC__
 			Globals.die "" __LOC__
@@ -698,8 +721,8 @@ let generate_function ctx f =
 		| OEndTrap true ->
 		| OEndTrap true ->
 			decr trap_depth
 			decr trap_depth
 		| OStaticClosure (_, fid) ->
 		| OStaticClosure (_, fid) ->
-			let ft = ctx.ftable.(fid) in
-			sexpr "static vclosure cl$%d = { %s, %s, 0 }" (!cl_id) (type_value (HFun (ft.fe_args,ft.fe_ret))) (funname fid);
+			let ft = gctx.ftable.(fid) in
+			sexpr "static vclosure cl$%d = { %s, %s, 0 }" (!cl_id) (type_value ctx (HFun (ft.fe_args,ft.fe_ret))) (funname fid);
 			incr cl_id;
 			incr cl_id;
 		| _ ->
 		| _ ->
 			()
 			()
@@ -819,10 +842,10 @@ let generate_function ctx f =
 		| OBool (r,b) ->
 		| OBool (r,b) ->
 			sexpr "%s = %s" (reg r) (if b then "true" else "false")
 			sexpr "%s = %s" (reg r) (if b then "true" else "false")
 		| OBytes (r,idx) ->
 		| OBytes (r,idx) ->
-			define "extern vbyte %s[];" ctx.bytes_names.(idx);
-			sexpr "%s = %s" (reg r) ctx.bytes_names.(idx)
+			define "extern vbyte %s[];" gctx.bytes_names.(idx);
+			sexpr "%s = %s" (reg r) gctx.bytes_names.(idx)
 		| OString (r,idx) ->
 		| OString (r,idx) ->
-			sexpr "%s = (vbyte*)%s" (reg r) (string ctx idx)
+			sexpr "%s = (vbyte*)%s" (reg r) (string gctx ctx idx)
 		| ONull r ->
 		| ONull r ->
 			sexpr "%s = NULL" (reg r)
 			sexpr "%s = NULL" (reg r)
 		| OAdd (r,a,b) ->
 		| OAdd (r,a,b) ->
@@ -903,22 +926,22 @@ let generate_function ctx f =
 			sexpr "%s = &cl$%d" (reg r) (!cl_id);
 			sexpr "%s = &cl$%d" (reg r) (!cl_id);
 			incr cl_id
 			incr cl_id
 		| OInstanceClosure (r,fid,ptr) ->
 		| OInstanceClosure (r,fid,ptr) ->
-			let ft = ctx.ftable.(fid) in
-			sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun (ft.fe_args,ft.fe_ret))) (funname fid) (reg ptr)
+			let ft = gctx.ftable.(fid) in
+			sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value ctx (HFun (ft.fe_args,ft.fe_ret))) (funname fid) (reg ptr)
 		| OVirtualClosure (r,o,m) ->
 		| OVirtualClosure (r,o,m) ->
 			(match rtype o with
 			(match rtype o with
 			| HObj p ->
 			| HObj p ->
-				let ft = ctx.ftable.(p.pvirtuals.(m)) in
+				let ft = gctx.ftable.(p.pvirtuals.(m)) in
 				let s = sprintf "%s->$type->vobj_proto[%d]" (reg o) m in
 				let s = sprintf "%s->$type->vobj_proto[%d]" (reg o) m in
-				sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun(ft.fe_args,ft.fe_ret))) s (reg o)
+				sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value ctx (HFun(ft.fe_args,ft.fe_ret))) s (reg o)
 			| _ ->
 			| _ ->
 				todo())
 				todo())
 		| OGetGlobal (r,g) ->
 		| OGetGlobal (r,g) ->
-			define_global ctx g;
-			sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) ctx.gnames.(g)
+			define_global gctx ctx g;
+			sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) gctx.gnames.(g)
 		| OSetGlobal (g,r) ->
 		| OSetGlobal (g,r) ->
-			define_global ctx g;
-			sexpr "%s = (%s)%s" ctx.gnames.(g) (ctype code.globals.(g)) (reg r)
+			define_global gctx ctx g;
+			sexpr "%s = (%s)%s" gctx.gnames.(g) (ctype code.globals.(g)) (reg r)
 		| ORet r ->
 		| ORet r ->
 			if rtype r = HVoid then expr "return" else sexpr "return %s" (rcast r fret)
 			if rtype r = HVoid then expr "return" else sexpr "return %s" (rcast r fret)
 		| OJTrue (r,d) | OJNotNull (r,d) ->
 		| OJTrue (r,d) | OJNotNull (r,d) ->
@@ -956,7 +979,7 @@ let generate_function ctx f =
 				sline "if( %s == NULL ) %s = NULL; else {" (reg v) (reg r);
 				sline "if( %s == NULL ) %s = NULL; else {" (reg v) (reg r);
 				block();
 				block();
 			end;
 			end;
-			sexpr "%s = hl_alloc_dynamic(%s)" (reg r) (type_value (rtype v));
+			sexpr "%s = hl_alloc_dynamic(%s)" (reg r) (type_value ctx (rtype v));
 			(match rtype v with
 			(match rtype v with
 			| HUI8 | HUI16 | HI32 | HBool ->
 			| HUI8 | HUI16 | HI32 | HBool ->
 				sexpr "%s->v.i = %s" (reg r) (reg v)
 				sexpr "%s->v.i = %s" (reg r) (reg v)
@@ -980,9 +1003,9 @@ let generate_function ctx f =
 			sexpr "%s = (int)%s" (reg r) (reg v)
 			sexpr "%s = (int)%s" (reg r) (reg v)
 		| ONew r ->
 		| ONew r ->
 			(match rtype r with
 			(match rtype r with
-			| HObj o | HStruct o -> sexpr "%s = (%s)hl_alloc_obj(%s)" (reg r) (tname o.pname) (type_value (rtype r))
+			| HObj o | HStruct o -> sexpr "%s = (%s)hl_alloc_obj(%s)" (reg r) (tname o.pname) (type_value ctx (rtype r))
 			| HDynObj -> sexpr "%s = hl_alloc_dynobj()" (reg r)
 			| HDynObj -> sexpr "%s = hl_alloc_dynobj()" (reg r)
-			| HVirtual _ as t -> sexpr "%s = hl_alloc_virtual(%s)" (reg r) (type_value t)
+			| HVirtual _ as t -> sexpr "%s = hl_alloc_virtual(%s)" (reg r) (type_value ctx t)
 			| _ -> Globals.die "" __LOC__)
 			| _ -> Globals.die "" __LOC__)
 		| OField (r,obj,fid) ->
 		| OField (r,obj,fid) ->
 			get_field r obj fid
 			get_field r obj fid
@@ -1030,13 +1053,13 @@ let generate_function ctx f =
 			if tsrc = HNull t then
 			if tsrc = HNull t then
 				sexpr "%s = %s ? %s%s : 0" (reg r) (reg v) (reg v) (dyn_value_field t)
 				sexpr "%s = %s ? %s%s : 0" (reg r) (reg v) (reg v) (dyn_value_field t)
 			else
 			else
-				sexpr "%s = (%s)hl_dyn_cast%s(&%s,%s%s)" (reg r) (ctype t) (dyn_prefix t) (reg v) (type_value (rtype v)) (type_value_opt t)
+				sexpr "%s = (%s)hl_dyn_cast%s(&%s,%s%s)" (reg r) (ctype t) (dyn_prefix t) (reg v) (type_value ctx (rtype v)) (type_value_opt t)
 		| OUnsafeCast (r,v) ->
 		| OUnsafeCast (r,v) ->
 			sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
 			sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
 		| OArraySize (r,a) ->
 		| OArraySize (r,a) ->
 			sexpr "%s = %s->size" (reg r) (reg a)
 			sexpr "%s = %s->size" (reg r) (reg a)
 		| OType (r,t) ->
 		| OType (r,t) ->
-			sexpr "%s = %s" (reg r) (type_value t)
+			sexpr "%s = %s" (reg r) (type_value ctx t)
 		| OGetType (r,v) ->
 		| OGetType (r,v) ->
 			sexpr "%s = %s ? ((vdynamic*)%s)->t : &hlt_void" (reg r) (reg v) (reg v)
 			sexpr "%s = %s ? ((vdynamic*)%s)->t : &hlt_void" (reg r) (reg v) (reg v)
 		| OGetTID (r,v) ->
 		| OGetTID (r,v) ->
@@ -1048,36 +1071,36 @@ let generate_function ctx f =
 		| OSetref (r,v) ->
 		| OSetref (r,v) ->
 			sexpr "*%s = %s" (reg r) (reg v)
 			sexpr "*%s = %s" (reg r) (reg v)
 		| OToVirtual (r,v) ->
 		| OToVirtual (r,v) ->
-			sexpr "%s = hl_to_virtual(%s,(vdynamic*)%s)" (reg r) (type_value (rtype r)) (reg v)
+			sexpr "%s = hl_to_virtual(%s,(vdynamic*)%s)" (reg r) (type_value ctx (rtype r)) (reg v)
 		| ODynGet (r,o,sid) ->
 		| ODynGet (r,o,sid) ->
 			let t = rtype r in
 			let t = rtype r in
-			let h = hash ctx sid in
+			let h = hash gctx sid in
 			sexpr "%s = (%s)hl_dyn_get%s((vdynamic*)%s,%ld/*%s*/%s)" (reg r) (ctype t) (dyn_prefix t) (reg o) h code.strings.(sid) (type_value_opt t)
 			sexpr "%s = (%s)hl_dyn_get%s((vdynamic*)%s,%ld/*%s*/%s)" (reg r) (ctype t) (dyn_prefix t) (reg o) h code.strings.(sid) (type_value_opt t)
 		| ODynSet (o,sid,v) ->
 		| ODynSet (o,sid,v) ->
-			let h = hash ctx sid in
+			let h = hash gctx sid in
 			sexpr "hl_dyn_set%s((vdynamic*)%s,%ld/*%s*/%s,%s)" (dyn_prefix (rtype v)) (reg o) h code.strings.(sid) (type_value_opt (rtype v)) (reg v)
 			sexpr "hl_dyn_set%s((vdynamic*)%s,%ld/*%s*/%s,%s)" (dyn_prefix (rtype v)) (reg o) h code.strings.(sid) (type_value_opt (rtype v)) (reg v)
 		| OMakeEnum (r,cid,rl) ->
 		| OMakeEnum (r,cid,rl) ->
-			let e, et = (match rtype r with HEnum e -> e, enum_constr_type ctx e cid | _ -> Globals.die "" __LOC__) in
+			let e, et = (match rtype r with HEnum e -> e, enum_constr_type gctx ctx e cid | _ -> Globals.die "" __LOC__) in
 			let need_tmp = List.mem r rl in
 			let need_tmp = List.mem r rl in
 			let tmp = if not need_tmp then reg r else begin
 			let tmp = if not need_tmp then reg r else begin
 				sexpr "{ venum *tmp";
 				sexpr "{ venum *tmp";
 				"tmp"
 				"tmp"
 			end in
 			end in
-			sexpr "%s = hl_alloc_enum(%s,%d)" tmp (type_value (rtype r)) cid;
+			sexpr "%s = hl_alloc_enum(%s,%d)" tmp (type_value ctx (rtype r)) cid;
 			let _,_,tl = e.efields.(cid) in
 			let _,_,tl = e.efields.(cid) in
 			list_iteri (fun i v ->
 			list_iteri (fun i v ->
 				sexpr "((%s*)%s)->p%d = %s" et tmp i (rcast v tl.(i))
 				sexpr "((%s*)%s)->p%d = %s" et tmp i (rcast v tl.(i))
 			) rl;
 			) rl;
 			if need_tmp then sexpr "%s = tmp; }" (reg r)
 			if need_tmp then sexpr "%s = tmp; }" (reg r)
 		| OEnumAlloc (r,cid) ->
 		| OEnumAlloc (r,cid) ->
-			sexpr "%s = hl_alloc_enum(%s,%d)" (reg r) (type_value (rtype r)) cid
+			sexpr "%s = hl_alloc_enum(%s,%d)" (reg r) (type_value ctx (rtype r)) cid
 		| OEnumIndex (r,v) ->
 		| OEnumIndex (r,v) ->
 			sexpr "%s = HL__ENUM_INDEX__(%s)" (reg r) (reg v)
 			sexpr "%s = HL__ENUM_INDEX__(%s)" (reg r) (reg v)
 		| OEnumField (r,e,cid,pid) ->
 		| OEnumField (r,e,cid,pid) ->
-			let tname,(_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e cid, e.efields.(cid) | _ -> Globals.die "" __LOC__) in
+			let tname,(_,_,tl) = (match rtype e with HEnum e -> enum_constr_type gctx ctx e cid, e.efields.(cid) | _ -> Globals.die "" __LOC__) in
 			sexpr "%s((%s*)%s)->p%d" (rassign r tl.(pid)) tname (reg e) pid
 			sexpr "%s((%s*)%s)->p%d" (rassign r tl.(pid)) tname (reg e) pid
 		| OSetEnumField (e,pid,r) ->
 		| OSetEnumField (e,pid,r) ->
-			let tname, (_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e 0, e.efields.(0) | _ -> Globals.die "" __LOC__) in
+			let tname, (_,_,tl) = (match rtype e with HEnum e -> enum_constr_type gctx ctx e 0, e.efields.(0) | _ -> Globals.die "" __LOC__) in
 			sexpr "((%s*)%s)->p%d = (%s)%s" tname (reg e) pid (ctype tl.(pid)) (reg r)
 			sexpr "((%s*)%s)->p%d = (%s)%s" tname (reg e) pid (ctype tl.(pid)) (reg r)
 		| OSwitch (r,idx,eend) ->
 		| OSwitch (r,idx,eend) ->
 			sline "switch(%s) {" (reg r);
 			sline "switch(%s) {" (reg r);
@@ -1397,9 +1420,9 @@ let make_modules ctx all_types =
 	) (List.rev !all_contexts);
 	) (List.rev !all_contexts);
 	!all_modules
 	!all_modules
 
 
-let generate_module_types ctx m =
+let generate_module_types gctx ctx m =
 	let def_name = "INC_" ^ String.concat "__" (ExtString.String.nsplit m.m_name "/") in
 	let def_name = "INC_" ^ String.concat "__" (ExtString.String.nsplit m.m_name "/") in
-	let line = line ctx and expr = expr ctx and sexpr fmt = Printf.ksprintf (expr ctx) fmt in
+	let line = linec ctx and expr = exprc ctx and sexpr fmt = Printf.ksprintf (exprc ctx) fmt in
 	let type_name t =
 	let type_name t =
 		match t with
 		match t with
 		| HObj o | HStruct o -> o.pname
 		| HObj o | HStruct o -> o.pname
@@ -1430,7 +1453,7 @@ let generate_module_types ctx m =
 				| None ->
 				| None ->
 					if not (is_struct t) then expr ("hl_type *$type");
 					if not (is_struct t) then expr ("hl_type *$type");
 				| Some c ->
 				| Some c ->
-					define_type ctx (if is_struct t then HStruct c else HObj c);
+					define_type gctx ctx (if is_struct t then HStruct c else HObj c);
 					loop c);
 					loop c);
 				Array.iteri (fun i (n,_,t) ->
 				Array.iteri (fun i (n,_,t) ->
 					let rec abs_index p v =
 					let rec abs_index p v =
@@ -1438,7 +1461,7 @@ let generate_module_types ctx m =
 						| None -> v
 						| None -> v
 						| Some o -> abs_index o.psuper (Array.length o.pfields + v)
 						| Some o -> abs_index o.psuper (Array.length o.pfields + v)
 					in
 					in
-					define_type ctx t;
+					define_type gctx ctx t;
 					expr (var_type (if n = "" then unamed_field (abs_index o.psuper i) else n) t)
 					expr (var_type (if n = "" then unamed_field (abs_index o.psuper i) else n) t)
 				) o.pfields;
 				) o.pfields;
 			in
 			in
@@ -1452,11 +1475,11 @@ let generate_module_types ctx m =
 					block ctx;
 					block ctx;
 					line "HL__ENUM_CONSTRUCT__";
 					line "HL__ENUM_CONSTRUCT__";
 					Array.iteri (fun i t ->
 					Array.iteri (fun i t ->
-						define_type ctx t;
+						define_type gctx ctx t;
 						expr (var_type ("p" ^ string_of_int i) t)
 						expr (var_type ("p" ^ string_of_int i) t)
 					) pl;
 					) pl;
 					unblock ctx;
 					unblock ctx;
-					sexpr "} %s" (enum_constr_type ctx e i);
+					sexpr "} %s" (enum_constr_type gctx ctx e i);
 				end;
 				end;
 			) e.efields
 			) e.efields
 		| _ ->
 		| _ ->
@@ -1465,43 +1488,36 @@ let generate_module_types ctx m =
 	line "#endif";
 	line "#endif";
 	line ""
 	line ""
 
 
-let write_c com file (code:code) gnames =
+let write_c com file (code:code) gnames num_domains =
 
 
 	let all_types, htypes = gather_types code in
 	let all_types, htypes = gather_types code in
 	let types_ids = make_types_idents htypes in
 	let types_ids = make_types_idents htypes in
 	let gnames = make_global_names code gnames in
 	let gnames = make_global_names code gnames in
 	let bnames = Array.map (fun b -> "bytes$" ^ short_digest (Digest.to_hex (Digest.bytes b))) code.bytes in
 	let bnames = Array.map (fun b -> "bytes$" ^ short_digest (Digest.to_hex (Digest.bytes b))) code.bytes in
-
-	let ctx = {
+	let gctx = {
 		version = com.Gctx.version.version;
 		version = com.Gctx.version.version;
-		out = Buffer.create 1024;
-		tabs = "";
 		hlcode = code;
 		hlcode = code;
+		hash_mutex = Mutex.create();
 		hash_cache = Hashtbl.create 0;
 		hash_cache = Hashtbl.create 0;
 		hash_mem = Hashtbl.create 0;
 		hash_mem = Hashtbl.create 0;
 		hash_cache_list = [];
 		hash_cache_list = [];
 		dir = (match Filename.dirname file with "" -> "." | dir -> String.concat "/" (ExtString.String.nsplit dir "\\"));
 		dir = (match Filename.dirname file with "" -> "." | dir -> String.concat "/" (ExtString.String.nsplit dir "\\"));
-		curfile = "";
 		cfiles = [];
 		cfiles = [];
 		ftable = make_function_table code;
 		ftable = make_function_table code;
 		htypes = types_ids;
 		htypes = types_ids;
 		gnames = gnames;
 		gnames = gnames;
 		bytes_names = bnames;
 		bytes_names = bnames;
-		defines = [];
-		hdefines = Hashtbl.create 0;
-		defined_funs = Hashtbl.create 0;
-		defined_types = PMap.empty;
-		file_prefix = "";
-		fun_index = 0;
 		type_module = PMap.empty;
 		type_module = PMap.empty;
 		gcon = com;
 		gcon = com;
 	} in
 	} in
-	let modules = make_modules ctx all_types in
+	let modules = make_modules gctx all_types in
+	let native_libs = Hashtbl.create 0 in
 
 
-	let line = line ctx and expr = expr ctx in
-	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
+	Path.mkdir_recursive "" (ExtString.String.nsplit (gctx.dir ^ "/hl") "/");
 
 
-	open_file ctx "hl/natives.h";
+	(
+	let ctx = open_file gctx "hl/natives.h" in
+	let line = linec ctx and sexpr fmt = Printf.ksprintf (exprc ctx) fmt in
 	define ctx "#ifndef HL_NATIVES_H";
 	define ctx "#ifndef HL_NATIVES_H";
 	define ctx "#define HL_NATIVES_H";
 	define ctx "#define HL_NATIVES_H";
 	define ctx "// Abstract decls";
 	define ctx "// Abstract decls";
@@ -1515,15 +1531,14 @@ let write_c com file (code:code) gnames =
 	List.iter (fun name -> define ctx (sprintf "typedef struct _%s %s;" name name)) abstracts;
 	List.iter (fun name -> define ctx (sprintf "typedef struct _%s %s;" name name)) abstracts;
 	define ctx "";
 	define ctx "";
 	line "// Natives functions";
 	line "// Natives functions";
-	let native_libs = Hashtbl.create 0 in
 	let sorted_natives = Array.copy code.natives in
 	let sorted_natives = Array.copy code.natives in
 	Array.sort (fun n1 n2 -> let mk (lib,name,_,_) = code.strings.(lib), code.strings.(name) in compare (mk n1) (mk n2)) sorted_natives;
 	Array.sort (fun n1 n2 -> let mk (lib,name,_,_) = code.strings.(lib), code.strings.(name) in compare (mk n1) (mk n2)) sorted_natives;
 	Array.iter (fun (lib,_,_,idx) ->
 	Array.iter (fun (lib,_,_,idx) ->
 		let name = code.strings.(lib) in
 		let name = code.strings.(lib) in
 		let name = if name.[0] = '?' then String.sub name 1 (String.length name - 1) else name in
 		let name = if name.[0] = '?' then String.sub name 1 (String.length name - 1) else name in
 		Hashtbl.replace native_libs name ();
 		Hashtbl.replace native_libs name ();
-		let ft = ctx.ftable.(idx) in
-		define_type ctx (HFun (ft.fe_args,ft.fe_ret));
+		let ft = gctx.ftable.(idx) in
+		define_type gctx ctx (HFun (ft.fe_args,ft.fe_ret));
 		match ft.fe_name with
 		match ft.fe_name with
 		| "hl_tls_get_w" ->
 		| "hl_tls_get_w" ->
 			define ctx "#define hl_tls_get_w(tls) ((vdynamic*)hl_tls_get(tls))";
 			define ctx "#define hl_tls_get_w(tls) ((vdynamic*)hl_tls_get(tls))";
@@ -1534,14 +1549,18 @@ let write_c com file (code:code) gnames =
 	) sorted_natives;
 	) sorted_natives;
 	line "#endif";
 	line "#endif";
 	line "";
 	line "";
+	close_file ctx;
+	);
 
 
-	open_file ctx "hl/globals.c";
+	(
+	let ctx = open_file gctx "hl/globals.c" in
+	let line = linec ctx and expr = exprc ctx and sline fmt = Printf.ksprintf (linec ctx) fmt and sexpr fmt = Printf.ksprintf (exprc ctx) fmt in
 	define ctx "#define HLC_BOOT";
 	define ctx "#define HLC_BOOT";
 	define ctx "#include <hlc.h>";
 	define ctx "#include <hlc.h>";
 	line "// Globals";
 	line "// Globals";
 	Array.iteri (fun i t ->
 	Array.iteri (fun i t ->
 		let name = gnames.(i) in
 		let name = gnames.(i) in
-		define_type ctx t;
+		define_type gctx ctx t;
 		sexpr "%s = 0" (var_type name t)
 		sexpr "%s = 0" (var_type name t)
 	) code.globals;
 	) code.globals;
 	Array.iter (fun (g,fields) ->
 	Array.iter (fun (g,fields) ->
@@ -1552,14 +1571,14 @@ let write_c com file (code:code) gnames =
 			| HI32 ->
 			| HI32 ->
 				Int32.to_string code.ints.(idx)
 				Int32.to_string code.ints.(idx)
 			| HBytes ->
 			| HBytes ->
-				"(vbyte*)" ^ string ctx idx
+				"(vbyte*)" ^ string gctx ctx idx
 			| _ ->
 			| _ ->
 				Globals.die "" __LOC__
 				Globals.die "" __LOC__
 		in
 		in
 		let fields = match t with
 		let fields = match t with
 			| HObj o | HStruct o ->
 			| HObj o | HStruct o ->
 				let fields = List.map2 field_value (List.map (fun (_,_,t) -> t) (Array.to_list o.pfields)) (Array.to_list fields) in
 				let fields = List.map2 field_value (List.map (fun (_,_,t) -> t) (Array.to_list o.pfields)) (Array.to_list fields) in
-				if is_struct t then fields else type_value ctx t :: fields
+				if is_struct t then fields else type_value gctx ctx t :: fields
 			| _ ->
 			| _ ->
 				Globals.die "" __LOC__
 				Globals.die "" __LOC__
 		in
 		in
@@ -1614,40 +1633,45 @@ let write_c com file (code:code) gnames =
 				output_bytes (output_string ch) (Bytes.to_string bytes);
 				output_bytes (output_string ch) (Bytes.to_string bytes);
 				close_out ch;
 				close_out ch;
 			end;
 			end;
-			sline "vbyte %s[] = {" ctx.bytes_names.(i);
+			sline "vbyte %s[] = {" gctx.bytes_names.(i);
 			output ctx (Printf.sprintf "#%s  include \"%s\"\n" ctx.tabs bytes_file);
 			output ctx (Printf.sprintf "#%s  include \"%s\"\n" ctx.tabs bytes_file);
 			sexpr "}";
 			sexpr "}";
 		end else begin
 		end else begin
-			output ctx (Printf.sprintf "vbyte %s[] = {" ctx.bytes_names.(i));
+			output ctx (Printf.sprintf "vbyte %s[] = {" gctx.bytes_names.(i));
 			output_bytes (output ctx) (Bytes.to_string bytes);
 			output_bytes (output ctx) (Bytes.to_string bytes);
 			sexpr "}";
 			sexpr "}";
 		end
 		end
 	) code.bytes;
 	) code.bytes;
+	close_file ctx;
+	save_cfile gctx ctx.curfile;
+	);
 
 
+	(
+	let ctx = open_file gctx "hl/types.c" in
+	let line = linec ctx and sexpr fmt = Printf.ksprintf (exprc ctx) fmt in
 	let type_value ctx t = "&" ^ type_name ctx t in (* no auto import *)
 	let type_value ctx t = "&" ^ type_name ctx t in (* no auto import *)
-	open_file ctx "hl/types.c";
 	define ctx "#define HLC_BOOT";
 	define ctx "#define HLC_BOOT";
 	define ctx "#include <hlc.h>";
 	define ctx "#include <hlc.h>";
 	line "// Types values";
 	line "// Types values";
 	Array.iteri (fun i t ->
 	Array.iteri (fun i t ->
 		match t with
 		match t with
 		| HMethod _ | HFun _ | HVirtual _ ->
 		| HMethod _ | HFun _ | HVirtual _ ->
-			sexpr "hl_type %s = { %s } /* %s */" (type_name ctx t) (type_id t) (tstr t);
+			sexpr "hl_type %s = { %s } /* %s */" (type_name gctx t) (type_id t) (tstr t);
 		| _ ->
 		| _ ->
-			sexpr "hl_type %s = { %s }" (type_name ctx t) (type_id t);
+			sexpr "hl_type %s = { %s }" (type_name gctx t) (type_id t);
 	) all_types;
 	) all_types;
 
 
 	line "";
 	line "";
 	line "// Types values data";
 	line "// Types values data";
 	Array.iter (fun t ->
 	Array.iter (fun t ->
 		let field_value (_,name_id,t) =
 		let field_value (_,name_id,t) =
-			sprintf "{(const uchar*)%s, %s, %ld}" (string ctx name_id) (type_value ctx t) (hash ctx name_id)
+			sprintf "{(const uchar*)%s, %s, %ld}" (string gctx ctx name_id) (type_value gctx t) (hash gctx name_id)
 		in
 		in
 		match t with
 		match t with
 		| HObj o | HStruct o ->
 		| HObj o | HStruct o ->
-			let name = type_name ctx t in
+			let name = type_name gctx t in
 			let proto_value p =
 			let proto_value p =
-				sprintf "{(const uchar*)%s, %d, %d, %ld}" (string ctx p.fid) p.fmethod (match p.fvirtual with None -> -1 | Some i -> i) (hash ctx p.fid)
+				sprintf "{(const uchar*)%s, %d, %d, %ld}" (string gctx ctx p.fid) p.fmethod (match p.fvirtual with None -> -1 | Some i -> i) (hash gctx p.fid)
 			in
 			in
 			let fields =
 			let fields =
 				if Array.length o.pfields = 0 then "NULL" else
 				if Array.length o.pfields = 0 then "NULL" else
@@ -1671,29 +1695,29 @@ let write_c com file (code:code) gnames =
 				string_of_int (Array.length o.pfields);
 				string_of_int (Array.length o.pfields);
 				string_of_int (Array.length o.pproto);
 				string_of_int (Array.length o.pproto);
 				string_of_int (List.length o.pbindings);
 				string_of_int (List.length o.pbindings);
-				sprintf "(const uchar*)%s" (string ctx o.pid);
-				(match o.psuper with None -> "NULL" | Some c -> type_value ctx (match t with HObj _ -> HObj c | _ -> HStruct c));
+				sprintf "(const uchar*)%s" (string gctx ctx o.pid);
+				(match o.psuper with None -> "NULL" | Some c -> type_value gctx (match t with HObj _ -> HObj c | _ -> HStruct c));
 				fields;
 				fields;
 				proto;
 				proto;
 				bindings
 				bindings
 			] in
 			] in
 			sexpr "static hl_type_obj obj%s = {%s}" name (String.concat "," ofields);
 			sexpr "static hl_type_obj obj%s = {%s}" name (String.concat "," ofields);
 		| HEnum e ->
 		| HEnum e ->
-			let ename = type_name ctx t in
+			let ename = type_name gctx t in
 			let constr_value cid (name,nid,tl) =
 			let constr_value cid (name,nid,tl) =
 				let tval = if Array.length tl = 0 then "NULL" else
 				let tval = if Array.length tl = 0 then "NULL" else
 					let name = sprintf "econstruct%s_%d" ename cid in
 					let name = sprintf "econstruct%s_%d" ename cid in
-					sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value ctx) (Array.to_list tl)));
+					sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value gctx) (Array.to_list tl)));
 					name
 					name
 				in
 				in
-				let size = if Array.length tl = 0 then "0" else sprintf "sizeof(%s)" (enum_constr_type ctx e cid) in
+				let size = if Array.length tl = 0 then "0" else sprintf "sizeof(%s)" (enum_constr_type gctx ctx e cid) in
 				let offsets = if Array.length tl = 0 then "NULL" else
 				let offsets = if Array.length tl = 0 then "NULL" else
 					let name = sprintf "eoffsets%s_%d" ename cid in
 					let name = sprintf "eoffsets%s_%d" ename cid in
 					sexpr "static int %s[] = {%s}" name (String.concat "," (List.map (fun _ -> "0") (Array.to_list tl)));
 					sexpr "static int %s[] = {%s}" name (String.concat "," (List.map (fun _ -> "0") (Array.to_list tl)));
 					name
 					name
 				in
 				in
 				let has_ptr = List.exists is_gc_ptr (Array.to_list tl) in
 				let has_ptr = List.exists is_gc_ptr (Array.to_list tl) in
-				sprintf "{(const uchar*)%s, %d, %s, %s, %s, %s}" (string ctx nid) (Array.length tl) tval size (if has_ptr then "true" else "false") offsets
+				sprintf "{(const uchar*)%s, %d, %s, %s, %s, %s}" (string gctx ctx nid) (Array.length tl) tval size (if has_ptr then "true" else "false") offsets
 			in
 			in
 			let constr_name = if Array.length e.efields = 0 then "NULL" else begin
 			let constr_name = if Array.length e.efields = 0 then "NULL" else begin
 				let name = sprintf "econstruct%s" ename in
 				let name = sprintf "econstruct%s" ename in
@@ -1701,13 +1725,13 @@ let write_c com file (code:code) gnames =
 				name;
 				name;
 			end in
 			end in
 			let efields = [
 			let efields = [
-				if e.eid = 0 then "NULL" else sprintf "(const uchar*)%s" (string ctx e.eid);
+				if e.eid = 0 then "NULL" else sprintf "(const uchar*)%s" (string gctx ctx e.eid);
 				string_of_int (Array.length e.efields);
 				string_of_int (Array.length e.efields);
 				constr_name
 				constr_name
 			] in
 			] in
 			sexpr "static hl_type_enum enum%s = {%s}" ename (String.concat "," efields);
 			sexpr "static hl_type_enum enum%s = {%s}" ename (String.concat "," efields);
 		| HVirtual v ->
 		| HVirtual v ->
-			let vname = type_name ctx t in
+			let vname = type_name gctx t in
 			let fields_name =
 			let fields_name =
 				if Array.length v.vfields = 0 then "NULL" else
 				if Array.length v.vfields = 0 then "NULL" else
 				let name = sprintf "vfields%s" vname in
 				let name = sprintf "vfields%s" vname in
@@ -1720,13 +1744,13 @@ let write_c com file (code:code) gnames =
 			] in
 			] in
 			sexpr "static hl_type_virtual virt%s = {%s}" vname (String.concat "," vfields);
 			sexpr "static hl_type_virtual virt%s = {%s}" vname (String.concat "," vfields);
 		| HFun (args,ret) | HMethod(args,ret) ->
 		| HFun (args,ret) | HMethod(args,ret) ->
-			let fname = type_name ctx t in
+			let fname = type_name gctx t in
 			let aname = if args = [] then "NULL" else
 			let aname = if args = [] then "NULL" else
 				let name = sprintf "fargs%s" fname in
 				let name = sprintf "fargs%s" fname in
-				sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value ctx) args));
+				sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value gctx) args));
 				name
 				name
 			in
 			in
-			sexpr "static hl_type_fun tfun%s = {%s,%s,%d}" fname aname (type_value ctx ret) (List.length args)
+			sexpr "static hl_type_fun tfun%s = {%s,%s,%d}" fname aname (type_value gctx ret) (List.length args)
 		| _ ->
 		| _ ->
 			()
 			()
 	) all_types;
 	) all_types;
@@ -1740,7 +1764,7 @@ let write_c com file (code:code) gnames =
 	sexpr "fdump(&ntypes,4)";
 	sexpr "fdump(&ntypes,4)";
 	let fcount = ref 0 in
 	let fcount = ref 0 in
 	Array.iter (fun t ->
 	Array.iter (fun t ->
-		sexpr "t = &%s; fdump(&t, sizeof(void*))" (type_name ctx t);
+		sexpr "t = &%s; fdump(&t, sizeof(void*))" (type_name gctx t);
 		(match t with
 		(match t with
 		| HFun _ -> incr fcount
 		| HFun _ -> incr fcount
 		| _ -> ());
 		| _ -> ());
@@ -1750,7 +1774,7 @@ let write_c com file (code:code) gnames =
 	Array.iter (fun t ->
 	Array.iter (fun t ->
 		match t with
 		match t with
 		| HFun _ ->
 		| HFun _ ->
-			sexpr "t = (hl_type*)&%s.fun->closure_type; fdump(&t, sizeof(void*))" (type_name ctx t);
+			sexpr "t = (hl_type*)&%s.fun->closure_type; fdump(&t, sizeof(void*))" (type_name gctx t);
 		| _ -> ()
 		| _ -> ()
 	) all_types;
 	) all_types;
 	line "#else";
 	line "#else";
@@ -1765,31 +1789,31 @@ let write_c com file (code:code) gnames =
 	Array.iter (fun t ->
 	Array.iter (fun t ->
 		match t with
 		match t with
 		| HObj o | HStruct o ->
 		| HObj o | HStruct o ->
-			let name = type_name ctx t in
+			let name = type_name gctx t in
 			sexpr "obj%s.m = ctx" name;
 			sexpr "obj%s.m = ctx" name;
 			(match o.pclassglobal with
 			(match o.pclassglobal with
 			| None -> ()
 			| None -> ()
 			| Some g ->
 			| Some g ->
-				define_global ctx g;
+				define_global gctx ctx g;
 				sexpr "obj%s.global_value = (void**)&%s" name gnames.(g));
 				sexpr "obj%s.global_value = (void**)&%s" name gnames.(g));
 			sexpr "%s.obj = &obj%s" name name
 			sexpr "%s.obj = &obj%s" name name
 		| HNull r | HRef r | HPacked r ->
 		| HNull r | HRef r | HPacked r ->
-			sexpr "%s.tparam = %s" (type_name ctx t) (type_value ctx r)
+			sexpr "%s.tparam = %s" (type_name gctx t) (type_value gctx r)
 		| HEnum e ->
 		| HEnum e ->
-			let name = type_name ctx t in
+			let name = type_name gctx t in
 			sexpr "%s.tenum = &enum%s" name name;
 			sexpr "%s.tenum = &enum%s" name name;
 			(match e.eglobal with
 			(match e.eglobal with
 			| None -> ()
 			| None -> ()
 			| Some g ->
 			| Some g ->
-				define_global ctx g;
+				define_global gctx ctx g;
 				sexpr "enum%s.global_value = (void**)&%s" name gnames.(g));
 				sexpr "enum%s.global_value = (void**)&%s" name gnames.(g));
 			sexpr "hl_init_enum(&%s,ctx)" name;
 			sexpr "hl_init_enum(&%s,ctx)" name;
 		| HVirtual _ ->
 		| HVirtual _ ->
-			let name = type_name ctx t in
+			let name = type_name gctx t in
 			sexpr "%s.virt = &virt%s" name name;
 			sexpr "%s.virt = &virt%s" name name;
 			sexpr "hl_init_virtual(&%s,ctx)" name;
 			sexpr "hl_init_virtual(&%s,ctx)" name;
 		| HFun _ | HMethod _ ->
 		| HFun _ | HMethod _ ->
-			let name = type_name ctx t in
+			let name = type_name gctx t in
 			sexpr "%s.fun = &tfun%s" name name
 			sexpr "%s.fun = &tfun%s" name name
 		| _ ->
 		| _ ->
 			()
 			()
@@ -1797,22 +1821,41 @@ let write_c com file (code:code) gnames =
 	sexpr "hl_gc_set_dump_types(dump_types)";
 	sexpr "hl_gc_set_dump_types(dump_types)";
 	unblock ctx;
 	unblock ctx;
 	line "}";
 	line "}";
+	close_file ctx;
+	save_cfile gctx ctx.curfile;
+	);
 
 
-	open_file ctx "hl/reflect.c";
+	(
+	let ctx = open_file gctx "hl/reflect.c" in
+	let line = linec ctx in
 	define ctx "#define HLC_BOOT";
 	define ctx "#define HLC_BOOT";
 	define ctx "#include <hlc.h>";
 	define ctx "#include <hlc.h>";
 	line "// Reflection helpers";
 	line "// Reflection helpers";
-	generate_reflection ctx;
-
-	List.iter (fun m ->
+	generate_reflection gctx ctx;
+	close_file ctx;
+	save_cfile gctx ctx.curfile;
+	);
+
+	(
+	let modules = Array.of_list modules in
+	Array.iter (fun m ->
+		let path = Filename.dirname m.m_name in
+		if not (Sys.file_exists (gctx.dir ^ "/" ^ path)) then
+			Path.mkdir_recursive gctx.dir (ExtString.String.nsplit path "/");
+		(* add cfiles in deterministic order *)
+		if m.m_functions <> [] then save_cfile gctx (m.m_name ^ ".c")
+	) modules;
+	Parallel.run_parallel_for num_domains (Array.length modules) (fun idx ->
+		let m = modules.(idx) in
 		let defined_types = ref PMap.empty in
 		let defined_types = ref PMap.empty in
 		if m.m_types <> [] then begin
 		if m.m_types <> [] then begin
-			open_file ctx (m.m_name ^ ".h");
-			generate_module_types ctx m;
+			let ctx = open_file gctx (m.m_name ^ ".h") in
+			generate_module_types gctx ctx m;
 			defined_types := ctx.defined_types;
 			defined_types := ctx.defined_types;
+			close_file ctx;
 		end;
 		end;
 		if m.m_functions <> [] then begin
 		if m.m_functions <> [] then begin
-			open_file ctx (m.m_name ^ ".c");
+			let ctx = open_file gctx (m.m_name ^ ".c") in
 			ctx.defined_types <- !defined_types;
 			ctx.defined_types <- !defined_types;
 			define ctx "#define HLC_BOOT";
 			define ctx "#define HLC_BOOT";
 			define ctx "#include <hlc.h>";
 			define ctx "#include <hlc.h>";
@@ -1826,47 +1869,61 @@ let write_c com file (code:code) gnames =
 					("",0)
 					("",0)
 			in
 			in
 			let funcs = List.sort (fun f1 f2 -> compare (file_pos f1) (file_pos f2)) m.m_functions in
 			let funcs = List.sort (fun f1 f2 -> compare (file_pos f1) (file_pos f2)) m.m_functions in
-			List.iter (fun fe -> match fe.fe_decl with None -> () | Some f -> generate_function ctx f) funcs;
+			List.iter (fun fe -> match fe.fe_decl with None -> () | Some f -> generate_function gctx ctx f) funcs;
+			close_file ctx;
 		end;
 		end;
-	) modules;
+	);
+	);
 
 
-	open_file ctx "hl/functions.c";
+	(
+	let ctx = open_file gctx "hl/functions.c" in
+	let line = linec ctx and sexpr fmt = Printf.ksprintf (exprc ctx) fmt in
 	define ctx "#define HLC_BOOT";
 	define ctx "#define HLC_BOOT";
 	define ctx "#include <hlc.h>";
 	define ctx "#include <hlc.h>";
 	sexpr "void *hl_functions_ptrs[] = {%s}" (String.concat ",\\\n\t" (List.map (fun f ->
 	sexpr "void *hl_functions_ptrs[] = {%s}" (String.concat ",\\\n\t" (List.map (fun f ->
-		let name = define_function ctx f.fe_index in
+		let name = define_function gctx ctx f.fe_index in
 		if name = "hl_tls_get_w" then "hl_tls_get" else name
 		if name = "hl_tls_get_w" then "hl_tls_get" else name
-	) (Array.to_list ctx.ftable)));
+	) (Array.to_list gctx.ftable)));
 	let rec loop i =
 	let rec loop i =
-		if i = Array.length ctx.ftable then [] else
-		let ft = ctx.ftable.(i) in
-		let n = type_name ctx (HFun (ft.fe_args,ft.fe_ret)) in
+		if i = Array.length gctx.ftable then [] else
+		let ft = gctx.ftable.(i) in
+		let n = type_name gctx (HFun (ft.fe_args,ft.fe_ret)) in
 		define ctx (sprintf "extern hl_type %s;" n);
 		define ctx (sprintf "extern hl_type %s;" n);
 		("&" ^ n) :: loop (i + 1)
 		("&" ^ n) :: loop (i + 1)
 	in
 	in
 	sexpr "hl_type *hl_functions_types[] = {%s}" (String.concat ",\\\n\t" (loop 0));
 	sexpr "hl_type *hl_functions_types[] = {%s}" (String.concat ",\\\n\t" (loop 0));
 	line "";
 	line "";
 	Array.iter (fun f ->
 	Array.iter (fun f ->
-		if f.fe_module = None then (match f.fe_decl with None -> () | Some f -> generate_function ctx f);
-	) ctx.ftable;
-
-	open_file ctx "hl/hashes.c";
+		if f.fe_module = None then (match f.fe_decl with None -> () | Some f -> generate_function gctx ctx f);
+	) gctx.ftable;
+	close_file ctx;
+	save_cfile gctx ctx.curfile;
+	);
+
+	(
+	let ctx = open_file gctx "hl/hashes.c" in
+	let line = linec ctx and sexpr fmt = Printf.ksprintf (exprc ctx) fmt in
 	define ctx "#define HLC_BOOT";
 	define ctx "#define HLC_BOOT";
 	define ctx "#include <hlc.h>";
 	define ctx "#include <hlc.h>";
 	line "";
 	line "";
 	line "void hl_init_hashes() {";
 	line "void hl_init_hashes() {";
 	block ctx;
 	block ctx;
-	List.iter (fun i -> sexpr "hl_hash((vbyte*)%s)" (string ctx i)) (List.rev ctx.hash_cache_list);
+	List.iter (fun i -> sexpr "hl_hash((vbyte*)%s)" (string gctx ctx i)) (List.rev gctx.hash_cache_list);
 	unblock ctx;
 	unblock ctx;
 	line "}";
 	line "}";
+	close_file ctx;
+	save_cfile gctx ctx.curfile;
+	);
 
 
-	open_file ctx (Filename.basename file);
+	(
+	let ctx = open_file gctx (Filename.basename file) in
+	let line = linec ctx and expr = exprc ctx and sline fmt = Printf.ksprintf (linec ctx) fmt and sexpr fmt = Printf.ksprintf (exprc ctx) fmt in
 	define ctx "#define HLC_BOOT";
 	define ctx "#define HLC_BOOT";
 	define ctx "#include <hlc.h>";
 	define ctx "#include <hlc.h>";
 	line "#include <hlc_main.c>";
 	line "#include <hlc_main.c>";
 	line "";
 	line "";
 	line "#ifndef HL_MAKE";
 	line "#ifndef HL_MAKE";
-	List.iter (sline "#  include <%s>") ctx.cfiles;
+	List.iter (sline "#  include <%s>") gctx.cfiles;
 	line "#endif";
 	line "#endif";
 	line "";
 	line "";
 	expr "void hl_init_hashes()";
 	expr "void hl_init_hashes()";
@@ -1885,16 +1942,20 @@ let write_c com file (code:code) gnames =
 	expr "hl_init_types(&ctx)";
 	expr "hl_init_types(&ctx)";
 	expr "hl_init_hashes()";
 	expr "hl_init_hashes()";
 	expr "hl_init_roots()";
 	expr "hl_init_roots()";
-	if code.entrypoint >= 0 then sexpr "%s()" (define_function ctx code.entrypoint);
+	if code.entrypoint >= 0 then sexpr "%s()" (define_function gctx ctx code.entrypoint);
 	unblock ctx;
 	unblock ctx;
 	line "}";
 	line "}";
 	line "";
 	line "";
+	close_file ctx;
+	save_cfile gctx ctx.curfile;
+	);
 
 
-	open_file ctx "hlc.json";
-
+	(
+	let ctx = open_file gctx "hlc.json" in
+	let line = linec ctx and sline fmt = Printf.ksprintf (linec ctx) fmt in
 	line "{";
 	line "{";
 	block ctx;
 	block ctx;
-	sline "\"version\" : %d," ctx.version;
+	sline "\"version\" : %d," gctx.version;
 	sline "\"libs\" : [%s]," (String.concat "," (Hashtbl.fold (fun k _ acc -> sprintf "\"%s\"" k :: acc) native_libs []));
 	sline "\"libs\" : [%s]," (String.concat "," (Hashtbl.fold (fun k _ acc -> sprintf "\"%s\"" k :: acc) native_libs []));
 	let defines = Buffer.create 64 in
 	let defines = Buffer.create 64 in
 	PMap.iter (fun key value ->
 	PMap.iter (fun key value ->
@@ -1902,8 +1963,8 @@ let write_c com file (code:code) gnames =
 	) com.defines.values;
 	) com.defines.values;
 	Buffer.truncate defines (Buffer.length defines - 1);
 	Buffer.truncate defines (Buffer.length defines - 1);
 	sline "\"defines\" : {%s\n\t}," (Buffer.contents defines);
 	sline "\"defines\" : {%s\n\t}," (Buffer.contents defines);
-	sline "\"files\" : [%s\n\t]" (String.concat "," (List.map (sprintf "\n\t\t\"%s\"") ctx.cfiles));
+	sline "\"files\" : [%s\n\t]" (String.concat "," (List.map (sprintf "\n\t\t\"%s\"") gctx.cfiles));
 	unblock ctx;
 	unblock ctx;
 	line "}";
 	line "}";
-
-	close_file ctx
+	close_file ctx;
+	);

+ 1 - 0
src/generators/hlcode.ml

@@ -213,6 +213,7 @@ type fundecl = {
 	code : opcode array;
 	code : opcode array;
 	debug : (int * int * Globals.pos) array;
 	debug : (int * int * Globals.pos) array;
 	assigns : (string index * int) array;
 	assigns : (string index * int) array;
+	need_opt : bool;
 }
 }
 
 
 type code = {
 type code = {

+ 8 - 7
src/generators/hlopt.ml

@@ -547,7 +547,8 @@ let remap_fun ctx f dump get_str old_code =
 	let nregs = Array.length f.regs in
 	let nregs = Array.length f.regs in
 	let reg_remap = ctx.r_used_regs <> nregs in
 	let reg_remap = ctx.r_used_regs <> nregs in
 	let assigns = ref f.assigns in
 	let assigns = ref f.assigns in
-	let write str = match dump with None -> () | Some ch -> IO.nwrite ch (Bytes.unsafe_of_string (str ^ "\n")) in
+	let dump_buffer = if dump then Buffer.create 1024 else Buffer.create 0  in
+	let write str = if dump then Buffer.add_string dump_buffer (str ^ "\n") else () in
 	let nargs = (match f.ftype with HFun (args,_) -> List.length args | _ -> Globals.die "" __LOC__) in
 	let nargs = (match f.ftype with HFun (args,_) -> List.length args | _ -> Globals.die "" __LOC__) in
 
 
 	let live_bits = ctx.r_live_bits in
 	let live_bits = ctx.r_live_bits in
@@ -620,7 +621,7 @@ let remap_fun ctx f dump get_str old_code =
 	end;
 	end;
 
 
 	(* done *)
 	(* done *)
-	if dump <> None then begin
+	if dump then begin
 		let old_assigns = Hashtbl.create 0 in
 		let old_assigns = Hashtbl.create 0 in
 		let new_assigns = Hashtbl.create 0 in
 		let new_assigns = Hashtbl.create 0 in
 		Array.iter (fun (var,pos) -> if pos >= 0 then Hashtbl.replace old_assigns pos var) f.assigns;
 		Array.iter (fun (var,pos) -> if pos >= 0 then Hashtbl.replace old_assigns pos var) f.assigns;
@@ -672,7 +673,6 @@ let remap_fun ctx f dump get_str old_code =
 		loop 0 ctx.r_root;
 		loop 0 ctx.r_root;
 		write "";
 		write "";
 		write "";
 		write "";
-		(match dump with None -> () | Some ch -> IO.flush ch);
 	end;
 	end;
 
 
 	let code = ref f.code in
 	let code = ref f.code in
@@ -739,7 +739,8 @@ let remap_fun ctx f dump get_str old_code =
 			regs := new_regs;
 			regs := new_regs;
 		end;
 		end;
 	end;
 	end;
-	{ f with code = !code; regs = !regs; debug = !debug; assigns = !assigns }
+	let dump_str = Buffer.contents dump_buffer in
+	({ f with code = !code; regs = !regs; debug = !debug; assigns = !assigns }, dump_str)
 
 
 let _optimize (f:fundecl) =
 let _optimize (f:fundecl) =
 	let nregs = Array.length f.regs in
 	let nregs = Array.length f.regs in
@@ -1059,8 +1060,8 @@ type cache_elt = {
 let opt_cache = ref PMap.empty
 let opt_cache = ref PMap.empty
 let used_mark = ref 0
 let used_mark = ref 0
 
 
-let optimize dump get_str (f:fundecl) (hxf:Type.tfunc) =
-	let old_code = match dump with None -> f.code | Some _ -> Array.copy f.code in
+let optimize dump get_str (f:fundecl) (hxf:string) =
+	let old_code = if dump then Array.copy f.code else f.code in
 	try
 	try
 		let c = PMap.find hxf (!opt_cache) in
 		let c = PMap.find hxf (!opt_cache) in
 		c.c_last_used <- !used_mark;
 		c.c_last_used <- !used_mark;
@@ -1095,7 +1096,7 @@ let optimize dump get_str (f:fundecl) (hxf:Type.tfunc) =
 		let fopt = remap_fun rctx f dump get_str old_code in
 		let fopt = remap_fun rctx f dump get_str old_code in
 		Hashtbl.iter (fun _ b ->
 		Hashtbl.iter (fun _ b ->
 			b.bstate <- None;
 			b.bstate <- None;
-			if dump = None then begin
+			if not dump then begin
 				b.bneed <- ISet.empty;
 				b.bneed <- ISet.empty;
 				b.bneed_all <- None;
 				b.bneed_all <- None;
 			end;
 			end;