@@ -47,8 +47,6 @@ module Debug : sig
47
47
48
48
val dbg_section_needed : t -> bool
49
49
50
- val propagate : Code.Var .t list -> Code.Var .t list -> unit
51
-
52
50
val find : t -> Code.Addr .t -> (int * Ident .t ) list * Env .summary
53
51
54
52
val find_rec : t -> Code.Addr .t -> (int * Ident .t ) list
@@ -308,14 +306,6 @@ end = struct
308
306
| [] -> None
309
307
| (source , event ) :: _ -> Some (event_location ~position ~source ~event )
310
308
311
- let rec propagate l1 l2 =
312
- match l1, l2 with
313
- | v1 :: r1 , v2 :: r2 ->
314
- Var. propagate_name v1 v2;
315
- propagate r1 r2
316
- | [] , [] -> ()
317
- | _ -> assert false
318
-
319
309
type summary =
320
310
{ is_empty : bool
321
311
; units : (string * string option , ml_unit ) Hashtbl .t
342
332
module Blocks : sig
343
333
type t
344
334
345
- val analyse : bytecode -> t
335
+ val analyse : bytecode -> t * Addr.Set .t
346
336
347
337
val next : t -> int -> int
348
338
@@ -352,45 +342,68 @@ end = struct
352
342
353
343
let add blocks pc = Addr.Set. add pc blocks
354
344
355
- let rec scan blocks code pc len =
345
+ let rec scan blocks starts repeats code pc len =
356
346
if pc < len
357
347
then
358
348
match (get_instr_exn code pc).kind with
359
- | KNullary -> scan blocks code (pc + 1 ) len
360
- | KUnary -> scan blocks code (pc + 2 ) len
361
- | KBinary -> scan blocks code (pc + 3 ) len
362
- | KNullaryCall -> scan blocks code (pc + 1 ) len
363
- | KUnaryCall -> scan blocks code (pc + 2 ) len
364
- | KBinaryCall -> scan blocks code (pc + 3 ) len
349
+ | KNullary -> scan blocks starts repeats code (pc + 1 ) len
350
+ | KUnary -> scan blocks starts repeats code (pc + 2 ) len
351
+ | KBinary -> scan blocks starts repeats code (pc + 3 ) len
352
+ | KNullaryCall -> scan blocks starts repeats code (pc + 1 ) len
353
+ | KUnaryCall -> scan blocks starts repeats code (pc + 2 ) len
354
+ | KBinaryCall -> scan blocks starts repeats code (pc + 3 ) len
365
355
| KJump ->
366
356
let offset = gets code (pc + 1 ) in
367
- let blocks = Addr.Set. add (pc + offset + 1 ) blocks in
368
- scan blocks code (pc + 2 ) len
357
+ let pc' = pc + offset + 1 in
358
+ let repeats =
359
+ if Addr.Set. mem pc' blocks then Addr.Set. add pc' repeats else repeats
360
+ in
361
+ let blocks = Addr.Set. add pc' blocks in
362
+ let pc'' = pc + 2 in
363
+ let starts = Addr.Set. add pc'' starts in
364
+ scan blocks starts repeats code pc'' len
369
365
| KCond_jump ->
370
366
let offset = gets code (pc + 1 ) in
371
- let blocks = Addr.Set. add (pc + offset + 1 ) blocks in
372
- scan blocks code (pc + 2 ) len
367
+ let pc' = pc + offset + 1 in
368
+ let repeats =
369
+ if Addr.Set. mem pc' blocks then Addr.Set. add pc' repeats else repeats
370
+ in
371
+ let blocks = Addr.Set. add pc' blocks in
372
+ scan blocks starts repeats code (pc + 2 ) len
373
373
| KCmp_jump ->
374
374
let offset = gets code (pc + 2 ) in
375
- let blocks = Addr.Set. add (pc + offset + 2 ) blocks in
376
- scan blocks code (pc + 3 ) len
375
+ let pc' = pc + offset + 2 in
376
+ let repeats =
377
+ if Addr.Set. mem pc' blocks then Addr.Set. add pc' repeats else repeats
378
+ in
379
+ let blocks = Addr.Set. add pc' blocks in
380
+ scan blocks starts repeats code (pc + 3 ) len
377
381
| KSwitch ->
378
382
let sz = getu code (pc + 1 ) in
383
+ let repeats = ref repeats in
379
384
let blocks = ref blocks in
380
- for i = 0 to (sz land 0xffff ) + (sz lsr 16 ) - 1 do
385
+ let count = (sz land 0xffff ) + (sz lsr 16 ) in
386
+ for i = 0 to count - 1 do
381
387
let offset = gets code (pc + 2 + i) in
382
- blocks := Addr.Set. add (pc + offset + 2 ) ! blocks
388
+ let pc' = pc + offset + 2 in
389
+ if Addr.Set. mem pc' ! blocks then repeats := Addr.Set. add pc' ! repeats;
390
+ blocks := Addr.Set. add pc' ! blocks
383
391
done ;
384
- scan ! blocks code (pc + 2 + (sz land 0xffff ) + (sz lsr 16 )) len
392
+ let pc'' = pc + 2 + count in
393
+ let starts = Addr.Set. add pc'' starts in
394
+ scan ! blocks starts ! repeats code pc'' len
385
395
| KClosurerec ->
386
396
let nfuncs = getu code (pc + 1 ) in
387
- scan blocks code (pc + nfuncs + 3 ) len
388
- | KClosure -> scan blocks code (pc + 3 ) len
389
- | KStop n -> scan blocks code (pc + n + 1 ) len
397
+ scan blocks starts repeats code (pc + nfuncs + 3 ) len
398
+ | KClosure -> scan blocks starts repeats code (pc + 3 ) len
399
+ | KStop n ->
400
+ let pc'' = pc + n + 1 in
401
+ let starts = Addr.Set. add pc'' starts in
402
+ scan blocks starts repeats code pc'' len
390
403
| K_will_not_happen -> assert false
391
404
else (
392
405
assert (pc = len);
393
- blocks)
406
+ blocks, starts, repeats )
394
407
395
408
(* invariant: a.(i) <= x < a.(j) *)
396
409
let rec find a i j x =
@@ -406,12 +419,14 @@ end = struct
406
419
let is_empty x = Array. length x < = 1
407
420
408
421
let analyse code =
409
- let blocks = Addr.Set. empty in
410
422
let len = String. length code / 4 in
423
+ let blocks, starts, repeats =
424
+ scan Addr.Set. empty Addr.Set. empty Addr.Set. empty code 0 len
425
+ in
426
+ let joins = Addr.Set. union repeats (Addr.Set. diff blocks starts) in
411
427
let blocks = add blocks 0 in
412
428
let blocks = add blocks len in
413
- let blocks = scan blocks code 0 len in
414
- Array. of_list (Addr.Set. elements blocks)
429
+ Array. of_list (Addr.Set. elements blocks), joins
415
430
end
416
431
417
432
(* Parse constants *)
@@ -803,6 +818,7 @@ let clo_offset_3 = 3
803
818
804
819
type compile_info =
805
820
{ blocks : Blocks .t
821
+ ; joins : Addr.Set .t
806
822
; code : string
807
823
; limit : int
808
824
; debug : Debug .t
@@ -828,7 +844,7 @@ let string_of_addr debug_data addr =
828
844
in
829
845
Printf. sprintf " %s:%s-%s %s" file (pos loc.loc_start) (pos loc.loc_end) kind)
830
846
831
- let rec compile_block blocks debug_data code pc state : unit =
847
+ let rec compile_block blocks joins debug_data code pc state : unit =
832
848
match Addr.Map. find_opt pc ! tagged_blocks with
833
849
| Some old_state -> (
834
850
(* Check that the shape of the stack is compatible with the one used to compile the block *)
@@ -857,10 +873,10 @@ let rec compile_block blocks debug_data code pc state : unit =
857
873
let limit = Blocks. next blocks pc in
858
874
assert (limit > pc);
859
875
if debug_parser () then Format. eprintf " Compiling from %d to %d@." pc (limit - 1 );
860
- let state = State. start_block pc state in
876
+ let state = if Addr.Set. mem pc joins then State. start_block pc state else state in
861
877
tagged_blocks := Addr.Map. add pc state ! tagged_blocks;
862
878
let instr, last, state' =
863
- compile { blocks; code; limit; debug = debug_data } pc state []
879
+ compile { blocks; joins; code; limit; debug = debug_data } pc state []
864
880
in
865
881
assert (not (Addr.Map. mem pc ! compiled_blocks));
866
882
(* When jumping to a block that was already visited and the
@@ -873,26 +889,36 @@ let rec compile_block blocks debug_data code pc state : unit =
873
889
State. clear_accu state'
874
890
| _ , _ -> state'
875
891
in
876
- let mk_cont pc =
877
- let state = adjust_state pc in
878
- pc, State. stack_vars state
892
+ let mk_cont ((pc , _ ) as cont ) =
893
+ if Addr.Set. mem pc joins
894
+ then
895
+ let state = adjust_state pc in
896
+ pc, State. stack_vars state
897
+ else cont
879
898
in
880
899
let last =
881
900
match last with
882
- | Branch (pc , _ ) -> Branch (mk_cont pc)
883
- | Cond (x , (pc1 , _ ), (pc2 , _ )) ->
884
- if pc1 = pc2 then Branch (mk_cont pc1) else Cond (x, mk_cont pc1, mk_cont pc2)
885
- | Poptrap (pc , _ ) -> Poptrap (mk_cont pc)
886
- | Switch (x , a ) -> Switch (x, Array. map a ~f: (fun (pc , _ ) -> mk_cont pc))
901
+ | Branch cont -> Branch (mk_cont cont)
902
+ | Cond (x , cont1 , cont2 ) ->
903
+ if cont_equal cont1 cont2
904
+ then Branch (mk_cont cont1)
905
+ else Cond (x, mk_cont cont1, mk_cont cont2)
906
+ | Poptrap cont -> Poptrap (mk_cont cont)
907
+ | Switch (x , a ) -> Switch (x, Array. map a ~f: mk_cont)
887
908
| Raise _ | Return _ | Stop -> last
888
909
| Pushtrap _ -> assert false
889
910
in
890
- compiled_blocks := Addr.Map. add pc (state, List. rev instr, last) ! compiled_blocks;
911
+ compiled_blocks :=
912
+ Addr.Map. add
913
+ pc
914
+ ((if Addr.Set. mem pc joins then Some state else None ), List. rev instr, last)
915
+ ! compiled_blocks;
891
916
match last with
892
- | Branch (pc' , _ ) -> compile_block blocks debug_data code pc' (adjust_state pc')
917
+ | Branch (pc' , _ ) ->
918
+ compile_block blocks joins debug_data code pc' (adjust_state pc')
893
919
| Cond (_ , (pc1 , _ ), (pc2 , _ )) ->
894
- compile_block blocks debug_data code pc1 (adjust_state pc1);
895
- compile_block blocks debug_data code pc2 (adjust_state pc2)
920
+ compile_block blocks joins debug_data code pc1 (adjust_state pc1);
921
+ compile_block blocks joins debug_data code pc2 (adjust_state pc2)
896
922
| Poptrap (_ , _ ) -> ()
897
923
| Switch (_ , _ ) -> ()
898
924
| Raise _ | Return _ | Stop -> ()
@@ -1219,11 +1245,8 @@ and compile infos pc state (instrs : instr list) =
1219
1245
let params, state' = State. make_stack nparams state' in
1220
1246
if debug_parser () then Format. printf " ) {@." ;
1221
1247
let state' = State. clear_accu state' in
1222
- compile_block infos.blocks infos.debug code addr state';
1248
+ compile_block infos.blocks infos.joins infos. debug code addr state';
1223
1249
if debug_parser () then Format. printf " }@." ;
1224
- let args = State. stack_vars state' in
1225
- let state'', _, _ = Addr.Map. find addr ! compiled_blocks in
1226
- Debug. propagate (State. stack_vars state'') args;
1227
1250
compile
1228
1251
infos
1229
1252
(pc + 3 )
@@ -1232,7 +1255,7 @@ and compile infos pc state (instrs : instr list) =
1232
1255
( x
1233
1256
, Closure
1234
1257
( List. rev params
1235
- , (addr, args )
1258
+ , (addr, [] )
1236
1259
, Debug. find_loc infos.debug ~position: After addr ) )
1237
1260
:: instrs)
1238
1261
| CLOSUREREC ->
@@ -1280,16 +1303,13 @@ and compile infos pc state (instrs : instr list) =
1280
1303
let params, state' = State. make_stack nparams state' in
1281
1304
if debug_parser () then Format. printf " ) {@." ;
1282
1305
let state' = State. clear_accu state' in
1283
- compile_block infos.blocks infos.debug code addr state';
1306
+ compile_block infos.blocks infos.joins infos. debug code addr state';
1284
1307
if debug_parser () then Format. printf " }@." ;
1285
- let args = State. stack_vars state' in
1286
- let state'', _, _ = Addr.Map. find addr ! compiled_blocks in
1287
- Debug. propagate (State. stack_vars state'') args;
1288
1308
Let
1289
1309
( x
1290
1310
, Closure
1291
1311
( List. rev params
1292
- , (addr, args )
1312
+ , (addr, [] )
1293
1313
, Debug. find_loc infos.debug ~position: After addr ) )
1294
1314
:: instr)
1295
1315
in
@@ -1694,9 +1714,9 @@ and compile infos pc state (instrs : instr list) =
1694
1714
let it = Array. init isize ~f: (fun i -> base + gets code (base + i)) in
1695
1715
let bt = Array. init bsize ~f: (fun i -> base + gets code (base + isize + i)) in
1696
1716
Array. iter it ~f: (fun pc' ->
1697
- compile_block infos.blocks infos.debug code pc' state);
1717
+ compile_block infos.blocks infos.joins infos. debug code pc' state);
1698
1718
Array. iter bt ~f: (fun pc' ->
1699
- compile_block infos.blocks infos.debug code pc' state);
1719
+ compile_block infos.blocks infos.joins infos. debug code pc' state);
1700
1720
match isize, bsize with
1701
1721
| _ , 0 -> instrs, Switch (x, Array. map it ~f: (fun pc -> pc, [] )), state
1702
1722
| 0 , _ ->
@@ -1710,24 +1730,32 @@ and compile infos pc state (instrs : instr list) =
1710
1730
let isblock_branch = pc + 2 in
1711
1731
let () =
1712
1732
tagged_blocks := Addr.Map. add isint_branch state ! tagged_blocks;
1713
- let i_state = State. start_block isint_branch state in
1714
- let i_args = State. stack_vars i_state in
1733
+ let i_args = State. stack_vars state in
1715
1734
compiled_blocks :=
1716
1735
Addr.Map. add
1717
1736
isint_branch
1718
- (i_state, [] , Switch (x, Array. map it ~f: (fun pc -> pc, i_args)))
1737
+ ( None
1738
+ , []
1739
+ , Switch
1740
+ ( x
1741
+ , Array. map it ~f: (fun pc ->
1742
+ pc, if Addr.Set. mem pc infos.joins then i_args else [] ) ) )
1719
1743
! compiled_blocks
1720
1744
in
1721
1745
let () =
1722
1746
tagged_blocks := Addr.Map. add isblock_branch state ! tagged_blocks;
1723
1747
let x_tag = Var. fresh () in
1724
- let b_state = State. start_block isblock_branch state in
1725
- let b_args = State. stack_vars b_state in
1748
+ let b_args = State. stack_vars state in
1726
1749
let instrs = [ Let (x_tag, Prim (Extern " %direct_obj_tag" , [ Pv x ])) ] in
1727
1750
compiled_blocks :=
1728
1751
Addr.Map. add
1729
1752
isblock_branch
1730
- (b_state, instrs, Switch (x_tag, Array. map bt ~f: (fun pc -> pc, b_args)))
1753
+ ( None
1754
+ , instrs
1755
+ , Switch
1756
+ ( x_tag
1757
+ , Array. map bt ~f: (fun pc ->
1758
+ pc, if Addr.Set. mem pc infos.joins then b_args else [] ) ) )
1731
1759
! compiled_blocks
1732
1760
in
1733
1761
let isint_var = Var. fresh () in
@@ -1753,16 +1781,12 @@ and compile infos pc state (instrs : instr list) =
1753
1781
compiled_blocks :=
1754
1782
Addr.Map. add
1755
1783
interm_addr
1756
- ( handler_ctx_state
1757
- , []
1758
- , Pushtrap
1759
- ( (body_addr, State. stack_vars state)
1760
- , x
1761
- , (handler_addr, State. stack_vars handler_state) ) )
1784
+ (Some handler_ctx_state, [] , Pushtrap ((body_addr, [] ), x, (handler_addr, [] )))
1762
1785
! compiled_blocks;
1763
- compile_block infos.blocks infos.debug code handler_addr handler_state;
1786
+ compile_block infos.blocks infos.joins infos. debug code handler_addr handler_state;
1764
1787
compile_block
1765
1788
infos.blocks
1789
+ infos.joins
1766
1790
infos.debug
1767
1791
code
1768
1792
body_addr
@@ -1775,11 +1799,12 @@ and compile infos pc state (instrs : instr list) =
1775
1799
:: State. Dummy " pushtrap(extra_args)"
1776
1800
:: state.State. stack
1777
1801
};
1778
- instrs, Branch (interm_addr, [] ), state
1802
+ instrs, Branch (interm_addr, State. stack_vars state ), state
1779
1803
| POPTRAP ->
1780
1804
let addr = pc + 1 in
1781
1805
compile_block
1782
1806
infos.blocks
1807
+ infos.joins
1783
1808
infos.debug
1784
1809
code
1785
1810
addr
@@ -2482,16 +2507,22 @@ type one =
2482
2507
let parse_bytecode code globals debug_data =
2483
2508
let state = State. initial globals in
2484
2509
Code.Var. reset () ;
2485
- let blocks' = Blocks. analyse code in
2510
+ let blocks', joins = Blocks. analyse code in
2486
2511
let p =
2487
2512
if not (Blocks. is_empty blocks')
2488
2513
then (
2489
2514
let start = 0 in
2490
- compile_block blocks' debug_data code start state;
2515
+ compile_block blocks' joins debug_data code start state;
2491
2516
let blocks =
2492
2517
Addr.Map. mapi
2493
2518
(fun _ (state , instr , last ) ->
2494
- { params = State. stack_vars state; body = instr; branch = last })
2519
+ { params =
2520
+ (match state with
2521
+ | Some state -> State. stack_vars state
2522
+ | None -> [] )
2523
+ ; body = instr
2524
+ ; branch = last
2525
+ })
2495
2526
! compiled_blocks
2496
2527
in
2497
2528
let free_pc = String. length code / 4 in
0 commit comments