Skip to content

Commit bff8d13

Browse files
OlivierNicolevouillonhhugo
authored
Effects: double translation of functions and dynamic switching between direct-style and CPS code (#1461)
* Effects: double translation of functions and ... dynamic switching between direct-style and CPS code. (#1461) * Add caml_assume_no_effects primitive and tests Passing a function [f] as argument of `caml_assume_no_effects` guarantees that, when compiling with `--enable doubletranslate`, the direct-style version of [f] is called, which is faster than the CPS version. As a consequence, performing an effect in a transitive callee of [f] will raise `Effect.Unhandled`, regardless of any effect handlers installed before the call to `caml_assume_no_effects`, unless a new effect handler was installed in the meantime. Usage: ``` external assume_no_effects : (unit -> 'a) -> 'a = "caml_assume_no_effects" ... caml_assume_no_effects (fun () -> (* Will be called in direct style... *)) ... ``` When double translation is disabled, `caml_assume_no_effects` simply acts like `fun f -> f ()`. This primitive is exposed via `Js_of_ocaml.Js.Effect.assume_no_perform`. * CR: Fix non-raised Unhandled with assume_no_perform * CR: Commit suggestion for compiler/lib/driver.ml Co-authored-by: Jérôme Vouillon <[email protected]> * Fix runtime deps, add missing test * Runtime format * Factorize substitution logic * CR: make caml_callback an alias of caml_call_gen... ... when double translation is enabled. * Promote tests * CR: Fix caml_trampoline_cps and rename it to caml_resume * CR: First fixes to Lambda_lifting_simple * Simplify and clarify Lambda_lifting_simple * Format runtime * Fix bug: functions inside CPS functions were not lambda-lifted * Runtime: fix caml_uncaught_effect_handler We can use a single definition for the CPS transformation and the double translation. The definition for the CPS transformation was wrong, since it did not take a continuation as parameter. * Runtime: the trampoline now distinguish direct and CPS calls * Fix unregistered test and add one for nested handler * Uses 'tests' dune stanza * Reformat dune files and remove leftover files * CR: Fixes in Lambda_lifting_simple * CR: remove unnecessary conditionals in Effects * CR: Remove duplicate instruction * CR: Apply suggested simplifications * Add test for lambda-lifting of mutually recursive functions * CR * Revert addition of no longer necessary Freevars functions * Add wasm mode to double translation tests * CR: Add missing Wasm stubs * Revert "Add wasm mode to double translation tests" This reverts commit d3cc1b7. * Update dune.inc * CR * CR * Use copy_file rather than duplicate tests * Update comment * Simplify function rewrite_instr * Function assume_no_perform makes perform fail for all effect implementations * CR: Add --effects option * Fix Dynlink and limit use of --enable=effects * Reformat * CR * CR * CR: add missing bound check * CR: Simplification in compiler/lib/effects.ml Co-authored-by: Jérôme Vouillon <[email protected]> * CR: simplify closure allocation * Javascript runtime: stop using 'arguments' * Fix too early effects backend setting Co-authored-by: Jérôme Vouillon <[email protected]> * Fix uses of `--enable=effects` in lib-wasm/ * Move assume_no_perform to Jsoo_runtime * Fix: move C primitive * CR * CR: rephrase comment Co-authored-by: hhugo <[email protected]> * CR: Move effects backend choice logic * CR: simplify * Docs: document double translation better Only document the use of `--enable effects` for now, as only this option is correctly handled by Dune, and document possible caching issues with `--effects=double-translation`. * Fix warning * Fix another warning * Update manual/effects.wiki Co-authored-by: Jérôme Vouillon <[email protected]> * CR: revert some changes in docs Co-authored-by: Jérôme Vouillon <[email protected]> * Don't set effects_backend in _cmd_arg_ modules * Fix compilation * CR * CR: add CONFIG macro * Re-export Jsoo_runtime from the js_of_ocaml library * Fix spurious free var warning over CONFIG macro * CR: Update compiler/lib/driver.ml Co-authored-by: hhugo <[email protected]> * Remove duplicate effects flag * CR: more explicit type for effects backend * CR: doc phrasing * CR: revert obsolete change * Fix assertion * CR: comment to justify constant * reformat * Fixes * Fix assert failure * reformat * CR: Create Js_of_ocaml.Effect_js * CR: move new tests to tests-jsoo/lib-effects * Fix warnings in tests --------- Co-authored-by: Jérôme Vouillon <[email protected]> Co-authored-by: hhugo <[email protected]>
1 parent 4587ff5 commit bff8d13

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+3221
-531
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* Merged Wasm_of_ocaml (#1724)
77
* Lib: removed no longer relevant Js.optdef type annotations (#1769)
88
* Misc: drop support for IE
9+
* Effects: add an optional feature of "dynamic switching" between CPS and direct style, resulting in better performance when no effect handler is installed
910

1011
## Bug fixes
1112
* Fix small bug in global data flow analysis (#1768)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ optimized:
9292
[More](http://ocsigen.org/js_of_ocaml/dev/manual/tailcall) about tail call
9393
optimization.
9494

95-
Effect handlers are supported with the `--enable=effects` flag.
95+
Effect handlers are supported with the `--effects={cps,double-translation}`
96+
flag.
9697

9798
## Data representation
9899

README_wasm_of_ocaml.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ In particular, the output code requires the following [Wasm extensions](https://
1313

1414
OCaml 5.x code using effect handlers can be compiled in two different ways:
1515
One can enable the CPS transformation from `js_of_ocaml` by passing the
16-
`--enable=effects` flag. Without the flag `wasm_of_ocaml` will instead emit code
17-
utilizing
16+
`--effects=cps` flag. Without the flag `wasm_of_ocaml` will instead default to
17+
`--effects=jspi` and emit code utilizing
1818
- [the JavaScript-Promise Integration extension](https://github.com/WebAssembly/js-promise-integration/blob/main/proposals/js-promise-integration/Overview.md)
1919

2020

compiler/bin-js_of_ocaml/build_fs.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ function jsoo_create_file_extern(name,content){
6262
|}
6363
in
6464
Config.set_target `JavaScript;
65+
Config.set_effects_backend `Disabled;
6566
let fragments = Linker.Fragment.parse_string code in
6667
Linker.load_fragments ~target_env:Isomorphic ~filename:"<dummy>" fragments;
6768
Linker.check_deps ();

compiler/bin-js_of_ocaml/check_runtime.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ let print_groups output l =
4444

4545
let f (runtime_files, bytecode, target_env) =
4646
Config.set_target `JavaScript;
47+
Config.set_effects_backend `Disabled;
4748
Linker.reset ();
4849
let runtime_files, builtin =
4950
List.partition_map runtime_files ~f:(fun name ->

compiler/bin-js_of_ocaml/cmd_arg.ml

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ let trim_trailing_dir_sep s =
3939

4040
let normalize_include_dirs dirs = List.map dirs ~f:trim_trailing_dir_sep
4141

42+
let normalize_effects (effects : [ `Cps | `Double_translation ] option) common :
43+
Config.effects_backend =
44+
match effects with
45+
| None ->
46+
(* For backward compatibility, consider that [--enable effects] alone means
47+
[--effects cps] *)
48+
if List.mem "effects" ~set:common.Jsoo_cmdline.Arg.optim.enable
49+
then `Cps
50+
else `Disabled
51+
| Some ((`Cps | `Double_translation) as e) -> (e :> Config.effects_backend)
52+
4253
type t =
4354
{ common : Jsoo_cmdline.Arg.t
4455
; (* compile option *)
@@ -65,6 +76,7 @@ type t =
6576
; fs_output : string option
6677
; fs_external : bool
6778
; keep_unit_names : bool
79+
; effects : Config.effects_backend
6880
}
6981

7082
let wrap_with_fun_conv =
@@ -253,6 +265,16 @@ let options =
253265
& opt (some string) None
254266
& info [ "ofs" ] ~docs:filesystem_section ~docv:"FILE" ~doc)
255267
in
268+
let effects =
269+
let doc =
270+
"Select an implementation of effect handlers. [$(docv)] should be one of $(b,cps) \
271+
or $(b,double-translation). Effects won't be supported if unspecified."
272+
in
273+
Arg.(
274+
value
275+
& opt (some (enum [ "cps", `Cps; "double-translation", `Double_translation ])) None
276+
& info [ "effects" ] ~docv:"KIND" ~doc)
277+
in
256278
let build_t
257279
common
258280
set_param
@@ -279,7 +301,8 @@ let options =
279301
output_file
280302
input_file
281303
js_files
282-
keep_unit_names =
304+
keep_unit_names
305+
effects =
283306
let inline_source_content = not sourcemap_don't_inline_content in
284307
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
285308
let runtime_files = js_files in
@@ -318,6 +341,7 @@ let options =
318341
let params : (string * string) list = List.flatten set_param in
319342
let static_env : (string * string) list = List.flatten set_env in
320343
let include_dirs = normalize_include_dirs include_dirs in
344+
let effects = normalize_effects effects common in
321345
`Ok
322346
{ common
323347
; params
@@ -341,6 +365,7 @@ let options =
341365
; bytecode
342366
; source_map
343367
; keep_unit_names
368+
; effects
344369
}
345370
in
346371
let t =
@@ -371,7 +396,8 @@ let options =
371396
$ output_file
372397
$ input_file
373398
$ js_files
374-
$ keep_unit_names)
399+
$ keep_unit_names
400+
$ effects)
375401
in
376402
Term.ret t
377403

@@ -496,6 +522,16 @@ let options_runtime_only =
496522
& opt (some string) None
497523
& info [ "ofs" ] ~docs:filesystem_section ~docv:"FILE" ~doc)
498524
in
525+
let effects =
526+
let doc =
527+
"Select an implementation of effect handlers. [$(docv)] should be one of $(b,cps) \
528+
or $(b,double-translation). Effects won't be supported if unspecified."
529+
in
530+
Arg.(
531+
value
532+
& opt (some (enum [ "cps", `Cps; "double-translation", `Double_translation ])) None
533+
& info [ "effects" ] ~docv:"KIND" ~doc)
534+
in
499535
let build_t
500536
common
501537
toplevel
@@ -515,7 +551,8 @@ let options_runtime_only =
515551
sourcemap_root
516552
target_env
517553
output_file
518-
js_files =
554+
js_files
555+
effects =
519556
let inline_source_content = not sourcemap_don't_inline_content in
520557
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
521558
let runtime_files = js_files in
@@ -544,6 +581,7 @@ let options_runtime_only =
544581
let params : (string * string) list = List.flatten set_param in
545582
let static_env : (string * string) list = List.flatten set_env in
546583
let include_dirs = normalize_include_dirs include_dirs in
584+
let effects = normalize_effects effects common in
547585
`Ok
548586
{ common
549587
; params
@@ -567,6 +605,7 @@ let options_runtime_only =
567605
; bytecode = `None
568606
; source_map
569607
; keep_unit_names = false
608+
; effects
570609
}
571610
in
572611
let t =
@@ -590,6 +629,7 @@ let options_runtime_only =
590629
$ sourcemap_root
591630
$ target_env
592631
$ output_file
593-
$ js_files)
632+
$ js_files
633+
$ effects)
594634
in
595635
Term.ret t

compiler/bin-js_of_ocaml/cmd_arg.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ type t =
4949
; fs_output : string option
5050
; fs_external : bool
5151
; keep_unit_names : bool
52+
; effects : Config.effects_backend
5253
}
5354

5455
val options : t Cmdliner.Term.t

compiler/bin-js_of_ocaml/compile.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ let run
153153
; export_file
154154
; keep_unit_names
155155
; include_runtime
156+
; effects
156157
} =
157158
let source_map_base = Option.map ~f:snd source_map in
158159
let source_map =
@@ -165,6 +166,7 @@ let run
165166
let custom_header = common.Jsoo_cmdline.Arg.custom_header in
166167
Config.set_target `JavaScript;
167168
Jsoo_cmdline.Arg.eval common;
169+
Config.set_effects_backend effects;
168170
Linker.reset ();
169171
(match output_file with
170172
| `Stdout, _ -> ()

compiler/bin-wasm_of_ocaml/cmd_arg.ml

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ let trim_trailing_dir_sep s =
3838

3939
let normalize_include_dirs dirs = List.map dirs ~f:trim_trailing_dir_sep
4040

41+
let normalize_effects (effects : [ `Cps | `Jspi ] option) common : Config.effects_backend
42+
=
43+
match effects with
44+
| None ->
45+
(* For backward compatibility, consider that [--enable effects] alone means
46+
[--effects cps] *)
47+
if List.mem "effects" ~set:common.Jsoo_cmdline.Arg.optim.enable then `Cps else `Jspi
48+
| Some ((`Cps | `Jspi) as e) -> e
49+
4150
type t =
4251
{ common : Jsoo_cmdline.Arg.t
4352
; (* compile option *)
@@ -51,6 +60,7 @@ type t =
5160
; sourcemap_don't_inline_content : bool
5261
; params : (string * string) list
5362
; include_dirs : string list
63+
; effects : Config.effects_backend
5464
}
5565

5666
let options =
@@ -103,6 +113,16 @@ let options =
103113
let doc = "Add [$(docv)] to the list of include directories." in
104114
Arg.(value & opt_all string [] & info [ "I" ] ~docv:"DIR" ~doc)
105115
in
116+
let effects =
117+
let doc =
118+
"Select an implementation of effect handlers. [$(docv)] should be one of $(b,jspi) \
119+
(the default) or $(b,cps)."
120+
in
121+
Arg.(
122+
value
123+
& opt (some (enum [ "jspi", `Jspi; "cps", `Cps ])) None
124+
& info [ "effects" ] ~docv:"KIND" ~doc)
125+
in
106126
let build_t
107127
common
108128
set_param
@@ -115,7 +135,8 @@ let options =
115135
sourcemap_root
116136
output_file
117137
input_file
118-
runtime_files =
138+
runtime_files
139+
effects =
119140
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
120141
let output_file =
121142
let ext =
@@ -133,6 +154,7 @@ let options =
133154
let params : (string * string) list = List.flatten set_param in
134155
let enable_source_maps = (not no_sourcemap) && sourcemap in
135156
let include_dirs = normalize_include_dirs include_dirs in
157+
let effects = normalize_effects effects common in
136158
`Ok
137159
{ common
138160
; params
@@ -145,6 +167,7 @@ let options =
145167
; enable_source_maps
146168
; sourcemap_root
147169
; sourcemap_don't_inline_content
170+
; effects
148171
}
149172
in
150173
let t =
@@ -161,7 +184,8 @@ let options =
161184
$ sourcemap_root
162185
$ output_file
163186
$ input_file
164-
$ runtime_files)
187+
$ runtime_files
188+
$ effects)
165189
in
166190
Term.ret t
167191

@@ -204,6 +228,16 @@ let options_runtime_only =
204228
& opt_all (list (pair ~sep:'=' (enum all) string)) []
205229
& info [ "set" ] ~docv:"PARAM=VALUE" ~doc)
206230
in
231+
let effects =
232+
let doc =
233+
"Select an implementation of effect handlers. [$(docv)] should be one of $(b,jspi) \
234+
(the default) or $(b,cps)."
235+
in
236+
Arg.(
237+
value
238+
& opt (some (enum [ "jspi", `Jspi; "cps", `Cps ])) None
239+
& info [ "effects" ] ~docv:"KIND" ~doc)
240+
in
207241
let build_t
208242
common
209243
set_param
@@ -213,10 +247,12 @@ let options_runtime_only =
213247
sourcemap_don't_inline_content
214248
sourcemap_root
215249
output_file
216-
runtime_files =
250+
runtime_files
251+
effects =
217252
let params : (string * string) list = List.flatten set_param in
218253
let enable_source_maps = (not no_sourcemap) && sourcemap in
219254
let include_dirs = normalize_include_dirs include_dirs in
255+
let effects = normalize_effects effects common in
220256
`Ok
221257
{ common
222258
; params
@@ -229,6 +265,7 @@ let options_runtime_only =
229265
; enable_source_maps
230266
; sourcemap_root
231267
; sourcemap_don't_inline_content
268+
; effects
232269
}
233270
in
234271
let t =
@@ -242,6 +279,7 @@ let options_runtime_only =
242279
$ sourcemap_don't_inline_content
243280
$ sourcemap_root
244281
$ output_file
245-
$ runtime_files)
282+
$ runtime_files
283+
$ effects)
246284
in
247285
Term.ret t

compiler/bin-wasm_of_ocaml/cmd_arg.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type t =
3131
; sourcemap_don't_inline_content : bool
3232
; params : (string * string) list
3333
; include_dirs : string list
34+
; effects : Config.effects_backend
3435
}
3536

3637
val options : t Cmdliner.Term.t

0 commit comments

Comments
 (0)