Skip to content

Commit 8966757

Browse files
committed
Compiler: no longer rely on iife
1 parent dcdb164 commit 8966757

File tree

11 files changed

+861
-1024
lines changed

11 files changed

+861
-1024
lines changed

compiler/lib/driver.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,8 @@ let full ~standalone ~wrap_with_fun ~profile ~linkall ~source_map formatter d p
603603
| O3 -> o3)
604604
+> exact_calls ~deadcode_sentinal profile
605605
+> effects ~deadcode_sentinal
606-
+> map_fst (Generate_closure.f +> deadcode')
606+
+> map_fst (if Config.Flag.effects () then fun x -> x else Generate_closure.f)
607+
+> map_fst deadcode'
607608
in
608609
let emit =
609610
generate

compiler/lib/generate.ml

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,15 @@ module Ctx = struct
281281
; effect_warning : bool ref
282282
; cps_calls : Effects.cps_calls
283283
; deadcode_sentinal : Var.t
284+
; mutated_vars : Code.Var.Set.t Code.Addr.Map.t
284285
}
285286

286287
let initial
287288
~warn_on_unhandled_effect
288289
~exported_runtime
289290
~should_export
290291
~deadcode_sentinal
292+
~mutated_vars
291293
blocks
292294
live
293295
cps_calls
@@ -302,6 +304,7 @@ module Ctx = struct
302304
; effect_warning = ref (not warn_on_unhandled_effect)
303305
; cps_calls
304306
; deadcode_sentinal
307+
; mutated_vars
305308
}
306309
end
307310

@@ -1383,9 +1386,73 @@ and translate_instr ctx expr_queue instr =
13831386
mutator_p
13841387
[ J.Expression_statement (J.EBin (J.Eq, Mlvalue.Array.field cx cy, cz)), loc ]
13851388

1386-
and translate_instrs ctx expr_queue instr last =
1389+
and translate_instrs (ctx : Ctx.t) expr_queue instr last =
13871390
match instr with
13881391
| [] -> [], expr_queue
1392+
| (Let (_, Closure _), _) :: _ -> (
1393+
let names, mut, pcs, all, rem = collect_closures ctx instr in
1394+
match Code.Var.Set.cardinal mut with
1395+
| 0 ->
1396+
let st, expr_queue =
1397+
List.fold_left all ~init:([], expr_queue) ~f:(fun (st, expr_queue) i ->
1398+
let l, expr_queue = translate_instr ctx expr_queue i in
1399+
List.rev_append l st, expr_queue)
1400+
in
1401+
let instrs, expr_queue = translate_instrs ctx expr_queue rem last in
1402+
List.rev_append st instrs, expr_queue
1403+
| _ ->
1404+
let muts =
1405+
Code.Var.Set.diff mut names
1406+
|> Code.Var.Set.elements
1407+
|> List.map ~f:(fun x -> x, Code.Var.fork x)
1408+
in
1409+
(* Rewrite blocks using well-scoped closure variables *)
1410+
let ctx =
1411+
let map =
1412+
List.fold_left muts ~init:Var.Map.empty ~f:(fun acc (x, x') ->
1413+
Var.Map.add x x' acc)
1414+
in
1415+
let p, _visited =
1416+
List.fold_left
1417+
pcs
1418+
~init:(ctx.blocks, Addr.Set.empty)
1419+
~f:(fun (blocks, visited) pc ->
1420+
Subst.cont' (Subst.from_map map) pc blocks visited)
1421+
in
1422+
{ ctx with blocks = p }
1423+
in
1424+
(* Let bind mutable variables that are part of closures *)
1425+
let let_bindings_rev, expr_queue =
1426+
let expr_queue, st_rev, l_rev =
1427+
List.fold_left
1428+
muts
1429+
~init:(expr_queue, [], [])
1430+
~f:(fun (expr_queue, st_rev, l_rev) (v, v') ->
1431+
let instrs, ((_px, cx), expr_queue) =
1432+
access_queue_may_flush expr_queue v' v
1433+
in
1434+
let l_rev = (J.V v', (cx, J.N)) :: l_rev in
1435+
expr_queue, List.rev_append instrs st_rev, l_rev)
1436+
in
1437+
(J.variable_declaration ~kind:Let (List.rev l_rev), J.N) :: st_rev, expr_queue
1438+
in
1439+
(* Mutually recursive need to be properly scoped. *)
1440+
let st_rev, expr_queue =
1441+
List.fold_left all ~init:([], expr_queue) ~f:(fun (st_rev, expr_queue) i ->
1442+
let l, expr_queue = translate_instr ctx expr_queue i in
1443+
let l_rev =
1444+
List.rev_map l ~f:(fun (e, loc') ->
1445+
match e with
1446+
(* FIXME: This pattern is too fragile *)
1447+
| J.Variable_statement
1448+
(Var, [ DeclIdent (x, Some (J.EFun (None, dcl), _loc)) ]) ->
1449+
J.Function_declaration (x, dcl), loc'
1450+
| _ -> e, loc')
1451+
in
1452+
List.rev_append l_rev st_rev, expr_queue)
1453+
in
1454+
let instrs, expr_queue = translate_instrs ctx expr_queue rem last in
1455+
List.rev_append let_bindings_rev (List.rev_append st_rev instrs), expr_queue)
13891456
| instr :: rem ->
13901457
let st, expr_queue = translate_instr ctx expr_queue instr in
13911458
let instrs, expr_queue = translate_instrs ctx expr_queue rem last in
@@ -1750,6 +1817,14 @@ and compile_closure ctx (pc, args) =
17501817
if debug () then Format.eprintf "}@]@;";
17511818
res
17521819

1820+
and collect_closures ctx l =
1821+
match l with
1822+
| ((Let (x, Closure (_, (pc, _))), _loc) as i) :: rem ->
1823+
let names', mut', pcs', i', rem' = collect_closures ctx rem in
1824+
let mut = Code.Addr.Map.find pc ctx.Ctx.mutated_vars in
1825+
Code.Var.Set.add x names', Code.Var.Set.union mut mut', pc :: pcs', i :: i', rem'
1826+
| _ -> Code.Var.Set.empty, Code.Var.Set.empty, [], [], l
1827+
17531828
let generate_shared_value ctx =
17541829
let strings =
17551830
( J.variable_declaration
@@ -1808,12 +1883,14 @@ let f
18081883
let exported_runtime =
18091884
if exported_runtime then Some (Code.Var.fresh_n "runtime", ref false) else None
18101885
in
1886+
let mutated_vars = Freevars.f p in
18111887
let ctx =
18121888
Ctx.initial
18131889
~warn_on_unhandled_effect
18141890
~exported_runtime
18151891
~should_export
18161892
~deadcode_sentinal
1893+
~mutated_vars
18171894
p.blocks
18181895
live_vars
18191896
cps_calls

compiler/lib/generate_closure.ml

Lines changed: 14 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ type closure_info =
2727
; args : Code.Var.t list
2828
; cont : Code.cont
2929
; tc : Code.Addr.Set.t Code.Var.Map.t
30-
; mutated_vars : Code.Var.Set.t
3130
; loc : Code.loc
3231
}
3332

@@ -67,24 +66,22 @@ let rec collect_apply pc blocks visited tc =
6766
(fun pc (visited, tc) -> collect_apply pc blocks visited tc)
6867
(visited, tc)
6968

70-
let rec collect_closures blocks mutated_vars l =
69+
let rec collect_closures blocks l =
7170
match l with
7271
| (Let (f_name, Closure (args, ((pc, _) as cont))), loc) :: rem ->
7372
let _, tc = collect_apply pc blocks Addr.Set.empty Var.Map.empty in
74-
let l, rem = collect_closures blocks mutated_vars rem in
75-
let mutated_vars = Addr.Map.find pc mutated_vars in
76-
{ f_name; args; cont; tc; mutated_vars; loc } :: l, rem
73+
let l, rem = collect_closures blocks rem in
74+
{ f_name; args; cont; tc; loc } :: l, rem
7775
| rem -> [], rem
7876

79-
let group_closures ~tc_only closures_map =
77+
let group_closures closures_map =
8078
let names =
8179
Var.Map.fold (fun _ x names -> Var.Set.add x.f_name names) closures_map Var.Set.empty
8280
in
8381
let graph =
8482
Var.Map.fold
8583
(fun _ x graph ->
8684
let calls = Var.Map.fold (fun x _ tc -> Var.Set.add x tc) x.tc Var.Set.empty in
87-
let calls = if tc_only then calls else Var.Set.union calls x.mutated_vars in
8885
Var.Map.add x.f_name (Var.Set.inter names calls) graph)
8986
closures_map
9087
Var.Map.empty
@@ -278,8 +275,6 @@ end
278275
let rewrite_tc free_pc blocks closures_map component =
279276
let open Config.Param in
280277
let trampoline =
281-
(not (Config.Flag.effects ()))
282-
&&
283278
match tailcall_optim () with
284279
| TcTrampoline -> true
285280
| TcNone -> false
@@ -288,189 +283,52 @@ let rewrite_tc free_pc blocks closures_map component =
288283
then Trampoline.f free_pc blocks closures_map component
289284
else Ident.f free_pc blocks closures_map component
290285

291-
let rewrite_mutable
292-
free_pc
293-
blocks
294-
mutated_vars
295-
rewrite_list
296-
{ int = closures_intern; ext = closures_extern } =
297-
let internal_and_external = closures_intern @ closures_extern in
298-
assert (not (List.is_empty closures_extern));
299-
let all_mut, names =
300-
List.fold_left
301-
internal_and_external
302-
~init:(Var.Set.empty, Var.Set.empty)
303-
~f:(fun (all_mut, names) i ->
304-
match i with
305-
| Let (x, Closure (_, (pc, _))), _ ->
306-
let all_mut =
307-
try Var.Set.union all_mut (Addr.Map.find pc mutated_vars)
308-
with Not_found -> all_mut
309-
in
310-
let names = Var.Set.add x names in
311-
all_mut, names
312-
| _ -> assert false)
313-
in
314-
let vars = Var.Set.elements (Var.Set.diff all_mut names) in
315-
if List.is_empty vars
316-
then free_pc, blocks, internal_and_external
317-
else
318-
match internal_and_external with
319-
| [ (Let (x, Closure (params, (pc, pc_args))), loc) ] ->
320-
let new_pc = free_pc in
321-
let free_pc = free_pc + 1 in
322-
let closure = Code.Var.fork x in
323-
let args = List.map vars ~f:Code.Var.fork in
324-
let new_x = Code.Var.fork x in
325-
let mapping = Subst.from_map (Subst.build_mapping (x :: vars) (new_x :: args)) in
326-
rewrite_list := (mapping, pc) :: !rewrite_list;
327-
let new_block =
328-
{ params = []
329-
; body =
330-
[ Let (new_x, Closure (params, (pc, List.map pc_args ~f:mapping))), loc ]
331-
; branch = Return new_x, loc
332-
}
333-
in
334-
let blocks = Addr.Map.add new_pc new_block blocks in
335-
let body =
336-
[ Let (closure, Closure (args, (new_pc, []))), noloc
337-
; Let (x, Apply { f = closure; args = vars; exact = true }), loc
338-
]
339-
in
340-
free_pc, blocks, body
341-
| _ ->
342-
let new_pc = free_pc in
343-
let free_pc = free_pc + 1 in
344-
let closure = Code.Var.fresh_n "closures" in
345-
let closure' = Code.Var.fresh_n "closures" in
346-
let b = Code.Var.fresh_n "block" in
347-
let args = List.map vars ~f:Code.Var.fork in
348-
let pcs =
349-
List.map internal_and_external ~f:(function
350-
| Let (_, Closure (_, (pc, _))), _ -> pc
351-
| _ -> assert false)
352-
in
353-
let old_xs =
354-
List.map closures_extern ~f:(function
355-
| Let (x, Closure _), _ -> x
356-
| _ -> assert false)
357-
in
358-
let new_xs = List.map old_xs ~f:Code.Var.fork in
359-
let mapping =
360-
Subst.from_map (Subst.build_mapping (old_xs @ vars) (new_xs @ args))
361-
in
362-
rewrite_list := List.map pcs ~f:(fun pc -> mapping, pc) @ !rewrite_list;
363-
let new_block =
364-
let proj =
365-
List.map2 closures_extern new_xs ~f:(fun cl new_x ->
366-
match cl with
367-
| Let (_, Closure (params, (pc, pc_args))), loc ->
368-
Let (new_x, Closure (params, (pc, List.map pc_args ~f:mapping))), loc
369-
| _ -> assert false)
370-
in
371-
{ params = []
372-
; body =
373-
closures_intern
374-
@ proj
375-
@ [ Let (b, Block (0, Array.of_list new_xs, NotArray)), noloc ]
376-
; branch = Return b, noloc
377-
}
378-
in
379-
let blocks = Addr.Map.add new_pc new_block blocks in
380-
let body =
381-
[ Let (closure, Closure (args, (new_pc, []))), noloc
382-
; Let (closure', Apply { f = closure; args = vars; exact = true }), noloc
383-
]
384-
@ List.mapi closures_extern ~f:(fun i x ->
385-
match x with
386-
| Let (x, Closure _), loc -> Let (x, Field (closure', i)), loc
387-
| _ -> assert false)
388-
in
389-
free_pc, blocks, body
390-
391-
let rec rewrite_closures mutated_vars rewrite_list free_pc blocks body : int * _ * _ list
392-
=
286+
let rec rewrite_closures free_pc blocks body : int * _ * _ list =
393287
match body with
394288
| (Let (_, Closure _), _) :: _ ->
395-
let closures, rem = collect_closures blocks mutated_vars body in
289+
let closures, rem = collect_closures blocks body in
396290
let closures_map =
397291
List.fold_left closures ~init:Var.Map.empty ~f:(fun closures_map x ->
398292
Var.Map.add x.f_name x closures_map)
399293
in
400-
let components = group_closures ~tc_only:false closures_map in
294+
let components = group_closures closures_map in
401295
let free_pc, blocks, closures =
402296
List.fold_left
403297
(Array.to_list components)
404298
~init:(free_pc, blocks, [])
405299
~f:(fun (free_pc, blocks, acc) component ->
406300
let free_pc, blocks, closures =
407-
let components =
408-
match component with
409-
| SCC.No_loop _ as one -> [ one ]
410-
| SCC.Has_loop all ->
411-
group_closures
412-
~tc_only:true
413-
(Var.Map.filter
414-
(fun v _ -> List.exists all ~f:(Var.equal v))
415-
closures_map)
416-
|> Array.to_list
417-
in
418-
List.fold_left
419-
~init:(free_pc, blocks, { int = []; ext = [] })
420-
components
421-
~f:(fun (free_pc, blocks, acc) component ->
422-
let free_pc, blocks, ie =
423-
rewrite_tc free_pc blocks closures_map component
424-
in
425-
free_pc, blocks, { int = ie.int :: acc.int; ext = ie.ext :: acc.ext })
426-
in
427-
let closures =
428-
{ int = List.concat (List.rev closures.int)
429-
; ext = List.concat (List.rev closures.ext)
430-
}
431-
in
432-
let free_pc, blocks, intrs =
433-
rewrite_mutable free_pc blocks mutated_vars rewrite_list closures
301+
rewrite_tc free_pc blocks closures_map component
434302
in
435-
free_pc, blocks, intrs :: acc)
436-
in
437-
let free_pc, blocks, rem =
438-
rewrite_closures mutated_vars rewrite_list free_pc blocks rem
303+
let intrs = closures.int :: closures.ext :: acc in
304+
free_pc, blocks, intrs)
439305
in
306+
let free_pc, blocks, rem = rewrite_closures free_pc blocks rem in
440307
free_pc, blocks, List.flatten closures @ rem
441308
| i :: rem ->
442-
let free_pc, blocks, rem =
443-
rewrite_closures mutated_vars rewrite_list free_pc blocks rem
444-
in
309+
let free_pc, blocks, rem = rewrite_closures free_pc blocks rem in
445310
free_pc, blocks, i :: rem
446311
| [] -> free_pc, blocks, []
447312

448313
let f p : Code.program =
449314
Code.invariant p;
450-
let mutated_vars = Freevars.f p in
451-
let rewrite_list = ref [] in
452315
let blocks, free_pc =
453316
Addr.Map.fold
454317
(fun pc _ (blocks, free_pc) ->
455318
(* make sure we have the latest version *)
456319
let block = Addr.Map.find pc blocks in
457-
let free_pc, blocks, body =
458-
rewrite_closures mutated_vars rewrite_list free_pc blocks block.body
459-
in
320+
let free_pc, blocks, body = rewrite_closures free_pc blocks block.body in
460321
Addr.Map.add pc { block with body } blocks, free_pc)
461322
p.blocks
462323
(p.blocks, p.free_pc)
463324
in
464325
(* Code.invariant (pc, blocks, free_pc); *)
465326
let p = { p with blocks; free_pc } in
466-
let p =
467-
List.fold_left !rewrite_list ~init:p ~f:(fun program (mapping, pc) ->
468-
Subst.cont mapping pc program)
469-
in
470327
Code.invariant p;
471328
p
472329

473330
let f p =
331+
assert (not (Config.Flag.effects ()));
474332
let t = Timer.make () in
475333
let p' = f p in
476334
if Debug.find "times" () then Format.eprintf " generate closures: %a@." Timer.print t;

compiler/lib/javascript.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,8 @@ end)
540540

541541
let dot e l = EDot (e, ANormal, l)
542542

543-
let variable_declaration l =
544-
Variable_statement (Var, List.map l ~f:(fun (i, e) -> DeclIdent (i, Some e)))
543+
let variable_declaration ?(kind = Var) l =
544+
Variable_statement (kind, List.map l ~f:(fun (i, e) -> DeclIdent (i, Some e)))
545545

546546
let array l = EArr (List.map l ~f:(fun x -> Element x))
547547

0 commit comments

Comments
 (0)