-
Notifications
You must be signed in to change notification settings - Fork 69
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
Two step space creation #1004
base: master
Are you sure you want to change the base?
Two step space creation #1004
Conversation
Since we compute the range of all spaces before creating them, we know the start of the FreeListPageResource when they are created.
Now it seems working.
Should we rename
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR illustrates that we can remove Map32::shared_fl_map
by introducing an explicit two-spec space creation. I think it is a good idea. However, implementation-wise, the PR is too complex at the moment.
I suggest we keep using the name VMRequest
. I see in the PR, that some enum variants need to be renamed. But I don't see a good reason we should rename the enum, and the new name does not seem to be clearer. I think we can just keep the name, and it will be helpful when we need to cross reference Rust and Java MMTk.
The concepts of asynchronous programming (future/promise/resolution) does not really applicable to our context in my opion, and the implementation is too complex. We can just ask each plan to provide a list of VMRequests
when we create HeapMeta
. HeapMeta
resolves the VMRequest
s when it is created, and store it in HeapMeta
. Then we pass HeapMeta
to new()
for each plan in the same way as it is now, and the plan can get the corresponding SpaceMeta
and use that to create the spaces. Concretely, we could also ask for a HashMap<&str, VMRequest>
(&str
is the space name), and provide fn get_space_meta(name: &str) -> SpaceMeta
on HeapMeta
.
We can rename What |
Yes. After a second thought, I think we should keep the name
I designed it this way so that the But if we use
If the idea of future/promise makes it hard to understand, we can rename |
We can achieve the same goal with a hash map. We can make sure that a space meta can be fetched exactly once (we remove an entry from the result hashmap once fetched), and after plan creation, the result hashmap should be empty (retrieving space meta matches VM requests). Fetching a wrong space meta will panic.
These are the two main reasons why I suggested providing a list of VMRequests: 1. It is structurally and logically simplerThis is what the current code does. The plan needs to make sure the ordering is correct for creating VMRequests, letting the parent plan to create VMRequests, and then resolving its own space creation. Plan: VMRequest1
ParentPlan: VMRequest2
ParentParentPlan: VMRequest3
ParentParentPlan: SpaceMeta3
ParentPlan: SpaceMeta2
Plan: SpaceMeta1 What I propose. All the requests are known beforehand, and are resolved. During plan creation, each plan just needs to get the space meta for their own spaces. MMTK: [VMRequest1, VMRequest2, VMReqest3]
HeapMeta: [SpaceMeta1, SpaceMeta2, SpaceMeta3]
Plan: Fetch SpaceMeta1
ParentPlan: Fetch SpaceMeta2
ParentParentPlan: Fetch SpaceMeta3 2. It matches the design of "plan as configuration"We have a general goal of being able to provide a configuration file for plans. We currently ask the plan for a configuration of allocators, allocation/copy semantics mapping, etc. Asking the plan to provide a configuration of VMRequests fits the design. I am happy to discuss further on the issue. |
It is still run-time checking instead of compile-time checking.
That mitigated the problem, but I still believe that compile-time checking (with the help of ownership and move checker) is a better solution because it prevents those things from happening completely.
I don't like the approach of making all There is one alternative that I actually considered. Letting each concrete plan implement a function that returns a vec (or map) of space-vmrequest pairs. impl SemiSpace {
pub fn specify_spaces() -> Vec<(&'static str, VMRequest)> {
let mut result = vec![("copyspace0", VMRequest::Unconstrainted), ("copyspace1", VMRequest::Unconstrainted)];
result.append(CommonSpace::specify_spaces());
result
}
} But I didn't adopt that approach in favour for the approach I used in this PR, mainly due to the ability to check statically.
Yes. I agree. Ideally, spaces should be specified declaratively and MMTk should be able to instantiate them in the right order, i.e. knowing their locations and contiguousness before instantiating spaces. Maybe it is possible to make some kind of DSL (maybe using macros) and hide some of the details to the implementation. I'll try making another version of this PR later to try some alternative approaches, e.g. HashMap and macros. |
This looks interesting. However, I would like to flag this for deep discussion before we go any further with it. The ideas at heart of this issue are foundational ones. Experience with ProcessEdgesWork suggests that well-intentioned refactoring can have profound impacts on usability which undermine the most key elements of the MMTk design. My suggestion is that we do not make any such change until:
We now have a situation where the code has become so complex that this is not possible, even for highly experienced team members. The design ethos of MMTk was to allow inexperienced people to come and rapidly explore GC designs. It is extremely important that we don't erode this principle. |
We let plans specify the requirement of all spaces, and then compute the start and extent of all spaces at the same time. By doing this, when a space (including discontiguous spaces) is created, we know its start and extent, and will no longer need to mutate the space later. This removes the global vec of unsafe mutable references to
FreeListPageResource
inMap32
.Concretely, the changes include:
VMRequest
into two structures,VMRequest
andVMResponse
.VMRequest
specifies the requirements, like the oldVMRequest
, butDiscontiguous
is changed toUnrestricted
. The plan no longer requests a "discontiguous" space which will later be changed to "contiguous" on 64-bit machines.VMResponse
represents the placement decision (contiguousness, start and extent). If theVMRequest
is "Unrestricted", theVMResponse
may be contiguous or discontiguous.HeapMeta
type determines the contiguousness and address range of each space.shared_fl_map: Vec<Option<NonNull<CommonFreeListPageResource>>>
field inMap32
is removed. That global map was used to record allFreeListPageResource
instances in order to fix their start addresses after the start address of the discontiguous range is computed after spaces are created. Since we now know the discontiguous range before creating any space, we no longer need that vec.Related issues and PRs
This PR is part of the greater goal of removing unsafe operations related to page resources and
VMMap
, described in #853:An older PR #953 also removes the unsafe
Map32::shared_fl_map
, but it does so by letting plans provide a methodfor_each_space_mut
to mutate spaces after creation. It doesn't fix the root of the problem because it still mutates spaces after creation.Things not fixed in this PR
Map64
holds global mutable references toFreeListPageResource
and mutate their start addresses, too, but for a completely different reason (see #853). But since fixing this problem will require non-trivial changes, too, I'll postpone that to another PR, possibly a shrunk version of #953 that focuses onMap64
alone.This PR does not remove the
UnsafeCell<Map32Inner>
inMap32
. It will be removed later.