@@ -43,14 +43,15 @@ method `schedule_common_work()` that will add common work packets for you.
4343
4444To use ` schedule_common_work() ` , first we need to create a type ` MyGCWorkContext `
4545and implement the trait ` GCWorkContext ` for it. We create ` gc_work.rs ` and add the
46- following implementation. Note that we do not set a specific ` ProcessEdgesWorkType `
47- and we will use the default [ ` SFTProcessEdges ` ] ( https://www.mmtk.io/mmtk-core/mmtk/scheduler/gc_work/struct.SFTProcessEdges.html ) ,
46+ following implementation. Note that we will use the default
47+ [ ` SFTProcessEdges ` ] ( https://www.mmtk.io/mmtk-core/mmtk/scheduler/gc_work/struct.SFTProcessEdges.html ) ,
4848which is a general work packet that a plan can use to trace objects. For plans
4949like semispace, ` SFTProcessEdges ` is sufficient. For more complex GC plans,
5050one can create and write their own work packet that implements the ` ProcessEdgesWork ` trait.
51+ We will discuss about this later, and discuss the alternatives.
5152
5253``` rust
53- {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: workcontext }}
54+ {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: workcontext_sft }}
5455```
5556
5657Then we implement ` schedule_collection() ` using ` MyGCWorkContext ` and ` schedule_common_work() ` .
@@ -111,35 +112,6 @@ there aren't any preparation steps for the mutator in this GC.
111112In ` create_mygc_mutator() ` , find the field ` prep_func ` and change it from
112113` mygc_mutator_noop() ` to ` mygc_mutator_prepare() ` .
113114
114-
115- ## Scan objects
116-
117- Next, we'll add the code to allow the plan to collect garbage - filling out
118- functions for work packets.
119-
120- In ` gc_work.rs ` , add a new method to ` ProcessEdgesWork for MyGCProcessEdges ` ,
121- ` trace_object(&mut self, object: ObjectReference) ` .
122- This method should return an ObjectReference, and use the
123- inline attribute.
124- Check if the object passed into the function is null
125- (` object.is_null() ` ). If it is, return the object.
126- Otherwise, check which space the object is in, and forward the call to the
127- policy-specific object tracing code. If it is in neither space, forward the
128- call to the common space and let the common space to handle object tracing in
129- its spaces (e.g. immortal or large object space):
130-
131- ``` rust
132- {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: trace_object }}
133- ```
134-
135- Add two new implementation blocks, ` Deref ` and ` DerefMut ` for
136- ` MyGCProcessEdges ` . These allow ` MyGCProcessEdges ` to be dereferenced to
137- ` ProcessEdgesBase ` , and allows easy access to fields in ` ProcessEdgesBase ` .
138-
139- ``` rust
140- {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: deref }}
141- ```
142-
143115## Release
144116
145117Finally, we need to fill out the functions that are, roughly speaking,
@@ -178,6 +150,91 @@ will then go to the new tospace.
178150Delete ` mygc_mutator_noop() ` . It was a placeholder for the prepare and
179151release functions that you have now added, so it is now dead code.
180152
153+ ## ProcessEdgesWork for MyGC
154+
155+ [ ` ProcessEdgesWork ` ] ( https://www.mmtk.io/mmtk-core/mmtk/scheduler/gc_work/trait.ProcessEdgesWork.html )
156+ is the key work packet for tracing objects in a GC. A ` ProcessEdgesWork ` implementation
157+ defines how to trace objects, and how to generate more work packets based on the current tracing
158+ to finish the object closure.
159+
160+ ` GCWorkContext ` specifies a type
161+ that implements ` ProcessEdgesWork ` , and we used ` SFTProcessEdges ` earlier. In
162+ this section, we discuss what ` SFTProcessEdges ` does, and what the alternatives
163+ are.
164+
165+ ### Approach 1: Use ` SFTProcessEdges `
166+
167+ [ ` SFTProcessEdges ` ] ( https://www.mmtk.io/mmtk-core/mmtk/scheduler/gc_work/struct.SFTProcessEdges.html ) dispatches
168+ trace objects to each space through [ Space Function Table (SFT)] ( https://www.mmtk.io/mmtk-core/mmtk/policy/space/trait.SFT.html ) .
169+ As long as all the policies in a plan provides an implementation of ` sft_trace_object() ` in their SFT implementation,
170+ the plan can use ` SFTProcessEdges ` . Currently most policies provide an implementation for ` sft_trace_object() ` , except
171+ mark compact and immix. Those two policies use multiple GC traces, and due to the limitation of SFT, SFT does not allow
172+ multiple ` sft_trace_object() ` for a policy.
173+
174+ ` SFTProcessEdges ` is the simplest approach when all the policies support it. Fortunately, we can use it for our GC, semispace.
175+
176+ ### Approach 2: Derive ` PlanTraceObject ` and use ` PlanProcessEdges `
177+
178+ ` PlanProcessEdges ` is another general ` ProcessEdgesWork ` implementation that can be used by most plans. When a plan
179+ implements the [ ` PlanTraceObject ` ] ( https://www.mmtk.io/mmtk-core/mmtk/plan/transitive_closure/trait.PlanTraceObject.html ) ,
180+ they can use ` PlanProcessEdges ` .
181+
182+ You can manually provide an implementation of ` PlanTraceObject ` for ` MyGC ` . But you can also use the derive macro MMTK provides,
183+ and the macro will generate an implementation of ` PlanTraceObject ` :
184+ * add ` #[derive(PlanTraceObject)] ` for ` MyGC ` (import the macro properly: ` use mmtk_macro_trace_object::PlanTraceObject ` )
185+ * add ` #[trace(CopySemantics::Default)] ` to both copy space fields, ` copyspace0 ` and ` copyspace1 ` . This tells the macro to generate
186+ trace code for both spaces, and for any copying in the spaces, use ` CopySemantics::DefaultCopy ` that we have configured early.
187+ * add ` #[fallback_trace] ` to ` common ` . This tells the macro that if an object is not found in any space with ` #[trace] ` in ths plan,
188+ try find the space for the object in the 'parent' plan. In our case, we fall back to the ` CommonPlan ` , as the object may be
189+ in large object space or immortal space in the common plan. ` CommonPlan ` also implements ` PlanTraceObject ` , so it knows how to
190+ find a space for the object and trace it in the same way.
191+
192+ With the derive macro, your ` MyGC ` struct should look like this:
193+ ``` rust
194+ {{#include .. / .. / .. / code / mygc_semispace / global . rs: plan_def }}
195+ ```
196+
197+ Once this is done, you can specify ` PlanProcessEdges ` as the ` ProcessEdgesWorkType ` in your GC work context:
198+ ``` rust
199+ {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: workcontext_plan }}
200+ ```
201+
202+ ### Approach 3: Implement your own ` ProcessEdgesWork `
203+
204+ Apart from the two approaches above, you can always implement your own ` ProcessEdgesWork ` . This is
205+ an overkill for simple plans like semi space, but is probably necessary for more complex plans.
206+ We discuss how to implement it for ` MyGC ` .
207+
208+ Create a struct ` MyGCProcessEdges<VM: VMBinding> ` in the ` gc_work ` module. It includes a reference
209+ back to the plan, and a ` ProcessEdgesBase ` field:
210+ ``` rust
211+ {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: mygc_process_edges }}
212+ ```
213+
214+ Implement ` ProcessEdgesWork ` for ` MyGCProcessEdges ` . As most methods in the trait have a default
215+ implemetation, we only need to implement ` new() ` and ` trace_object() ` for our plan. However, this
216+ may not be true when you are implement for other GC plans. It would be better to check the default
217+ implementation of ` ProcessEdgesWork ` .
218+
219+ For ` trace_object() ` , what we do is similar to the approach above (except that we need to write the code
220+ ourselves rather than letting the macro to generate it for us). We try figure out
221+ which space the object is in, and invoke ` trace_object() ` for the object on that space. If the
222+ object is not in any of the semi spaces in the plan, we forward the call to ` CommonPlan ` .
223+ ``` rust
224+ {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: mygc_process_edges_impl }}
225+ ```
226+
227+ We would also need to implement ` Deref ` and ` DerefMut ` to our ` ProcessEdgesWork ` impl to be
228+ dereferenced as ` ProcessEdgesBase ` .
229+ ``` rust
230+ {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: mygc_process_edges_deref }}
231+ ```
232+
233+ In the end, use ` MyGCProcessEdges ` as ` ProcessEdgesWorkType ` in the ` GCWorkContext ` :
234+ ``` rust
235+ {{#include .. / .. / .. / code / mygc_semispace / gc_work . rs: workcontext_mygc }}
236+ ```
237+
181238## Summary
182239
183240You should now have MyGC working and able to collect garbage. All three
0 commit comments