@@ -281,13 +281,15 @@ module Ctx = struct
281
281
; effect_warning : bool ref
282
282
; cps_calls : Effects .cps_calls
283
283
; deadcode_sentinal : Var .t
284
+ ; mutated_vars : Code.Var.Set .t Code.Addr.Map .t
284
285
}
285
286
286
287
let initial
287
288
~warn_on_unhandled_effect
288
289
~exported_runtime
289
290
~should_export
290
291
~deadcode_sentinal
292
+ ~mutated_vars
291
293
blocks
292
294
live
293
295
cps_calls
@@ -302,6 +304,7 @@ module Ctx = struct
302
304
; effect_warning = ref (not warn_on_unhandled_effect)
303
305
; cps_calls
304
306
; deadcode_sentinal
307
+ ; mutated_vars
305
308
}
306
309
end
307
310
@@ -1383,9 +1386,73 @@ and translate_instr ctx expr_queue instr =
1383
1386
mutator_p
1384
1387
[ J. Expression_statement (J. EBin (J. Eq , Mlvalue.Array. field cx cy, cz)), loc ]
1385
1388
1386
- and translate_instrs ctx expr_queue instr last =
1389
+ and translate_instrs ( ctx : Ctx.t ) expr_queue instr last =
1387
1390
match instr with
1388
1391
| [] -> [] , 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_rev, expr_queue =
1397
+ List. fold_left all ~init: ([] , expr_queue) ~f: (fun (st_rev , expr_queue ) i ->
1398
+ let l, expr_queue = translate_instr ctx expr_queue i in
1399
+ List. rev_append l st_rev, expr_queue)
1400
+ in
1401
+ let instrs, expr_queue = translate_instrs ctx expr_queue rem last in
1402
+ List. rev_append st_rev 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. 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)
1389
1456
| instr :: rem ->
1390
1457
let st, expr_queue = translate_instr ctx expr_queue instr in
1391
1458
let instrs, expr_queue = translate_instrs ctx expr_queue rem last in
@@ -1750,6 +1817,14 @@ and compile_closure ctx (pc, args) =
1750
1817
if debug () then Format. eprintf " }@]@;" ;
1751
1818
res
1752
1819
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
+
1753
1828
let generate_shared_value ctx =
1754
1829
let strings =
1755
1830
( J. variable_declaration
@@ -1808,12 +1883,14 @@ let f
1808
1883
let exported_runtime =
1809
1884
if exported_runtime then Some (Code.Var. fresh_n " runtime" , ref false ) else None
1810
1885
in
1886
+ let mutated_vars = Freevars. f p in
1811
1887
let ctx =
1812
1888
Ctx. initial
1813
1889
~warn_on_unhandled_effect
1814
1890
~exported_runtime
1815
1891
~should_export
1816
1892
~deadcode_sentinal
1893
+ ~mutated_vars
1817
1894
p.blocks
1818
1895
live_vars
1819
1896
cps_calls
0 commit comments