From bb9583bf99826600cda6be8b672453ed635aa8d6 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Wed, 26 Jul 2023 20:47:25 +0000 Subject: [PATCH] [vm, reload] Fix assertion failure when instance morphing encounters a field value that is an already morphed instance. TEST=ci Change-Id: I0d04b92fafc7ccb655e67e1fa3805d00e92a7e4b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316488 Commit-Queue: Ryan Macnak Reviewed-by: Ben Konyi --- runtime/vm/isolate_reload.cc | 6 +++-- runtime/vm/isolate_reload_test.cc | 41 +++++++++++++++++++++++++++++++ runtime/vm/object.h | 3 +++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc index bc24d502701..06f47b450d0 100644 --- a/runtime/vm/isolate_reload.cc +++ b/runtime/vm/isolate_reload.cc @@ -388,8 +388,10 @@ void InstanceMorpher::CreateMorphedCopies(Become* become) { if (from.box_cid == kIllegalCid) { // Boxed to boxed field migration. ASSERT(to.box_cid == kIllegalCid); - value = before.RawGetFieldAtOffset(from.offset); - after.RawSetFieldAtOffset(to.offset, value); + // No handle: raw_value might be a ForwardingCorpse for an object + // processed earlier in instance morphing + ObjectPtr raw_value = before.RawGetFieldAtOffset(from.offset); + after.RawSetFieldAtOffset(to.offset, raw_value); } else if (to.box_cid == kIllegalCid) { // Unboxed to boxed field migration. switch (from.box_cid) { diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc index 34247f447f6..83c768f59d5 100644 --- a/runtime/vm/isolate_reload_test.cc +++ b/runtime/vm/isolate_reload_test.cc @@ -3934,6 +3934,47 @@ TEST_CASE(IsolateReload_ChangeInstanceFormat9) { EXPECT_ERROR(lib, "type parameters have changed"); } +TEST_CASE(IsolateReload_ShapeChangeMutualReference) { + const char* kScript = + "class A{\n" + " var x;\n" + " get yourself => this;\n" + "}\n" + "var retained1;\n" + "var retained2;\n" + "main() {\n" + " retained1 = new A();\n" + " retained2 = new A();\n" + " retained1.x = retained2;\n" + " retained2.x = retained1;\n" + " return '${identical(retained1.x.yourself, retained2)}'\n" + " '${identical(retained2.x.yourself, retained1)}';\n" + "}\n"; + + Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr); + EXPECT_VALID(lib); + EXPECT_STREQ("truetrue", SimpleInvokeStr(lib, "main")); + + const char* kReloadScript = + "class A{\n" + " var x;\n" + " var y;\n" + " var z;\n" + " var w;\n" + " get yourself => this;\n" + "}\n" + "var retained1;\n" + "var retained2;\n" + "main() {\n" + " return '${identical(retained1.x.yourself, retained2)}'\n" + " '${identical(retained2.x.yourself, retained1)}';\n" + "}\n"; + + lib = TestCase::ReloadTestScript(kReloadScript); + EXPECT_VALID(lib); + EXPECT_STREQ("truetrue", SimpleInvokeStr(lib, "main")); +} + TEST_CASE(IsolateReload_ShapeChangeRetainsHash) { const char* kScript = "class A{\n" diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 3f45370c829..3eb505de0a3 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -8294,6 +8294,9 @@ class Instance : public Object { void RawSetFieldAtOffset(intptr_t offset, const Object& value) const { StoreCompressedPointer(RawFieldAddrAtOffset(offset), value.ptr()); } + void RawSetFieldAtOffset(intptr_t offset, ObjectPtr value) const { + StoreCompressedPointer(RawFieldAddrAtOffset(offset), value); + } template T* RawUnboxedFieldAddrAtOffset(intptr_t offset) const {