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

exnref <: anyref allows cyclical references to exceptions #85

Closed
AndrewScheidecker opened this issue Jul 14, 2019 · 5 comments
Closed

Comments

@AndrewScheidecker
Copy link
Contributor

From the proposal:

For this reason, WebAssembly exceptions are designed to allow other storage management methods, such as reference counting, to perform the garbage collection in the embedder.

To do this, WebAssembly exceptions are immutable once created, to avoid cyclic data structures that cannot easily be reference-counted.

The exception reference type can be represented as a subtype of anyref type introduced in WebAssembly reference type proposal.

If exnref <: anyref, then it's possible to form cycles including an exception object. For example, you can throw an exception with an argument that references a function, catch the exception, and store the exnref in a global accessible by the function referenced by the exception. The function must implicitly hold a reference to the global that it may access, so there's a cycle from exception->function->global->exception.

I can't see how it's possible to prohibit exnref cycles as long as they are subtypes of anyref and can stored in tables, mutable globals, etc. Am I missing something?

@rossberg
Copy link
Member

If you take dynamic lifetime management for functions and instances into account, then you cannot prohibit cycles in general. Even in the MVP, you can create a cycle between a table M1.t and two functions M1.f and M2.f from different modules M1, M2, by putting M2.f into M1.t.

So cycles involving functions are not new. I think the statement from the proposal is meant to say that there cannot be cycles between "dynamically" allocated values (where functions and instances are considered "static" in some suitable sense).

Also note that the situation is simply a consequence of exnref being a value type, which allows storing it in a global (and which is intentional). Whether exnref is also a subtype of anyref makes no difference AFAICS.

@AndrewScheidecker
Copy link
Contributor Author

It's true that anyref implies that you need a garbage collector that can handle cycles. However, there's still some value to constraining exceptions to be reference counted: it's easier to free the exceptions precisely when they become unreferenced, instead of waiting for the garbage collector to scan the heap.

I think the statement from the proposal is meant to say that there cannot be cycles between "dynamically" allocated values (where functions and instances are considered "static" in some suitable sense).

I don't see how this distinction makes it easier to reference count exceptions that are part of a cycle that includes "static" objects.

Whether exnref is also a subtype of anyref makes no difference AFAICS.

I'm only saying that making exnref a subtype of anyref implies cycles, not that making exnref disjoint from anyref is sufficient to prohibit cycles. To prohibit cycles, it would also be necessary to make exnref some kind of value type that cannot be stored in globals. That seems like a case of the cure is worse than the disease, though.

@rossberg
Copy link
Member

I don't see how this distinction makes it easier to reference count exceptions that are part of a cycle that includes "static" objects.

It means that you only need to worry about cycles in situations where you already have to, namely when wanting to deallocate modules or functions. That is, an engine can handle exnrefs per se with reference counting; a global may hold a reference. If the engine has no mechanism for deallocating modules (which may be the case in offline VMs, for example), then that's enough. OTOH, a system that wants to deallocate modules already needs to have a mechanism to detect cycles between module-level objects. All that changes is that this mechanism now also needs to look through exnrefs, not just funcrefs. Either can occur in globals or tables.

@AndrewScheidecker
Copy link
Contributor Author

It's possible to eagerly free an exception by storing two separate reference counts: one for locals and value stack slots, and one for globals and table elements. When both reference counts reach zero, the exception may be eagerly freed. When only the local/stack reference count is zero, it may still be possible to free the exception by scanning for unreachable anyref cycles.

Nevertheless, I think some clarification to the proposal is warranted.

@aheejin
Copy link
Member

aheejin commented Oct 12, 2020

Closing this, as we decided to remove exnref in Sep 15 CG meeting.

@aheejin aheejin closed this as completed Oct 12, 2020
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