js_of_ocaml icon indicating copy to clipboard operation
js_of_ocaml copied to clipboard

Making the OCaml compiler more friendly to Js_of_ocaml

Open vouillon opened this issue 10 years ago • 23 comments

I have recently proposed to change the definition of Pervasives.min/max_int so that Js_of_ocaml does not have to patch the bytecode (ocaml/ocaml#19). I'm wondering what other changes we could propose that would be useful to Js_of_ocaml.

  • [x] Pervasives.min/max_int
  • [x] caml_alloc_dummy_closure
  • [x] Sys.int_size
  • [x] Sys.max_array_length
  • [x] String.concat #977 #1585
  • [ ] map OCaml values to JavaScript objects, MAKEBLOCK is used for allocating both arrays and blocks
  • [x] caml_alloc_dummy_infix could receive arity https://github.com/ocsigen/js_of_ocaml/pull/1393#issuecomment-1400612112

vouillon avatar Mar 20 '14 10:03 vouillon

One more PR that might break js_of_ocaml. see comment https://github.com/ocaml/ocaml/pull/14#issuecomment-35822033

hhugo avatar Mar 20 '14 10:03 hhugo

What about more debug (event) information ?

hhugo avatar Mar 20 '14 10:03 hhugo

What do you mean?

vouillon avatar Mar 20 '14 10:03 vouillon

could we improve sourcemap generation with more debug information ?

hhugo avatar Mar 20 '14 10:03 hhugo

Do you have anything specific in mind? I would say we already have all the needed information: for code with debugg information, we should be able to associate to any bytecode instruction a corresponding location in the source code.

vouillon avatar Mar 20 '14 11:03 vouillon

Code like let rec f x y = 1 and z = Some (f, h) is compiled using primitive caml_alloc_dummy to allocate a block (for all values but floats, including closures), then caml_update_dummy to fill the block with its actual contents. So we have a hack in Js_of_ocaml to be able to use a block (a JavaScript array), as if it was a function.

It would be better if a specific primitive caml_alloc_dummy_closure was used to allocate dummy closures. Even better, this primitive could be given the arity of the closure. Then, we could compile a primitive call caml_alloc_dummy_function(2) into a function function f(x,y) {return f.fun(x,y); } which does not need any specific runtime support.

vouillon avatar Mar 20 '14 11:03 vouillon

I'm wondering whether we could do something for recursive modules as well. At the moment, we have a hack that replaces the bytecode implementation of CamlinternalMod by a JavaScript implementation.

vouillon avatar Mar 20 '14 13:03 vouillon

caml_alloc_dummy_closure => https://github.com/hhugo/ocaml/compare/jsoo_friendly

hhugo avatar Apr 01 '14 14:04 hhugo

limits due to runtime representation should/could be set from the runtime.

  • Sys.max_array_length
  • Sys.int_size (new)

hhugo avatar Apr 09 '14 10:04 hhugo

https://github.com/ocaml/ocaml/pull/37

hhugo avatar Apr 15 '14 06:04 hhugo

https://github.com/ocaml/ocaml/pull/36

hhugo avatar Apr 15 '14 06:04 hhugo

If String.copy and (^) were implemented as primitive, we could more easily generate efficient code for them.

vouillon avatar Sep 24 '14 09:09 vouillon

OCaml is switching to immutable strings. However, as they are implemented imperatively, based on byte sequence operations, there does not seem to be any easy way to take advantage of this.

vouillon avatar Sep 24 '14 09:09 vouillon

We should probably map OCaml values to JavaScript objects rather than JavaScript arrays. Indeed, this is more memory efficient (V8 has a high overhead for arrays; the block tag would not need to be stored in the object) and potentially faster (no need for bound check when accessing fields).

However, the same bytecode instruction MAKEBLOCK is used for allocating both arrays and blocks.

vouillon avatar Sep 24 '14 09:09 vouillon

How would you compile OCaml value to Js Object ? One constructor per tag and size couple ?

hhugo avatar Sep 25 '14 17:09 hhugo

@vouillon, a quick experiment with compiling ocaml blocks to Js objects shows poor performances. x2.5 slower on @jordwalke example.

(deriving and marshall not updated) https://github.com/ocsigen/js_of_ocaml/tree/caml_block https://github.com/hhugo/ocaml/tree/make_array

hhugo avatar Sep 26 '14 10:09 hhugo

This is because you are using numeric fields. Here is what I get by manually tweaking the JavaScript output:

Arrays Objects (numeric fields) Objects (non-numeric fields)
V8 180 500 125
JSC 86 150 83
Spidermonkey 170 300 82

vouillon avatar Sep 26 '14 11:09 vouillon

I've update the code (regression inside) to use non-numeric fields. It's better but still a little bit slower than the current implem.

hhugo avatar Sep 26 '14 13:09 hhugo

Which JavaScript engine did you try? Which version?

vouillon avatar Sep 26 '14 14:09 vouillon

this is very interesting discussion, @vouillon , how did you get such numbers? btw, it is not always correct to compile blocks and arrays differently, since some internal hacks of the compiler treat array and object in a uniform way

bobzhang avatar Feb 11 '16 15:02 bobzhang

That's the timings for a single program, that I manually rewrote.

You're right that for making this work the OCaml compiler would have to be modified.

vouillon avatar Feb 17 '16 10:02 vouillon

If String.copy and (^) were implemented as primitive, we could more easily generate efficient code for them.

I believe we are now closer to optimize theses string operations (xlink #977 #976 #924)

hhugo avatar May 03 '20 17:05 hhugo

de implementation of CamlinternalMod by a JavaScript implementation.

This is now gone

hhugo avatar Sep 22 '21 11:09 hhugo