Skip to content

Commit

Permalink
[vm/concurrency] Add missing WeakProperty support to transitive copy
Browse files Browse the repository at this point in the history
The transitive copy algorithm was missing support for [WeakProperty]s,
thereby ensuring that we only copy the values if the keys are reachable.

Furthermore we might need to re-hash [Expando]s - since the copied
objects start with no identity hash codes.

The CL also makes us avoid calling to Dart for each [Expando]
separately and instead use a list - just as we do in the re-hashing of
maps/sets.

We also move the C++ code to invoke rehashing logic into
DartLibraryCalls::*.

Issue #36097

TEST=vm/dart{,_2}/isolates/fast_object_copy{,2}_test

Change-Id: I836745feef8a6d7573faa94e29a19c1eca0c39f2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/209106
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
  • Loading branch information
mkustermann authored and commit-bot@chromium.org committed Aug 9, 2021
1 parent 122cd0c commit d7c0271
Show file tree
Hide file tree
Showing 15 changed files with 445 additions and 118 deletions.
8 changes: 6 additions & 2 deletions runtime/lib/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,12 @@ DEFINE_NATIVE_ENTRY(SendPortImpl_sendAndExitInternal_, 0, 2) {
Object& validated_result = Object::Handle(zone);
const Object& msg_obj = Object::Handle(zone, obj.ptr());
validated_result = ValidateMessageObject(zone, isolate, msg_obj);
// msg_array = [<message>, <object-in-message-to-rehash>]
const Array& msg_array = Array::Handle(zone, Array::New(2));
// msg_array = [
// <message>,
// <collection-lib-objects-to-rehash>,
// <core-lib-objects-to-rehash>,
// ]
const Array& msg_array = Array::Handle(zone, Array::New(3));
msg_array.SetAt(0, msg_obj);
if (validated_result.IsUnhandledException()) {
Exceptions::PropagateError(Error::Cast(validated_result));
Expand Down
67 changes: 66 additions & 1 deletion runtime/tests/vm/dart/isolates/fast_object_copy_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// VMOptions=
// VMOptions=--no-enable-isolate-groups
// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy
// VMOptions=--enable-isolate-groups --enable-fast-object-copy
// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer
Expand Down Expand Up @@ -219,6 +219,8 @@ class SendReceiveTest extends SendReceiveTestBase {

await testFastOnly();
await testSlowOnly();

await testWeakProperty();
}

Future testTransferrable() async {
Expand Down Expand Up @@ -579,6 +581,69 @@ class SendReceiveTest extends SendReceiveTestBase {
await sendReceive([notAllocatableInTLAB, smallContainer]));
}
}

Future testWeakProperty() async {
final key = Object();
final expando1 = Expando();
final expando2 = Expando();
final expando3 = Expando();
final expando4 = Expando();
expando1[key] = expando2;
expando2[expando2] = expando3;
expando3[expando3] = expando4;
expando4[expando4] = {'foo': 'bar'};

{
final result = await sendReceive([
key,
expando1,
]);
final keyCopy = result[0];
final expando1Copy = result[1] as Expando;
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
{
final result = await sendReceive([
expando1,
key,
]);
final expando1Copy = result[0] as Expando;
final keyCopy = result[1];
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
{
final result = await sendReceive([
expando1,
notAllocatableInTLAB,
key,
]);
final expando1Copy = result[0] as Expando;
final keyCopy = result[2];
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
{
final result = await sendReceive([
key,
notAllocatableInTLAB,
expando1,
]);
final keyCopy = result[0];
final expando1Copy = result[2] as Expando;
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
}
}

main() async {
Expand Down
67 changes: 66 additions & 1 deletion runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

// @dart = 2.9

// VMOptions=
// VMOptions=--no-enable-isolate-groups
// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy
// VMOptions=--enable-isolate-groups --enable-fast-object-copy
// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation --verify-store-buffer
Expand Down Expand Up @@ -221,6 +221,8 @@ class SendReceiveTest extends SendReceiveTestBase {

await testFastOnly();
await testSlowOnly();

await testWeakProperty();
}

Future testTransferrable() async {
Expand Down Expand Up @@ -581,6 +583,69 @@ class SendReceiveTest extends SendReceiveTestBase {
await sendReceive([notAllocatableInTLAB, smallContainer]));
}
}

Future testWeakProperty() async {
final key = Object();
final expando1 = Expando();
final expando2 = Expando();
final expando3 = Expando();
final expando4 = Expando();
expando1[key] = expando2;
expando2[expando2] = expando3;
expando3[expando3] = expando4;
expando4[expando4] = {'foo': 'bar'};

{
final result = await sendReceive([
key,
expando1,
]);
final keyCopy = result[0];
final expando1Copy = result[1] as Expando;
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
{
final result = await sendReceive([
expando1,
key,
]);
final expando1Copy = result[0] as Expando;
final keyCopy = result[1];
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
{
final result = await sendReceive([
expando1,
notAllocatableInTLAB,
key,
]);
final expando1Copy = result[0] as Expando;
final keyCopy = result[2];
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
{
final result = await sendReceive([
key,
notAllocatableInTLAB,
expando1,
]);
final keyCopy = result[0];
final expando1Copy = result[2] as Expando;
final expando2Copy = expando1Copy[keyCopy] as Expando;
final expando3Copy = expando2Copy[expando2Copy] as Expando;
final expando4Copy = expando3Copy[expando3Copy] as Expando;
Expect.equals('bar', (expando4Copy[expando4Copy] as Map)['foo']);
}
}
}

main() async {
Expand Down
34 changes: 23 additions & 11 deletions runtime/vm/dart_entry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -786,24 +786,36 @@ ObjectPtr DartLibraryCalls::EnsureScheduleImmediate() {
return result.ptr();
}

ObjectPtr DartLibraryCalls::RehashObjects(
Thread* thread,
const Object& array_or_growable_array) {
static ObjectPtr RehashObjects(Zone* zone,
const Library& library,
const Object& array_or_growable_array) {
ASSERT(array_or_growable_array.IsArray() ||
array_or_growable_array.IsGrowableObjectArray());

auto zone = thread->zone();
const Library& collections_lib =
Library::Handle(zone, Library::CollectionLibrary());
const Function& rehashing_function = Function::Handle(
zone,
collections_lib.LookupFunctionAllowPrivate(Symbols::_rehashObjects()));
const auto& rehashing_function = Function::Handle(
zone, library.LookupFunctionAllowPrivate(Symbols::_rehashObjects()));
ASSERT(!rehashing_function.IsNull());

const Array& arguments = Array::Handle(zone, Array::New(1));
const auto& arguments = Array::Handle(zone, Array::New(1));
arguments.SetAt(0, array_or_growable_array);

return DartEntry::InvokeFunction(rehashing_function, arguments);
}

ObjectPtr DartLibraryCalls::RehashObjectsInDartCollection(
Thread* thread,
const Object& array_or_growable_array) {
auto zone = thread->zone();
const auto& collections_lib =
Library::Handle(zone, Library::CollectionLibrary());
return RehashObjects(zone, collections_lib, array_or_growable_array);
}

ObjectPtr DartLibraryCalls::RehashObjectsInDartCore(
Thread* thread,
const Object& array_or_growable_array) {
auto zone = thread->zone();
const auto& core_lib = Library::Handle(zone, Library::CoreLibrary());
return RehashObjects(zone, core_lib, array_or_growable_array);
}

} // namespace dart
12 changes: 9 additions & 3 deletions runtime/vm/dart_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,15 @@ class DartLibraryCalls : public AllStatic {
// Returns null on success, an ErrorPtr on failure.
static ObjectPtr EnsureScheduleImmediate();

// Runs the `_rehashObjects()` function.
static ObjectPtr RehashObjects(Thread* thread,
const Object& array_or_growable_array);
// Runs the `_rehashObjects()` function in `dart:collection`.
static ObjectPtr RehashObjectsInDartCollection(
Thread* thread,
const Object& array_or_growable_array);

// Runs the `_rehashObjects()` function in `dart:core`.
static ObjectPtr RehashObjectsInDartCore(
Thread* thread,
const Object& array_or_growable_array);
};

} // namespace dart
Expand Down
21 changes: 18 additions & 3 deletions runtime/vm/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1329,14 +1329,29 @@ MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
// Parse the message.
Object& msg_obj = Object::Handle(zone);
if (message->IsPersistentHandle()) {
// msg_array = [<message>, <object-in-message-to-rehash>]
// msg_array = [
// <message>,
// <collection-lib-objects-to-rehash>,
// <core-lib-objects-to-rehash>,
// ]
const auto& msg_array = Array::Handle(
zone, Array::RawCast(message->persistent_handle()->ptr()));
ASSERT(msg_array.Length() == 3);
msg_obj = msg_array.At(0);
if (msg_array.At(1) != Object::null()) {
const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(1));
const auto& result = Object::Handle(
zone, DartLibraryCalls::RehashObjects(thread, objects_to_rehash));
auto& result = Object::Handle(zone);
result = DartLibraryCalls::RehashObjectsInDartCollection(
thread, objects_to_rehash);
if (result.ptr() != Object::null()) {
msg_obj = result.ptr();
}
}
if (msg_array.At(2) != Object::null()) {
const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(2));
auto& result = Object::Handle(zone);
result =
DartLibraryCalls::RehashObjectsInDartCore(thread, objects_to_rehash);
if (result.ptr() != Object::null()) {
msg_obj = result.ptr();
}
Expand Down
18 changes: 7 additions & 11 deletions runtime/vm/message_snapshot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ ObjectPtr MessageDeserializationCluster::PostLoadLinkedHash(
Array& maps = Array::Handle(d->zone(), d->refs());
maps = maps.Slice(start_index_, stop_index_ - start_index_,
/*with_type_argument=*/false);
return DartLibraryCalls::RehashObjects(d->thread(), maps);
return DartLibraryCalls::RehashObjectsInDartCollection(d->thread(), maps);
}

class ClassMessageSerializationCluster : public MessageSerializationCluster {
Expand Down Expand Up @@ -916,18 +916,14 @@ class InstanceMessageDeserializationCluster
}

if (cls_.ptr() == d->isolate_group()->object_store()->expando_class()) {
Instance& instance = Instance::Handle(d->zone());
const String& selector = Library::PrivateCoreLibName(Symbols::_rehash());
Array& args = Array::Handle(d->zone(), Array::New(1));
for (intptr_t i = start_index_; i < stop_index_; i++) {
const auto& expandos =
Array::Handle(d->zone(), Array::New(stop_index_ - start_index_));
auto& instance = Instance::Handle(d->zone());
for (intptr_t i = start_index_, j = 0; i < stop_index_; i++, j++) {
instance ^= d->Ref(i);
args.SetAt(0, instance);
ObjectPtr error = instance.Invoke(selector, args, Object::empty_array(),
false, false);
if (error != Object::null()) {
return error;
}
expandos.SetAt(j, instance);
}
return DartLibraryCalls::RehashObjectsInDartCore(d->thread(), expandos);
}
return nullptr;
}
Expand Down
Loading

0 comments on commit d7c0271

Please sign in to comment.