-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Move semantics for SendPort #49587
Comments
Not sure how you would efficiently assert that there is only one reference to each object in the object graph. That sounds like something which needs a full GC-equivalent memory scan to ensure. (Mark the transitive closure of the unique object in one color, then mark from the roots in another color, stopping at the unique object, and see that you don't re-mark any object in both colors). That's already better than "only referenced once" because it allows the unique object graph to refer to the same object more than once, as long as there are no references from outside that graph. Also, it probably still won't work, since it means the graph cannot safely contain I think simply making "immutable objects" a concept (anything created using Trying to contain a Dart object reference, while providing access to the object, is something I very much doubt will ever work. |
I guess it depends on how the garbage collector was implemented. I was assuming it would be cheap to crawl the subsection of memory that is referenced from an object recursively and count those references per object. I never looked at the Dart GC implementation, but it's probably not the case now that I consider it. You'd probably need a doubly linked graph of objects that's readily available at any time, which we'd never have.
Yea, Martin has already talked about making these cheap for sending over SendPort, so they there is already an idea for detecting them.
I don't follow this statement. Maybe my proposal for compile-time checks for uniqueness was a better way to go. I already closed it thinking this would be easier to implement. |
As @lrhn says it is a very hard problem to maintain the Rephrasing the requirement of On top of that, sending across So we're down to sending mutable trees at this point. Do they have to be mutable? |
This would not work, because you are looking for incoming references, rather than outgoing references. You will need to crawl the whole heap to find all incoming references to objects within the subgraph referenced by the given root. It's going to be expensive. That being said, I think there is a trick that might work here. If you know that you are creating objects for transfer, you could tell VM to allocate them all in a separate part of the heap and you use write-barrier to track when references to that part of the heap escape, i.e. // o.f = v
def WriteBarrier(object, field, value):
if pageOf(object).id != pageOf(value).id
pageOf(value).selfContained = false
if !value.isCanonical:
pageOf(object).selfContained = false Now when you are transfering an def transfer(port, object):
# Check if there is potential escape through thread stack or globals
# Caveat: ignores current frame (object variable).
iterateRoots(lambda o: pageOf(o).selfContained = false)
if not pageOf(object).selfContained:
raise 'Can't transfer object which potentially escaped'
# Now we know that the object graph is self-contained within
# a number of heap pages and there are no references (except object)
# to these pages. This means we can transfer the object. With this approach you would need to write the code like this: Map<String, Object> makeLargeMap(int n) {
// |allocateForTransfer| makes VM allocate all new objects in a separate page.
return allocateForTransfer(() {
Map<String, Object> result = {};
for (int i = 0; i < n; ++i) {
result[i.toString()] = i;
}
return result;
});
} Maybe something like this can work. |
Using Using a separate page with a write barrier needs to check both directions: When references to the presumed nonshared objects escape, and when an already shared (other-page) reference is written into that page. Either write loses the ability to share the page. Presumably permanently, because if you clear either of the cross-page references, you may need to do an expensive test to check that the object graph is closed again. It still means needing to share common objects, like numbers, strings, booleans and Factory constructors and object caches become a problem, when you can't predict whether a call actually performs the allocation in the current zone. Seems potentially very complicated, if at all viable. (Maybe just make |
Another probably silly idea (just for brainstorm): Can we convert objects between mutable and immutable, and ensure A typical usage:
|
This tracker is for issues related to:
Description
We should be able to transfer any object over SendPort in constant time if we know:
To make this possible I propose we add a new class called
Unique
that whenconstructedsent over aSendPort
asserts that there is one reference to each object in the object graph and nulls out its reference. That way we can have constant-time communication of any object overSendPort
s. It isn't asserted at compile time, but this might be the best we can do with Dart.The printed timestamps should almost be the same, today the difference is 12s locally:
Related language request for move semantics: dart-lang/language#2355 (this has compile time checks for uniqueness)
cc @mkustermann
Alternatives considered
The text was updated successfully, but these errors were encountered: