Skip to content

Compiler: do not inline try_catch less function in a try catch context #230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 17, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/.depend
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ generate.cmo : util.cmi subst.cmi primitive.cmi parse_js.cmi parse_info.cmi \
generate.cmx : util.cmx subst.cmx primitive.cmx parse_js.cmx parse_info.cmx \
parse_bytecode.cmx option.cmx js_tailcall.cmx js_simpl.cmx javascript.cmx \
freevars.cmx code.cmx generate.cmi
inline.cmo : code.cmi inline.cmi
inline.cmx : code.cmx inline.cmi
inline.cmo : util.cmi option.cmi code.cmi inline.cmi
inline.cmx : util.cmx option.cmx code.cmx inline.cmi
instr.cmo : util.cmi instr.cmi
instr.cmx : util.cmx instr.cmi
javascript.cmo : varPrinter.cmi util.cmi parse_info.cmi code.cmi \
Expand Down
19 changes: 19 additions & 0 deletions compiler/code.ml
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,25 @@ let fold_children blocks pc f accu =
accu >> Array.fold_right (fun (pc, _) accu -> f pc accu) a1
>> Array.fold_right (fun (pc, _) accu -> f pc accu) a2

let rec traverse' fold f pc visited blocks acc =
if not (AddrSet.mem pc visited) then begin
let visited = AddrSet.add pc visited in
let (visited, acc) =
fold blocks pc
(fun pc (visited, acc) ->
let (visited, acc) =
traverse' fold f pc visited blocks acc in
(visited, acc))
(visited, acc)
in
let acc = f pc acc in
(visited, acc)
end else
(visited, acc)

let traverse fold f pc blocks acc =
snd (traverse' fold f pc AddrSet.empty blocks acc)

let eq (pc1, blocks1, _) (pc2, blocks2, _) =
pc1 = pc2 &&
AddrMap.cardinal blocks1 = AddrMap.cardinal blocks2 &&
Expand Down
5 changes: 5 additions & 0 deletions compiler/code.mli
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ val fold_closures :
val fold_children :
block AddrMap.t -> addr -> (addr -> 'c -> 'c) -> 'c -> 'c

val traverse :
(block AddrMap.t -> addr -> (addr -> (AddrSet.t * 'c) -> (AddrSet.t * 'c)) -> (AddrSet.t * 'c) -> (AddrSet.t * 'c)) ->
(addr -> 'c -> 'c) ->
addr -> block AddrMap.t -> 'c -> 'c

val prepend : program -> instr list -> program

val eq : program -> program -> bool
113 changes: 71 additions & 42 deletions compiler/inline.ml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,43 @@

open Code

let optimizable blocks pc acc =
Code.traverse Code.fold_children (fun pc acc ->
if not acc
then acc
else
let b = AddrMap.find pc blocks in
match b with
| {handler = Some _}
| {branch = Pushtrap _ }
| {branch = Poptrap _ } -> false
| _ ->
List.for_all (function
| Let (_, Prim (Extern "caml_js_eval_string",_)) -> false
| Let (_, Prim (Extern "debugger",_)) -> false
| Let
(x,
Prim(Extern
("caml_js_var"
|"caml_js_expr"
|"caml_pure_js_expr"),_)) ->
(* TODO: we should smarter here and look the generated js *)
(* let's consider it this opmiziable *)
true
| _ -> true
) b.body ) pc blocks true

let get_closures (_, blocks, _) =
AddrMap.fold
(fun _ block closures ->
List.fold_left
(fun closures i ->
match i with
Let (x, Closure (l, cont)) ->
VarMap.add x (l, cont) closures
(* we can compute this once during the pass
as the property won't change with inlining *)
let f_optimizable = optimizable blocks (fst cont) true in
VarMap.add x (l, cont, f_optimizable) closures
| _ ->
closures)
closures block.body)
Expand Down Expand Up @@ -64,24 +93,8 @@ let fold_children blocks pc f accu =
accu >> Array.fold_right (fun (pc, _) accu -> f pc accu) a1
>> Array.fold_right (fun (pc, _) accu -> f pc accu) a2

let rec traverse f pc visited blocks =
if not (AddrSet.mem pc visited) then begin
let visited = AddrSet.add pc visited in
let (visited, blocks) =
fold_children blocks pc
(fun pc (visited, blocks) ->
let (visited, blocks) =
traverse f pc visited blocks in
(visited, blocks))
(visited, blocks)
in
let blocks = rewrite_block f pc blocks in
(visited, blocks)
end else
(visited, blocks)

let rewrite_closure blocks cont_pc clos_pc handler =
snd (traverse (cont_pc, handler) clos_pc AddrSet.empty blocks)
Code.traverse fold_children (rewrite_block (cont_pc, handler)) clos_pc blocks blocks

(****)

Expand All @@ -92,7 +105,7 @@ update closure body to return to this location
make current block continuation jump to closure body
*)

let inline closures live_vars blocks free_pc pc =
let inline closures live_vars outer_optimizable pc (blocks,free_pc)=
let block = AddrMap.find pc blocks in
let (body, (branch, blocks, free_pc)) =
List.fold_right
Expand All @@ -101,31 +114,41 @@ let inline closures live_vars blocks free_pc pc =
Let (x, Apply (f, args, true))
when live_vars.(Var.idx f) = 1
&& VarMap.mem f closures ->
let (params, (clos_pc, clos_args)) = VarMap.find f closures in
let (branch, blocks, free_pc) = state in
let (blocks, cont_pc) =
match rem, branch with
[], Return y when Var.compare x y = 0 ->
let (params, (clos_pc, clos_args),f_optimizable) = VarMap.find f closures in
(* inlining the code of an optimizable function could make
this code unoptimized. (wrt to Jit compilers)
At the moment, V8 doesn't optimize function containing try..catch.
We disable inlining if the inner and outer funcitons don't have
the same "contain_try_catch" property *)
if outer_optimizable = f_optimizable
then
let (branch, blocks, free_pc) = state in
let (blocks, cont_pc) =
match rem, branch with
[], Return y when Var.compare x y = 0 ->
(* We do not need a continuation block for tail calls *)
(blocks, None)
| _ ->
| _ ->
(AddrMap.add free_pc
{ params = [x]; handler = block.handler;
body = rem; branch = branch } blocks,
Some free_pc)
in
let blocks =
rewrite_closure blocks cont_pc clos_pc block.handler in
(* We do not really need this intermediate block. It
just avoid the need to find which function parameters
are used in the function body. *)
let blocks =
AddrMap.add (free_pc + 1)
{ params = params; handler = block.handler;
body = []; branch = Branch (clos_pc, clos_args) } blocks
in
([], (Branch (free_pc + 1, args), blocks, free_pc + 2))

in
let blocks =
rewrite_closure blocks cont_pc clos_pc block.handler in
(* We do not really need this intermediate block. It
just avoid the need to find which function parameters
are used in the function body. *)
let blocks =
AddrMap.add (free_pc + 1)
{ params = params; handler = block.handler;
body = []; branch = Branch (clos_pc, clos_args) } blocks
in
([], (Branch (free_pc + 1, args), blocks, free_pc + 2))
else begin
(* Format.eprintf "Do not inline because inner:%b outer:%b@." f_has_handler outer_has_handler; *)
(i :: rem, state)
end
| _ ->
(i :: rem, state))
block.body ([], (block.branch, blocks, free_pc))
Expand All @@ -134,12 +157,18 @@ let inline closures live_vars blocks free_pc pc =

(****)

let times = Option.Debug.find "times"
let f ((pc, blocks, free_pc) as p) live_vars =
let t = Util.Timer.make () in
let closures = get_closures p in
let (blocks, free_pc) =
AddrMap.fold
(fun pc _ (blocks, free_pc) ->
inline closures live_vars blocks free_pc pc)
blocks (blocks, free_pc)
Code.fold_closures p (fun name _ (pc,_) (blocks,free_pc) ->
let outer_optimizable = match name with
| None -> optimizable blocks pc true
| Some x -> let _,_,b = VarMap.find x closures in
b in
Code.traverse Code.fold_children (inline closures live_vars outer_optimizable) pc blocks (blocks,free_pc)
) (blocks, free_pc)
in
if times () then Format.eprintf " inlining: %a@." Util.Timer.print t;
(pc, blocks, free_pc)