Преглед изворни кода

Inline ctors improved handling of ignored exprs. (#11356)

This commit changes the captured argument of analyze_aliases from a
boolean into a three value enum.
What used to be captured = false is now IEHNotHandled.
What used to be captured = true is now split between IEHCaptured and
IEHIgnored.
Knowing that the value will be ignored allows if and try expressions to
not cancel the inlining of their bodies.
Mario Carbajal пре 1 година
родитељ
комит
01dde74b8a
2 измењених фајлова са 65 додато и 23 уклоњено
  1. 50 23
      src/optimization/inlineConstructors.ml
  2. 15 0
      tests/optimization/src/TestInlineConstructors.hx

+ 50 - 23
src/optimization/inlineConstructors.ml

@@ -107,6 +107,15 @@ and inline_object_field =
 	| IOFInlineVar of inline_var
 	| IOFInlineVar of inline_var
 	| IOFNone
 	| IOFNone
 
 
+(*
+	inline_expression_handled
+	Defines what will happen to the expression being analized by analyze_aliases
+*)
+and inline_expression_handled = 
+	| IEHCaptured (* The expression will be assigned to a variable *)
+	| IEHIgnored (* The result of the expression will not be used *)
+	| IEHNotHandled (* Cases that are not handled (usually leads to cancelling inlining *)
+
 let inline_constructors ctx original_e =
 let inline_constructors ctx original_e =
 	let inline_objs = ref IntMap.empty in
 	let inline_objs = ref IntMap.empty in
 	let vars = ref IntMap.empty in
 	let vars = ref IntMap.empty in
@@ -259,7 +268,7 @@ let inline_constructors ctx original_e =
 
 
 		e: The expression to analyze
 		e: The expression to analyze
 	*)
 	*)
-	let rec analyze_aliases (seen_ctors:tclass_field list) (captured:bool) (is_lvalue:bool) (e:texpr) : inline_var option =
+	let rec analyze_aliases (seen_ctors:tclass_field list) (captured:inline_expression_handled) (is_lvalue:bool) (e:texpr) : inline_var option =
 		let mk_io ?(has_untyped=false) (iok : inline_object_kind) (id:int) (expr:texpr) : inline_object =
 		let mk_io ?(has_untyped=false) (iok : inline_object_kind) (id:int) (expr:texpr) : inline_object =
 			let io = {
 			let io = {
 				io_kind = iok;
 				io_kind = iok;
@@ -297,8 +306,8 @@ let inline_constructors ctx original_e =
 			| _ -> None
 			| _ -> None
 			end
 			end
 		in
 		in
-		let handle_field_case ?(captured=false) ?(is_lvalue=false) efield ethis fname validate_io : inline_object_field =
-			begin match analyze_aliases true ethis with
+		let handle_field_case ?(captured=IEHNotHandled) ?(is_lvalue=false) efield ethis fname validate_io : inline_object_field =
+			begin match analyze_aliases IEHCaptured ethis with
 			| Some({iv_state = IVSAliasing io} as iv) when validate_io io ->
 			| Some({iv_state = IVSAliasing io} as iv) when validate_io io ->
 				begin match get_io_inline_method io fname with
 				begin match get_io_inline_method io fname with
 				| Some(c, tl, cf, tf)->
 				| Some(c, tl, cf, tf)->
@@ -321,7 +330,7 @@ let inline_constructors ctx original_e =
 							warning ctx WConstructorInliningCancelled ("Constructor inlining cancelled because of use of uninitialized member field " ^ fname) ethis.epos;
 							warning ctx WConstructorInliningCancelled ("Constructor inlining cancelled because of use of uninitialized member field " ^ fname) ethis.epos;
 							raise Not_found
 							raise Not_found
 						);
 						);
-						if not captured then cancel_iv fiv efield.epos;
+						if captured == IEHNotHandled then cancel_iv fiv efield.epos;
 						IOFInlineVar(fiv)
 						IOFInlineVar(fiv)
 					with Not_found ->
 					with Not_found ->
 						cancel_iv iv efield.epos;
 						cancel_iv iv efield.epos;
@@ -343,7 +352,7 @@ let inline_constructors ctx original_e =
 		let handle_default_case e =
 		let handle_default_case e =
 			let old = !scoped_ivs in
 			let old = !scoped_ivs in
 			scoped_ivs := [];
 			scoped_ivs := [];
-			let f e = ignore(analyze_aliases false e) in
+			let f e = ignore(analyze_aliases IEHNotHandled e) in
 			Type.iter f e;
 			Type.iter f e;
 			List.iter (fun iv -> iv.iv_closed <- true) !scoped_ivs;
 			List.iter (fun iv -> iv.iv_closed <- true) !scoped_ivs;
 			scoped_ivs := old;
 			scoped_ivs := old;
@@ -357,7 +366,7 @@ let inline_constructors ctx original_e =
 					| _ ->
 					| _ ->
 						let v = alloc_var VGenerated "arg" e.etype e.epos in
 						let v = alloc_var VGenerated "arg" e.etype e.epos in
 						let decle = mk (TVar(v, Some e)) ctx.t.tvoid e.epos in
 						let decle = mk (TVar(v, Some e)) ctx.t.tvoid e.epos in
-						ignore(analyze_aliases true decle);
+						ignore(analyze_aliases IEHIgnored decle);
 						let mde = (Meta.InlineConstructorArgument (v.v_id, 0)), [], e.epos in
 						let mde = (Meta.InlineConstructorArgument (v.v_id, 0)), [], e.epos in
 						let e = mk (TMeta(mde, e)) e.etype e.epos in
 						let e = mk (TMeta(mde, e)) e.etype e.epos in
 						loop (v::vs, e::es) el
 						loop (v::vs, e::es) el
@@ -369,7 +378,7 @@ let inline_constructors ctx original_e =
 		let handle_inline_object_case (io_id:int) (force_inline:bool) (e:texpr) =
 		let handle_inline_object_case (io_id:int) (force_inline:bool) (e:texpr) =
 			match e.eexpr, e.etype with
 			match e.eexpr, e.etype with
 			| TNew({ cl_constructor = Some ({cf_expr = Some ({eexpr = TFunction tf})} as cf)} as c,tl,pl),_
 			| TNew({ cl_constructor = Some ({cf_expr = Some ({eexpr = TFunction tf})} as cf)} as c,tl,pl),_
-				when captured && not (List.memq cf seen_ctors) ->
+				when captured!=IEHNotHandled && not (List.memq cf seen_ctors) ->
 				begin
 				begin
 					let argvs, pl = analyze_call_args pl in
 					let argvs, pl = analyze_call_args pl in
 					let _, cname = c.cl_path in
 					let _, cname = c.cl_path in
@@ -395,12 +404,12 @@ let inline_constructors ctx original_e =
 					in loop c tl;
 					in loop c tl;
 					let iv = add v IVKLocal in
 					let iv = add v IVKLocal in
 					set_iv_alias iv io;
 					set_iv_alias iv io;
-					ignore(analyze_aliases_in_ctor cf true io.io_expr);
+					ignore(analyze_aliases_in_ctor cf IEHIgnored io.io_expr);
 					Some iv
 					Some iv
 				end
 				end
 			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some _} as cf)} as c,_,pl),_ when is_extern_ctor c cf ->
 			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some _} as cf)} as c,_,pl),_ when is_extern_ctor c cf ->
 				raise_typing_error "Extern constructor could not be inlined" e.epos;
 				raise_typing_error "Extern constructor could not be inlined" e.epos;
-			| TObjectDecl fl, _ when captured && fl <> [] && List.for_all (fun((s,_,_),_) -> Lexer.is_valid_identifier s) fl ->
+			| TObjectDecl fl, _ when captured!=IEHNotHandled && fl <> [] && List.for_all (fun((s,_,_),_) -> Lexer.is_valid_identifier s) fl ->
 				let v = alloc_var VGenerated "inlobj" e.etype e.epos in
 				let v = alloc_var VGenerated "inlobj" e.etype e.epos in
 				let ev = mk (TLocal v) v.v_type e.epos in
 				let ev = mk (TLocal v) v.v_type e.epos in
 				let el = List.map (fun ((s,_,_),e) ->
 				let el = List.map (fun ((s,_,_),e) ->
@@ -413,9 +422,9 @@ let inline_constructors ctx original_e =
 				List.iter (fun ((s,_,_),e) -> ignore(alloc_io_field io s e.etype v.v_pos)) fl;
 				List.iter (fun ((s,_,_),e) -> ignore(alloc_io_field io s e.etype v.v_pos)) fl;
 				let iv = add v IVKLocal in
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
 				set_iv_alias iv io;
-				List.iter (fun e -> ignore(analyze_aliases true e)) el;
+				List.iter (fun e -> ignore(analyze_aliases IEHIgnored e)) el;
 				Some iv
 				Some iv
-			| TArrayDecl el, TInst(_, [elemtype]) when captured ->
+			| TArrayDecl el, TInst(_, [elemtype]) when captured!=IEHNotHandled ->
 				let len = List.length el in
 				let len = List.length el in
 				let v = alloc_var VGenerated "inlarr" e.etype e.epos in
 				let v = alloc_var VGenerated "inlarr" e.etype e.epos in
 				let ev = mk (TLocal v) v.v_type e.epos in
 				let ev = mk (TLocal v) v.v_type e.epos in
@@ -429,7 +438,7 @@ let inline_constructors ctx original_e =
 				for i = 0 to len-1 do ignore(alloc_io_field io (int_field_name i) elemtype v.v_pos) done;
 				for i = 0 to len-1 do ignore(alloc_io_field io (int_field_name i) elemtype v.v_pos) done;
 				let iv = add v IVKLocal in
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
 				set_iv_alias iv io;
-				List.iter (fun e -> ignore(analyze_aliases true e)) el;
+				List.iter (fun e -> ignore(analyze_aliases IEHIgnored e)) el;
 				Some iv
 				Some iv
 			| _ ->
 			| _ ->
 				handle_default_case e
 				handle_default_case e
@@ -443,7 +452,7 @@ let inline_constructors ctx original_e =
 			handle_inline_object_case io_id false e
 			handle_inline_object_case io_id false e
 		| TVar(v,None) -> ignore(add v IVKLocal); None
 		| TVar(v,None) -> ignore(add v IVKLocal); None
 		| TVar(v,Some rve) ->
 		| TVar(v,Some rve) ->
-			begin match analyze_aliases true rve with
+			begin match analyze_aliases IEHCaptured rve with
 			| Some({iv_state = IVSAliasing(io)}) ->
 			| Some({iv_state = IVSAliasing(io)}) ->
 				let iv = add v IVKLocal in
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
 				set_iv_alias iv io;
@@ -453,15 +462,15 @@ let inline_constructors ctx original_e =
 		| TBinop(OpAssign, lve, rve) ->
 		| TBinop(OpAssign, lve, rve) ->
 			begin match analyze_aliases_in_lvalue lve with
 			begin match analyze_aliases_in_lvalue lve with
 			| Some({iv_state = IVSUnassigned} as iv) ->
 			| Some({iv_state = IVSUnassigned} as iv) ->
-				begin match analyze_aliases true rve with
+				begin match analyze_aliases IEHCaptured rve with
 				| Some({iv_state = IVSAliasing(io)}) ->
 				| Some({iv_state = IVSAliasing(io)}) ->
 					scoped_ivs := iv :: !scoped_ivs;
 					scoped_ivs := iv :: !scoped_ivs;
 					set_iv_alias iv io
 					set_iv_alias iv io
 				| _ -> cancel_iv iv lve.epos
 				| _ -> cancel_iv iv lve.epos
 				end;
 				end;
 				Some iv
 				Some iv
-			| Some(iv) -> cancel_iv iv e.epos; ignore(analyze_aliases false rve); None
-			| _ -> ignore(analyze_aliases false rve); None
+			| Some(iv) -> cancel_iv iv e.epos; ignore(analyze_aliases IEHNotHandled rve); None
+			| _ -> ignore(analyze_aliases IEHNotHandled rve); None
 			end
 			end
 		| TField(ethis, fa) ->
 		| TField(ethis, fa) ->
 			handle_field_case_no_methods e ethis (field_name fa) (fun _ -> true)
 			handle_field_case_no_methods e ethis (field_name fa) (fun _ -> true)
@@ -471,19 +480,19 @@ let inline_constructors ctx original_e =
 			handle_field_case_no_methods e ethis (int_field_name i) validate_io
 			handle_field_case_no_methods e ethis (int_field_name i) validate_io
 		| TLocal(v) when v.v_id < 0 ->
 		| TLocal(v) when v.v_id < 0 ->
 			let iv = get_iv v.v_id in
 			let iv = get_iv v.v_id in
-			if iv.iv_closed || not captured then cancel_iv iv e.epos;
+			if iv.iv_closed || captured==IEHNotHandled then cancel_iv iv e.epos;
 			Some iv
 			Some iv
 		| TBlock(el) ->
 		| TBlock(el) ->
 			let rec loop = function
 			let rec loop = function
 				| [e] -> analyze_aliases captured e
 				| [e] -> analyze_aliases captured e
-				| e::el -> ignore(analyze_aliases true e); loop (el)
+				| e::el -> ignore(analyze_aliases IEHIgnored e); loop (el)
 				| [] -> None
 				| [] -> None
 			in loop el
 			in loop el
 		| TMeta((Meta.InlineConstructorArgument (vid,_),_,_),_) ->
 		| TMeta((Meta.InlineConstructorArgument (vid,_),_,_),_) ->
 			(* The contents have already been analyzed, so we must skip the wrapped expression *)
 			(* The contents have already been analyzed, so we must skip the wrapped expression *)
 			(try
 			(try
 				let iv = get_iv vid in
 				let iv = get_iv vid in
-				if iv.iv_closed || not captured then cancel_iv iv e.epos;
+				if iv.iv_closed || captured==IEHNotHandled then cancel_iv iv e.epos;
 				Some(get_iv vid)
 				Some(get_iv vid)
 			with Not_found -> None)
 			with Not_found -> None)
 		| TParenthesis e | TMeta(_,e) | TCast(e,None) ->
 		| TParenthesis e | TMeta(_,e) | TCast(e,None) ->
@@ -517,14 +526,32 @@ let inline_constructors ctx original_e =
 				end
 				end
 			| IOFInlineVar(iv) ->
 			| IOFInlineVar(iv) ->
 				cancel_iv iv e.epos;
 				cancel_iv iv e.epos;
-				List.iter (fun ca -> ignore(analyze_aliases false ca)) call_args;
+				List.iter (fun ca -> ignore(analyze_aliases IEHNotHandled ca)) call_args;
 				None
 				None
 			| IOFNone ->
 			| IOFNone ->
-				List.iter (fun ca -> ignore(analyze_aliases false ca)) call_args;
+				List.iter (fun ca -> ignore(analyze_aliases IEHNotHandled ca)) call_args;
 				None
 				None
 			end
 			end
 		| TFunction tf ->
 		| TFunction tf ->
-			analyze_aliases true tf.tf_expr
+			let old = !scoped_ivs in
+			scoped_ivs := [];
+			ignore(analyze_aliases IEHIgnored tf.tf_expr);
+			List.iter (fun iv -> iv.iv_closed <- true) !scoped_ivs;
+			scoped_ivs := old;
+			None
+		| TWhile(condition, body, _)  ->
+			ignore(analyze_aliases IEHNotHandled condition);
+			ignore(analyze_aliases IEHIgnored body);
+			None
+		| TIf (e,e1,e2) when captured=IEHIgnored ->
+			ignore(analyze_aliases IEHNotHandled e);
+			ignore(analyze_aliases IEHIgnored e1);
+			(match e2 with None -> () | Some e -> ignore(analyze_aliases IEHIgnored e));
+			None
+		| TTry (e,catches) when captured==IEHIgnored ->
+			ignore(analyze_aliases IEHIgnored e);
+			List.iter (fun (_,e) -> ignore(analyze_aliases IEHIgnored e)) catches;
+			None
 		| _ ->
 		| _ ->
 			handle_default_case e
 			handle_default_case e
 	in
 	in
@@ -690,7 +717,7 @@ let inline_constructors ctx original_e =
 	in
 	in
 	if not (check_for_ctors original_e) then original_e else
 	if not (check_for_ctors original_e) then original_e else
 	let e = mark_ctors original_e in
 	let e = mark_ctors original_e in
-	ignore(analyze_aliases [] false false e);
+	ignore(analyze_aliases [] IEHNotHandled false e);
 	if IntMap.for_all (fun _ io -> io.io_cancelled) !inline_objs then begin
 	if IntMap.for_all (fun _ io -> io.io_cancelled) !inline_objs then begin
 		IntMap.iter (fun _ iv -> let v = iv.iv_var in if v.v_id < 0 then v.v_id <- -v.v_id ) !vars;
 		IntMap.iter (fun _ iv -> let v = iv.iv_var in if v.v_id < 0 then v.v_id <- -v.v_id ) !vars;
 		original_e
 		original_e

+ 15 - 0
tests/optimization/src/TestInlineConstructors.hx

@@ -19,6 +19,12 @@ class InlineClass {
 	}
 	}
 }
 }
 
 
+class ExternInlineClass {
+	public var a = 1;
+	public extern inline function new() {
+	}
+}
+
 class InlineIterator {
 class InlineIterator {
 	public var i = 0;
 	public var i = 0;
 	public inline function new() {};
 	public inline function new() {};
@@ -130,4 +136,13 @@ class TestInlineConstructors extends TestBase {
 		}
 		}
 		return acc;
 		return acc;
 	}
 	}
+
+	static var condition = false;
+	static function testIgnoredValuesNotCancelling() {
+		var a = new ExternInlineClass();
+		if ( condition ) a else a;
+		while ( condition ) a;
+		try { a; } catch(_) { a; };
+		return a.a;
+	}
 }
 }