Skip to content

Commit

Permalink
Inline ctors improved handling of ignored exprs. (HaxeFoundation#11356)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
basro authored and 0b1kn00b committed Jan 25, 2024
1 parent 4f88f29 commit 7f69c33
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 23 deletions.
73 changes: 50 additions & 23 deletions src/optimization/inlineConstructors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)->
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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) ->
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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) ->
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions tests/optimization/src/TestInlineConstructors.hx
Original file line number Diff line number Diff line change
Expand Up @@ -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() {};
Expand Down Expand Up @@ -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;
}
}

0 comments on commit 7f69c33

Please sign in to comment.