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

Special topic chapter for finalizers and weak references #1265

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

wks
Copy link
Collaborator

@wks wks commented Jan 16, 2025

This PR adds a special topic chapter in the Porting Guide for supporting finalizers and weak references. This topic is frequently asked and somewhat complex, and needs a dedicated chapter.

We also updated the doc comments of the Scanning::process_weak_refs API to add code example of the intended use case, and warn the users about potential pitfalls.

wks added 2 commits January 21, 2025 19:33
Added a special topic chapter for how to implement finalizers and weak
references with MMTk.
@wks wks force-pushed the feature/weak-final-guide branch from b2ea9b3 to be789b2 Compare January 21, 2025 11:51
@wks wks changed the title WIP: Special topic chapter for weak references Special topic chapter for finalizers and weak references Jan 23, 2025
@wks wks marked this pull request as ready for review January 23, 2025 06:24
@wks wks requested review from qinsoon and k-sareen January 23, 2025 06:25
@wks
Copy link
Collaborator Author

wks commented Jan 23, 2025

I have finished the chapter, and I invited @qinsoon and @k-sareen to review it. There are some things I haven't done in this PR, but can be added later.

  1. Ephemerons: We currently have not implemented ephemerons in any VMs. We need Ephemeron for V8, but that's not a priority at this moment. We can add a subsection for ephemerons when we implemented it, or when someone needs help implementing ephemerons with MMTk. (Update: I added a section for ephemerons. But since we don't have a VM that actively uses that algorithm, we can't verify if that algorithm is correct.)
  2. Hyperlinks between the doc comments in the code and the Porting Guide chapter. The porting guide needs to be rendered in order to be published to https://docs.mmtk.io/, and that'll happen after this PR is merged. We can add the URL when the new chapter becomes publicly available.

Maybe I also need to define some concepts in that chapter, such as what exactly is a finalizer or a weak reference. I think the current state is clear enough for people with experience with GC and VM development. But please let met know if anything is not clear.

@wks
Copy link
Collaborator Author

wks commented Jan 23, 2025

It is still arguable whether "retain" or "resurrect" is a better word for keeping an unreachable object alive in a GC. "Resurrect" is more intuitive because we also talk about "finalizers can resurrect dead objects". But the word "resurrect" may imply that the object has already died once. It is OK for finalizers because the object has already become unreachable during mutator time, which can be considered as "dead". But for soft references, it is a bit awkward to say we "resurrect" the referent of a soft reference because that implies we consider the referent as "dead" before. It is "dead" in the sense that it is not strongly reachable, but softly reachable objects usually live through GCs, as long as it is not emergency GC. Maybe "retain" is better when describing soft references.

In existing code, we use the word "retain" in many places in ReferenceProcessor. There is only one use of "resurrect" in FinalizerProcessor, and it was added by me.

Copy link
Member

@qinsoon qinsoon left a comment

Choose a reason for hiding this comment

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

The doc is written with dfiferent definitions of 'weak ref', and 'resurrect objects'. I think we should refer to a well-accepted literature such as the GC handbook for such definitions, and be consistent with their definitions. In my opinion, we need a pass through the section to fix the definitions and related descriptions. I would like to do a detailed review after that.

@@ -36,6 +36,8 @@
- [Performance Tuning](portingguide/perf_tuning/prefix.md)
- [Link Time Optimization](portingguide/perf_tuning/lto.md)
- [Optimizing Allocation](portingguide/perf_tuning/alloc.md)
- [Special Topics](portingguide/topics/prefix.md)
Copy link
Member

Choose a reason for hiding this comment

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

I suggest using something like "Runtime Features", or "Language Features" as the title. I don't see how this section is 'special' compared to other sections.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

What about "VM-Specific Concerns"?

The GC Handbook has a chapter named Language-Specific Concerns, and it discusses only finalizers and weak references. I think that's because finalizer and weak reference semantics is part of the programming language, and is visible to the programmers. Things like conservative stack scanning, object pinning and interior pointers are not all exposed at the language level, but they are more related to VM implementations. So "VM-Specific Concerns" may be a better title.

I don't like calling them "Runtime/Language Features" because "features" are things meant to be used by their users, but things like stack scanning are peculiar aspects of those runtimes/languages that their implementers should care about.

And I think "VM peculiarities" also describes what the chapters in this part are about. But it sounds offensive to the VMs.

@@ -0,0 +1,5 @@
# Special topics

Every VM is special in some way. Because of this, some VM bindings may use MMTk features not
Copy link
Member

Choose a reason for hiding this comment

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

If we change the title, the paragraph needs to be changed accordingly. I feel it is more reasonable that this section is dedicated to how to implement different runtime features with MMTk.

Comment on lines +6 to +8
Some VMs support **weak references**. If an object cannot be reached from roots following only
strong references, the object will be considered dead. Weak references to dead objects will be
cleared, and associated clean-up operations will be executed. Some VMs also support more complex
Copy link
Member

Choose a reason for hiding this comment

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

The definition for weak references is incorrect.

If an object cannot be reached from roots following only strong references, the object will be considered dead.

If an object cannot be reached from strong references, it is not "strongly reachable". It is not dead, as it can still be "weakly reachable". Sometimes "reachable" implies strongly reachable. That's fine. But this should not be used in a context that may cause confusion.

Weak references to dead objects will be cleared, and associated clean-up operations will be executed.

This is indeed confusing. If we have a weak reference to the object, the object is not dead. It is up to the language semantics or the VM to decide whether to keep the weakly-referenced object alive or not. Only when the VM decides that the referent will not be kept alive, the object/referent is dead, otherwise it is alive.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I will rewrite this part using definitions from the GC handbook, and probably add a "Definitions" section before the "Overview" section.

I didn't use the terms "strongly/weakly reachable" because I thought they were Java-specific. But since the GC Handbook also uses that term in the language-neutral introduction section of weak references, I believe those terms should be acceptable for other VMs in general, too.

- **Query forwarded address**: If an object is already reached, the VM binding can further query
the new address of an object. This is needed to support copying GC.
+ Do this with `ObjectReference::get_forwarded_object()`.
- **Resurrect objects**: If an object is not reached, the VM binding can optionally resurrect the
Copy link
Member

Choose a reason for hiding this comment

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

See my argument above for the definition of weak ref. We do not 'resurect' weak reference.

It is arguable whether we should say 'resurrect' finalizable objects. GC needs to keep finalizable objects alive until they are properly finalized -- I don't want to call it 'resurrect', simply it is not dead from the GC's perspective. Also 'resurrecting objects' normally refers to the specific application behavior that an object that is being finalized and should become dead after finalization is at the language/application level kept alive. Using 'resurrect' in the GC may get things confusing.

GC handbook's definition for 'resurrection': "an action performed by a finaliser that caused the previously unreachable object to become reachable."

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I consulted @eliotmoss and read the GC handbook, and they both agree with what you said. "Resurrection" refers to the action in the finalizer that makes the object reachable from other parts of the program by, for example, assigning its reference to a global variable. This is not what tracer.trace_object does. Even if we call trace_object(object), it still doesn't guarantee the object will "resurrect" in that sense. If the finalize() function doesn't leak its reference, the object will still be collectable after finalize() returns.

"Retain" should be a better term, and it is already used in JikesRVM as well as our existing ReferenceProcessor in mmtk-core.

descendants) live through the current GC. The typical use pattern is:

```rust
impl<VM: VMBinding> Scanning<VM> for VMScanning {
Copy link
Member

Choose a reason for hiding this comment

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

It is generally preferrable to put the code into a test, and include the snippets in the test in the doc. In such cases, the code will be always checked by the tests and the CI. Maybe we cannot run process_weak_refs in our mock tests, but we can still make sure that it can be compiled.

See here for examples:

{{#include ../../../../../src/vm/tests/mock_tests/mock_test_doc_mutator_storage.rs:mutator_storage_boxed_pointer}}

@k-sareen
Copy link
Collaborator

k-sareen commented Jan 24, 2025

I would avoid inventing terminology and just use what is in the GC Handbook. The handbook uses resurrect for finalizers and "trace" for soft references. Pg 213 onwards for the First Edition of the GC Handbook

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

Successfully merging this pull request may close these issues.

3 participants