Support for Cross-Language Garbage Collection

Is there a case in wasm in which it can refer to objects on other side of the bridge and direct their actions or cause resources to be held circularly? Simply because it is pass by value doesn’t mean those values can’t be handles. I suspect the answer will be no. But I want to make sure.

The question wasn’t whether WASM has cross language garbage collection (which is very unlikely given I can’t find such a thing in literature) but simply whether there was the potential for reference loops that CLGC can help resolve. Either way thanks for the input.

Possibly. The WIT types have resources that are essentially pointers, so who knows what one might do with them in terms of lists, behind the scenes, etc. Honestly, WASI generally assumes a compiled language, and so there’s also a bit of an assumption something like a circular reference isn’t an issue since it’s still just memory you’re going to free at some point when you decide you are done with the resource.

Thanks for the response.

I will consider that a negative on the need. If the resource is created temporarily and you don’t have two different languages which are strongly referencing each other that clgc is likely not needed. It sounds more like one language is running as a resource and is thrown away on demand thus there are never going to be any back references that is more like a disposable object where one side is dominate. Since the objects on the other side of WIT can’t access Python object nor be given a Python refence that they will increment the reference count on the Python object while they are alive it is unlikely a loop can form.

Currently I have only found Python<–>Java and Python<–>Javascript as being potential users (two gcs with some way to reference each other).

For Java we can 1) have Python reference a Java Object. 2) Pass a Python resource to Java and have it hold it.

I believe the same for the Javascript users though I need a bit more info.

I had a discussion with @Thrameos about this proposal here. Based on that discussion, I believe that this general approach is capable of solving Pyodide’s two-garbage-collectors problem.

3 Likes

I am ready to begin the work. With the help of @hoodmane, we determined that this tool would solve their issue and likely the same issue in C# (though I have not succeeded in making contact). That means at least 2 clear users of the API and one likely user.

To use the technology

  • Both sides of the bridge must create reference managers (the one in CPython will be mostly standardized, the other will be language specific)
  • There needs to be a deadlock free method of communication of messages between the reference managers.
  • There are a number of “danger” cases that have to be avoided, such as the requirement of make-before-break for certain actions. As one can get into the case where both garbage collectors are running at the same time.
  • The CPython side will be triggered by the modified CPython API.
  • The entire module must use the reference manager resources to communicate.
  • A manual with diagrams showing each of the interactions. While the number of actions the reference managers take is very limited the interactions are complex because we must maintain a set of invariants such that nothing which is referenced can ever be collected.

(If someone cares to try to prove the method mathematically it appears possible, but my eldest estimated it would take considerable effort just to pose the problem formally as a colored graph problem.)

The other important point that came from the conversation is that if one of the references which has been internalized is accessed from the uncooperative side, all of its leases must be returned to the ReferenceManager until the next cycle because it is possible that the tree was reattached.

My current plans are to create a PR containing the CPython implementation under the PyUnstable likely as a file call Include/cpython/clgc.h. I will then incorporate all of the hooks required use the garbage collection. That is the easy part as the API is very small and the location of the modification is highly confined. Total time may be as little as a few hours.

From this point it gets a bit challenging. My desire is to make a reference version which shows exactly how the clgc operates, but the only models we have (Javascript, Java, and C#) currently don’t have the type of reference manager that would be required out of the box. Thus either I have to modify a large package to demonstrate it or create toy package which is capable of demonstrating its use. A large package modification will take several weeks to execute and likely will be extensive enough that it won’t be a very good model for others to follow. A toy problem will be faster but at the same time will need to build enough infrastructure that perform some useful function (such as a module that can only manipulate lists and hashtables.) Even that for a JNI is rather extensive in terms of a code base. There is also the matter of complexity versus efficiency. For high efficiency the reference manager would want to spool up a large number of transactions and execute them. But this would make the reference implementation much harder to follow. So this will be a tough balancing act.

I will probably start with the JPype modifications, and then decide if we can reduce it into a reference implementation. That would be the least work on my part. I can then coordinate with any others interested in using the same method.

@encukou If you have any guidance as to how to best accomplish the goal, now is the time as I will be executing the plan this month.

@hoodmane Phase 1 is complete. I have added the proposed API to CPython and collected the changes into a PR so that we can look at the proposed API. The API is completely opaque and I believe consistent with the requirements of not locking in the current GC and not exposing any of the current GC implementation to the outside. Next, I need to debug by building a reference implementation on to verify function.