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

Marking roots on the native stack #62

Open
y21 opened this issue Apr 29, 2023 · 1 comment
Open

Marking roots on the native stack #62

y21 opened this issue Apr 29, 2023 · 1 comment

Comments

@y21
Copy link
Owner

y21 commented Apr 29, 2023

A major problem with the current GC is that the vm has no way of telling that a variable in a native function is holding a reference to a JavaScript object. If a GC cycle happens to trigger (e.g. due to calling a JS function), the object referenced by the variable is (mistakenly) deallocated.

Fixing this likely requires major changes wrt how values are represented all over the vm and how native code works with these.
One possible way to fix this is to have a separate vector of "external references" (i.e. objects referenced by bindings on the native stack). The current vm actually already has something similar, but it requires manually adding values to it. It would be nice if we could make this sort of pattern a compile error (pseudocode):

fn native_function() {
  let o = create_object();
  js_function(); // calls some JavaScript function, GC triggers in here, `o` is not marked and gets deallocated
  print(o); // using deallocated object
}

We could perhaps make some kind of macro that also adds the assigned value to the external refs vector, used like so:

fn native_function() {
  letroot!(o = create_object()); // allocate object AND add to vector of external refs
  js_function(); // GC triggers, but `o` is in external refs vector and is not deallocated
  print(o); // ok
}
@y21
Copy link
Owner Author

y21 commented Jul 31, 2023

Now that we have an Unrooted API, one thing we could explore is using custom lints that check for how these are used.
In particular, one issue that remains is that one can carry an Unrooted object, call into JavaScript (which causes the unrooted value to get GC'd), then root the value, but at that point it is too late. We ideally would want to make this a compile error, so that you have to root all your values before doing anything with the Vm if you want to be able to carry them across JS boundaries, but I don't think it's possible to express that with the type system or lifetimes. The easier option for now would be to simply have some kind of deny lint that ensures that you must root Unrooted things as early as possible

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

No branches or pull requests

1 participant