Kaynağa Gözat

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 yıl önce
ebeveyn
işleme
01dde74b8a

+ 50 - 23
src/optimization/inlineConstructors.ml

@@ -107,6 +107,15 @@ and inline_object_field =
 	| IOFInlineVar of inline_var
 	| 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_objs = 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
 	*)
-	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 io = {
 				io_kind = iok;
@@ -297,8 +306,8 @@ let inline_constructors ctx original_e =
 			| _ -> None
 			end
 		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 ->
 				begin match get_io_inline_method io fname with
 				| 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;
 							raise Not_found
 						);
-						if not captured then cancel_iv fiv efield.epos;
+						if captured == IEHNotHandled then cancel_iv fiv efield.epos;
 						IOFInlineVar(fiv)
 					with Not_found ->
 						cancel_iv iv efield.epos;
@@ -343,7 +352,7 @@ let inline_constructors ctx original_e =
 		let handle_default_case e =
 			let old = !scoped_ivs in
 			scoped_ivs := [];
-			let f e = ignore(analyze_aliases false e) in
+			let f e = ignore(analyze_aliases IEHNotHandled e) in
 			Type.iter f e;
 			List.iter (fun iv -> iv.iv_closed <- true) !scoped_ivs;
 			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 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 e = mk (TMeta(mde, e)) e.etype e.epos in
 						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) =
 			match e.eexpr, e.etype with
 			| 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
 					let argvs, pl = analyze_call_args pl in
 					let _, cname = c.cl_path in
@@ -395,12 +404,12 @@ let inline_constructors ctx original_e =
 					in loop c tl;
 					let iv = add v IVKLocal in
 					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
 				end
 			| 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;
-			| 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 ev = mk (TLocal v) v.v_type e.epos in
 				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;
 				let iv = add v IVKLocal in
 				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
-			| TArrayDecl el, TInst(_, [elemtype]) when captured ->
+			| TArrayDecl el, TInst(_, [elemtype]) when captured!=IEHNotHandled ->
 				let len = List.length el in
 				let v = alloc_var VGenerated "inlarr" e.etype 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;
 				let iv = add v IVKLocal in
 				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
 			| _ ->
 				handle_default_case e
@@ -443,7 +452,7 @@ let inline_constructors ctx original_e =
 			handle_inline_object_case io_id false e
 		| TVar(v,None) -> ignore(add v IVKLocal); None
 		| TVar(v,Some rve) ->
-			begin match analyze_aliases true rve with
+			begin match analyze_aliases IEHCaptured rve with
 			| Some({iv_state = IVSAliasing(io)}) ->
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
@@ -453,15 +462,15 @@ let inline_constructors ctx original_e =
 		| TBinop(OpAssign, lve, rve) ->
 			begin match analyze_aliases_in_lvalue lve with
 			| 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)}) ->
 					scoped_ivs := iv :: !scoped_ivs;
 					set_iv_alias iv io
 				| _ -> cancel_iv iv lve.epos
 				end;
 				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
 		| TField(ethis, fa) ->
 			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
 		| TLocal(v) when v.v_id < 0 ->
 			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
 		| TBlock(el) ->
 			let rec loop = function
 				| [e] -> analyze_aliases captured e
-				| e::el -> ignore(analyze_aliases true e); loop (el)
+				| e::el -> ignore(analyze_aliases IEHIgnored e); loop (el)
 				| [] -> None
 			in loop el
 		| TMeta((Meta.InlineConstructorArgument (vid,_),_,_),_) ->
 			(* The contents have already been analyzed, so we must skip the wrapped expression *)
 			(try
 				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)
 			with Not_found -> None)
 		| TParenthesis e | TMeta(_,e) | TCast(e,None) ->
@@ -517,14 +526,32 @@ let inline_constructors ctx original_e =
 				end
 			| IOFInlineVar(iv) ->
 				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
 			| IOFNone ->
-				List.iter (fun ca -> ignore(analyze_aliases false ca)) call_args;
+				List.iter (fun ca -> ignore(analyze_aliases IEHNotHandled ca)) call_args;
 				None
 			end
 		| 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
 	in
@@ -690,7 +717,7 @@ let inline_constructors ctx original_e =
 	in
 	if not (check_for_ctors original_e) then original_e else
 	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
 		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

+ 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 {
 	public var i = 0;
 	public inline function new() {};
@@ -130,4 +136,13 @@ class TestInlineConstructors extends TestBase {
 		}
 		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;
+	}
 }