Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add javascript backend output support #31

Open
jappeace opened this issue Mar 14, 2023 · 7 comments
Open

Add javascript backend output support #31

jappeace opened this issue Mar 14, 2023 · 7 comments

Comments

@jappeace
Copy link

Feature request

Recently I tried helping a someone on discord, however it's rather difficult to get a specific version of ghc compiler since I'm on nixos, I could only get ghc 9.7.1 but it didn't have the javascript backend. It'd be great if the playground would have the javascript backend supported as well so I can play around with FFI.

@tomsmeding
Copy link
Collaborator

What would you imagine the support to look like? Would the javascript be run in the client's browser, or on the server, and if the latter in what runtime? (Sorry, I'm not yet familiar with how the new backends work)

@jappeace
Copy link
Author

I'd say add a js button next to asm for example:

image

I care not much for execution, I just want to see what it produces, to execute I can paste it into file to run in a browser.

@tomsmeding
Copy link
Collaborator

tomsmeding commented Mar 15, 2023

While this would be possible, I'm not sure it would be terribly useful. Following this page, I compiled the quicksort example to JS and looked at the outputs. We have:

  • rts.js: generated RTS code. I'd assume not relevant to you. 282KiB
  • lib.js: js-sources output, including some RTS stuff. Same. 212KiB
  • out.js: compiled Haskell sources, including your own code but also stuff in used libraries such as base. 1.7MiB
  • runmain.js which contains literally h$main(h$mainZCZCMainzimain);
  • all.js which is just the concatenation of the above, in-order. 2.2MiB

And some other files, description copied from the link above (ghc wiki):

  • all.js.externs are exported references from the JS backend RTS.
  • out.frefs.js and out.frefs.json are used for foreign references. out.frefs.js contains only a single unused function h$checkForeignRefs and out.frefs.json is empty. These files will be used once the FFI is implemented.
  • out.stats provides some metadata on the number of modules used in the program and their size.

Amusingly, all.js.externs is identical to the output of the following bash script, both for a hello world example and for quicksort: echo '// GHCJS RTS externs for closure compiler ADVANCED_OPTIMIZATIONS'; echo; for i in $(seq 7 16384); do echo '/** @type {*} */'; echo "Object.d$i;"; done. Also it's 502KiB.

So what would you like to see? Putting all.js in a browser works, it seems, but it contains such a gigantic amount of cruft in addition to the code you're interested in that I'm not sure showing that in the playground output is helpful to anyone. To be noted is that the current output size limit is 100 000 bytes, whereas all.js is almost 23x that.

EDIT: all.js, out.js

@jappeace
Copy link
Author

lol, yeah, that'd be the entire runtime ported to JS for us.

yeah, clearly I've not thought trough all implications of this request,
but still having to build a custom ghc just to play around with javascript is kind of bad user experience.

Maybe it'd be possible to offer the files for download?

@Kleidukos
Copy link
Member

Perhaps we can do some explicit post-processing like stripping the RTS stuff and piping through the Closure Compiler ?
Yes it's not necessarily a faithful exact representation of what will be be output but:

  1. It's for an online visualisation, so it's okay to provide reduced outputs
  2. The playground is not an interactive development environment, we must give priority to ease of use.

@tomsmeding
Copy link
Collaborator

  • gzip'ing all.js reduces the initial 2.2 MiB to 269 KiB
  • passing all.js through the closure compiler with --assume_function_wrapper --warning_level QUIET produces 493 KiB
  • Passing that closure compiler result through gzip yields 105 KiB

However, the closure compiler takes about 4.5 seconds to do so. And that's on a processor running at >5 GHz, which is more than your average VPS.

However, stripping RTS stuff is clearly something we can do -- if anything, we can transfer it to the client once instead of on every compile. But rts.js is just 282 KiB out of the full 2.2 MiB, so that doesn't help much.

@Kleidukos

It's for an online visualisation

Depends on what we want the goal of this to be. If the goal is what @jappeace said, which is to just offer the files for download: this would be possible, but it's only tangentially related to the goal of the playground, and we only sort-of by accident have some infrastructure for that. (Though not all.) So I'm not terribly enthousiastic about this, while I would be happy to give some tips/pointers on how to set up a very simple sandboxed compilation server.

If the goal is to run the code in the client's browser, we need all the code there, and it isn't very important how the code looks. But sending over multi-megabyte downloads for every run is a bit much -- and the closure compiler is apparently far too slow to be useful here.

If the goal is to let the user look at the code: closure compiler wouldn't help, and honestly I have no clue where to look even in the 1.7 MiB that is out.js, allegedly containing the user's haskell code. (It also includes compiled code from base, which perhaps is what makes it large.)

So I'm not terribly optimistic currently. :D But if your opinion differs on any of these points, please speak up! My opinions here are weakly held.

@Kleidukos
Copy link
Member

Kleidukos commented Mar 15, 2023

For the JS dump (which is thankfully not the same as executing in the browser, which is fairly dangerous anyway), we have to find a way to isolate the user code, prettify it a bit and display it. Which means that we remove RTS, base and such.

If the goal is to run the code in the client's browser, we need all the code there, and it isn't very important how the code looks. But sending over multi-megabyte downloads for every run is a bit much -- and the closure compiler is apparently far too slow to be useful here.

In my professional opinion, this is not a thing we should aim to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants