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

enable lambda-lifting for the JavaScript target #586

Merged
merged 1 commit into from Mar 15, 2023

Conversation

zerbina
Copy link
Collaborator

@zerbina zerbina commented Mar 14, 2023

Summary

Previously, inner closure procedures were not lifted into free-standing procedures during transf, but rather kept as-is and mapped to nested JavaScript functions by jsgen. Besides requiring the JavaScript target to be special-cased in transf and lambdalifting, this also caused observable semantic issues: the destructors for captured variables were called when leaving the scope in which they were defined, not when the closure got destroyed.

In order to bring the closure semantics in line with the other targets and as a prerequisite for full ORC support, lambda-lifting is now also enabled when using the JS target -- the code generator is adjusted to support the lifted procedures. The code generator changes are also a
preparation for full closure iterator support.

As a side-effect, closures now also work as expected when using the JS target and executing non-compile-time-only procedures that have inner closure procedures at compile-time.

Details

  • remove the dispatching based on the selected backend from transf and lambdalifting
  • remove all code related to the previous closure support from jsgen
  • implement support for lifted procedures in jsgen

The hidden environment parameter of routines using the .closure calling convention is mapped to the this parameter at the JavaScript level.

When a NimSkull closure object is created, a new function instance is created via bind and the provided environment bound to the this parameter. In addition, the both the function and environment are also assigned to the respective prc and env properties on the function object -- this allows for later retrieval.

Compared to using an object, this approach has the benefit that closures can still be passed to an imported procedure that expects a JavaScript function object, without requiring any changes to the user code.


Notes for Reviewers

@saem saem added enhancement New feature or request compiler/sem Related to semantic-analysis system of the compiler compiler/backend Related to backend system of the compiler simplification Removal of the old, unused, unnecessary or un/under-specified language features. labels Mar 14, 2023
@saem saem added this to the JS backend refactoring milestone Mar 14, 2023
Copy link
Collaborator

@saem saem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome, good to merge! 🚀

I thought of two follow-ups. I'll start on the first one ~tomorrow and see about the second one based on the outcome:

  1. have as much of tests/lang_callable/iter run for js/all platforms see where things land
  2. quick update of the manual to remove the "big" mentions of can't use closure iterators for JS (rest can be long tail)

compiler/backend/jsgen.nim Outdated Show resolved Hide resolved
Summary
=======

Previously, inner closure procedures were not lifted into free-standing
procedures during `transf`, but rather kept as is and mapped to nested
JavaScript functions by `jsgen`. Besides requiring the JavaScript target
to be special-cased in `transf` and `lambdalifting`, this also caused
observable semantic issues: the destructors for captured variables were
called when leaving the scope in which they were defined, not when the
closure got destroyed.

In order to bring the closure semantics in line with the other targets
and as a prerequisite for full ORC support, lambda-lifting is now also
enabled when using the JS target -- the code generator is adjusted to
support the lifted procedures. The code generator changes are also a
preparation for full closure iterator support.

As a side-effect, closures now also work as expected when using the JS
target and executing non-compile-time-only procedures that have inner
closure procedures at compile-time.

Details
=======

- remove the dispatching based on the selected backend from `transf` and
  `lambdalifting`
- remove all code related to the previous closure support from `jsgen`
- implement support for lifted procedures in `jsgen`

The hidden environment parameter of routines using the `.closure`
calling convention is mapped to the this parameter at the JavaScript
level.

When a NimSkull closure object is created, a new function instance is
created via `bind` and the provided environment bound to the `this`
parameter. In addition, the both the function and environment are also
assigned to the respective prc and env properties on the function
object -- this allows for later retrieval.

Compared to using an object, this approach has the benefit that closures
can still be passed to an imported procedure that expects a JavaScript
function object, without requiring any changes to the user code.
@zerbina
Copy link
Collaborator Author

zerbina commented Mar 15, 2023

  1. have as much of tests/lang_callable/iter run for js/all platforms see where things land

Yep, that's a good idea. Having the iter tests work, at least in theory, on the JS and VM would be a big help when implementing closure iterator in the respective backends.

@zerbina
Copy link
Collaborator Author

zerbina commented Mar 15, 2023

bors r+

@bors
Copy link
Contributor

bors bot commented Mar 15, 2023

Build succeeded:

@bors bors bot merged commit 3fe97ba into nim-works:devel Mar 15, 2023
20 checks passed
@zerbina zerbina deleted the lambda-lifting-for-js branch March 15, 2023 22:18
@zerbina zerbina mentioned this pull request Apr 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/backend Related to backend system of the compiler compiler/sem Related to semantic-analysis system of the compiler enhancement New feature or request simplification Removal of the old, unused, unnecessary or un/under-specified language features.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants