Browse Source

added method wrapper allocation

Nicolas Cannasse 9 years ago
parent
commit
a18194a56e
1 changed files with 58 additions and 3 deletions
  1. 58 3
      genhl.ml

+ 58 - 3
genhl.ml

@@ -242,6 +242,7 @@ type context = {
 	mutable cached_types : (path, ttype) PMap.t;
 	mutable m : method_context;
 	mutable anons_cache : (tanon * ttype) list;
+	mutable method_wrappers : ((ttype * ttype), int) PMap.t;
 	array_impl : array_impl;
 }
 
@@ -372,6 +373,14 @@ let null_proto =
 		pfunctions = PMap.empty;
 	}
 
+let null_capture =
+	{
+		c_reg = 0;
+		c_vars = [||];
+		c_map = PMap.empty;
+		c_type = HVoid;
+	}
+
 let lookup l v fb =
 	try
 		PMap.find v l.map
@@ -382,6 +391,11 @@ let lookup l v fb =
 		DynArray.set l.arr id (fb());
 		id
 
+let lookup_alloc l v =
+	let id = DynArray.length l.arr in
+	DynArray.add l.arr v;
+	id
+
 let method_context t captured =
 	{
 		mregs = new_lookup();
@@ -718,6 +732,9 @@ let rec eval_to ctx e (t:ttype) =
 
 and cast_to ctx (r:reg) (t:ttype) p =
 	let rt = rtype ctx r in
+	let invalid() =
+		error ("Don't know how to cast " ^ tstr rt ^ " to " ^ tstr t) p
+	in
 	if safe_cast rt t then r else
 	match rt, t with
 	| HVirtual _, HDyn None ->
@@ -766,8 +783,18 @@ and cast_to ctx (r:reg) (t:ttype) p =
 		let tmp = alloc_tmp ctx (HDyn (Some rt)) in
 		op ctx (OToDyn (tmp, r));
 		tmp
+	| HFun (args1,ret1), HFun (args2, ret2) when List.length args1 = List.length args2 && List.for_all2 safe_cast args2 args1 ->
+		if safe_cast ret1 ret2 then
+			r
+		else if ret2 = HDyn None then begin
+			let fid = gen_method_wrapper ctx rt t p in
+			let fr = alloc_tmp ctx t in
+			op ctx (OClosure (fr,fid,r));
+			fr
+		end else
+			invalid()
 	| _ ->
-		error ("Don't know how to cast " ^ tstr rt ^ " to " ^ tstr t) p
+		invalid()
 
 and get_access ctx e =
 	match e.eexpr with
@@ -1634,7 +1661,7 @@ and eval_expr ctx e =
 			) cases;
 			List.iter (fun j -> j()) (!jends);
 		with Exit ->
-			assert false);
+			error "Unsupported switch" e.epos);
 		r
 	| TEnumParameter (ec,f,index) ->
 		let r = alloc_tmp ctx (to_type ctx e.etype) in
@@ -1723,6 +1750,33 @@ and build_capture_vars ctx f =
 		c_reg = 0;
 	}
 
+and gen_method_wrapper ctx rt t p =
+	try
+		PMap.find (rt,t) ctx.method_wrappers
+	with Not_found ->
+		let fid = lookup_alloc ctx.cfids () in
+		let old = ctx.m in
+		let targs, tret = (match t with HFun (args, ret) -> args, ret | _ -> assert false) in
+		let iargs, iret = (match rt with HFun (args, ret) -> args, ret | _ -> assert false) in
+		ctx.m <- method_context (HDyn None) null_capture;
+
+		let rfun = alloc_tmp ctx rt in
+		let rargs = List.map (alloc_tmp ctx) targs in
+
+		let rret = alloc_tmp ctx iret in
+		op ctx (OCallClosure (rret,rfun,List.map2 (fun r t -> cast_to ctx r t p) rargs iargs));
+		op ctx (ORet (cast_to ctx rret tret p));
+
+		let f = {
+			findex = fid;
+			ftype = HFun (rt :: targs, tret);
+			regs = DynArray.to_array ctx.m.mregs.arr;
+			code = DynArray.to_array ctx.m.mops;
+		} in
+		ctx.m <- old;
+		DynArray.add ctx.cfunctions f;
+		fid
+
 and make_fun ctx fidx f cthis cparent =
 	let old = ctx.m in
 	let capt = build_capture_vars ctx f in
@@ -3365,7 +3419,7 @@ let generate com =
 	in
 	let ctx = {
 		com = com;
-		m = method_context HVoid { c_reg = 0; c_vars = [||]; c_map = PMap.empty; c_type = HVoid; };
+		m = method_context HVoid null_capture;
 		cints = new_lookup();
 		cstrings = new_lookup();
 		cfloats = new_lookup();
@@ -3382,6 +3436,7 @@ let generate com =
 			af64 = get_class "ArrayF64";
 		};
 		anons_cache = [];
+		method_wrappers = PMap.empty;
 	} in
 	ignore(alloc_string ctx "");
 	let all_classes = Hashtbl.create 0 in