@@ -306,10 +306,149 @@ and eq_primitive (p : Lambda.primitive) (p1 : Lambda.primitive) =
306306 try p = p1 with _ -> false
307307
308308
309- let is_closed_by map lam =
310- Lambda.IdentSet. for_all Ident. global
311- (Lambda.IdentSet. diff (Lambda. free_variables lam) map )
309+
310+ type stats =
311+ {
312+ mutable top : bool ;
313+ (* all appearances are in the top, substitution is fine
314+ whether it is pure or not
315+ {[
316+ (fun x y
317+ -> x + y + (f x )) (32) (console.log('hi'), 33)
318+ ]}
319+ since in ocaml, the application order is intentionally undefined,
320+ note if [times] is not one, this field does not make sense
321+ *)
322+ mutable times : int ;
323+ }
324+ type env =
325+ { top : bool ;
326+ loop : bool
327+ }
328+
329+ let no_substitute = { top = false ; loop = true }
330+ let fresh_env = {top = true ; loop = false }
331+ let fresh_stats () = { top = true ; times = 0 }
332+
333+ let param_map_of_list lst =
334+ List. fold_left (fun acc l -> Ident_map. add l (fresh_stats () ) acc) Ident_map. empty lst
335+
336+ (* * Sanity check, remove all varaibles in [local_set] in the last pass *)
337+
338+ let free_variables (export_idents : Ident_set.t ) (params : stats Ident_map.t ) lam =
339+ let fv = ref params in
340+ let local_set = ref export_idents in
341+
342+ let local_add k =
343+ local_set := Ident_set. add k ! local_set in
344+ let local_add_list ks =
345+ local_set :=
346+ List. fold_left (fun acc k -> Ident_set. add k acc) ! local_set ks
347+ in
348+ let loop_use = 100 in
349+ let map_use {top; loop} v =
350+ (* relies on [identifier] uniquely bound *)
351+ let times = if loop then loop_use else 1 in
352+ if Ident_set. mem v ! local_set then ()
353+ else begin match Ident_map. find v ! fv with
354+ | exception Not_found
355+ -> fv := Ident_map. add v { top ; times } ! fv
356+ | v ->
357+ v.times < - v.times + times ;
358+ v.top < - v.top && top
359+ end
360+ in
361+ let new_env lam (env : env ) =
362+ if env.top then
363+ if no_side_effects lam
364+ then env
365+ else { env with top = false }
366+ else env
367+ in
368+ let rec iter (top : env ) (lam : Lambda.lambda ) =
369+ match lam with
370+ | Lvar v -> map_use top v
371+ | Lconst _ -> ()
372+ | Lapply (fn , args , _ ) ->
373+ iter top fn;
374+ let top = new_env fn top in
375+ List. iter (iter top ) args
376+ | Lprim (_p , args ) ->
377+ (* Check: can top be propoaged for all primitives *)
378+ List. iter (iter top) args
379+ | Lfunction (_kind , params , body ) ->
380+ local_add_list params;
381+ iter no_substitute body
382+ | Llet (_let_kind , id , arg , body ) ->
383+ local_add id ;
384+ iter top arg; iter no_substitute body
385+ | Lletrec (decl , body ) ->
386+ local_set := List. fold_left (fun acc (id , _ ) ->
387+ Ident_set. add id acc) ! local_set decl;
388+ List. iter (fun (_ , exp ) -> iter no_substitute exp) decl;
389+ iter no_substitute body
390+ | Lswitch (arg , sw ) ->
391+ iter top arg;
392+ let top = new_env arg top in
393+ List. iter (fun (key , case ) -> iter top case) sw.sw_consts;
394+ List. iter (fun (key , case ) -> iter top case) sw.sw_blocks;
395+
396+ begin match sw.sw_failaction with
397+ | None -> ()
398+ | Some x ->
399+ let nconsts = List. length sw.sw_consts in
400+ let nblocks = List. length sw.sw_blocks in
401+
402+ if nconsts < sw.sw_numconsts && nblocks < sw.sw_numblocks then
403+ iter no_substitute x
404+ else
405+ iter top x
406+ end
407+
408+ | Lstringswitch (arg ,cases ,default ) ->
409+ iter top arg ;
410+ let top = new_env arg top in
411+ List. iter (fun (_ ,act ) -> iter top act) cases ;
412+ begin match default with
413+ | None -> ()
414+ | Some x -> iter top x
415+ end
416+ | Lstaticraise (_ ,args ) ->
417+ List. iter (iter no_substitute ) args
418+ | Lstaticcatch (e1 , (_ ,vars ), e2 ) ->
419+ iter no_substitute e1;
420+ local_add_list vars;
421+ iter no_substitute e2
422+ | Ltrywith (e1 , exn , e2 ) ->
423+ iter top e1; iter no_substitute e2
424+ | Lifthenelse (e1 , e2 , e3 ) ->
425+ iter top e1;
426+ let top = new_env e1 top in
427+ iter top e2; iter top e3
428+ | Lsequence (e1 , e2 ) ->
429+ iter top e1; iter no_substitute e2
430+ | Lwhile (e1 , e2 ) ->
431+ iter no_substitute e1; iter no_substitute e2 (* in the loop, no substitution any way *)
432+ | Lfor (v , e1 , e2 , dir , e3 ) ->
433+ local_add v ;
434+ iter no_substitute e1; iter no_substitute e2; iter no_substitute e3
435+ | Lassign (id , e ) ->
436+ map_use top id ;
437+ iter top e
438+ | Lsend (_k , met , obj , args , _ ) ->
439+ iter no_substitute met ;
440+ iter no_substitute obj;
441+ List. iter (iter no_substitute) args
442+ | Levent (lam , evt ) ->
443+ iter top lam
444+ | Lifused (v , e ) ->
445+ iter no_substitute e in
446+ iter fresh_env lam ; ! fv
447+
448+
449+ let is_closed_by set lam =
450+ Ident_map. is_empty (free_variables set (Ident_map. empty ) lam )
312451
313452
314453let is_closed lam =
315- Lambda.IdentSet. for_all Ident. global ( Lambda. free_variables lam)
454+ Ident_map. is_empty (free_variables Ident_set. empty Ident_map. empty lam)
0 commit comments