[reload] Rehash constants before running new initializers.

Use of constants before rehashing can result in duplicate "canonical" constants.

Change-Id: I48c008b269267461c30933002c5a5e57005dfef5
Reviewed-on: https://dart-review.googlesource.com/5282
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2017-09-12 22:00:21 +00:00 committed by commit-bot@chromium.org
parent 8f1ca007f2
commit 2d698cc4d0
3 changed files with 67 additions and 14 deletions

View file

@ -333,6 +333,7 @@ cc/IsolateReload_RunNewFieldInitializersMutateStaticField: Skip
cc/IsolateReload_RunNewFieldInitializersReferenceStaticField: Skip
cc/IsolateReload_RunNewFieldInitializersSyntaxError3: Fail
cc/IsolateReload_RunNewFieldInitializersThrows: Skip
cc/IsolateReload_RunNewFieldInitializersWithConsts: Skip
cc/IsolateReload_ShapeChangeRetainsHash: Skip
cc/IsolateReload_SmiFastPathStubs: Fail
cc/IsolateReload_TearOff_AddArguments2: Fail

View file

@ -1288,8 +1288,19 @@ void IsolateReloadContext::Commit() {
Become::ElementsForwardIdentity(before, after);
}
// Run the initializers for new instance fields.
RunNewFieldInitializers();
// Rehash constants map for all classes. Constants are hashed by address, and
// addresses may change during a become operation.
RehashConstants();
#ifdef DEBUG
// Verify that all canonical instances are correctly setup in the
// corresponding canonical tables.
Thread* thread = Thread::Current();
I->heap()->CollectAllGarbage();
HeapIterationScope iteration(thread);
VerifyCanonicalVisitor check_canonical(thread);
iteration.IterateObjects(&check_canonical);
#endif // DEBUG
if (FLAG_identity_reload) {
if (saved_num_cids_ != I->class_table()->NumCids()) {
@ -1306,18 +1317,8 @@ void IsolateReloadContext::Commit() {
}
}
// Rehash constants map for all classes.
RehashConstants();
#ifdef DEBUG
// Verify that all canonical instances are correctly setup in the
// corresponding canonical tables.
Thread* thread = Thread::Current();
I->heap()->CollectAllGarbage();
HeapIterationScope iteration(thread);
VerifyCanonicalVisitor check_canonical(thread);
iteration.IterateObjects(&check_canonical);
#endif // DEBUG
// Run the initializers for new instance fields.
RunNewFieldInitializers();
}
void IsolateReloadContext::RehashConstants() {

View file

@ -3542,6 +3542,57 @@ TEST_CASE(IsolateReload_RunNewFieldInitialiazersSuperClass) {
EXPECT_STREQ("right", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_RunNewFieldInitializersWithConsts) {
const char* kScript =
"class C {\n"
" final x;\n"
" const C(this.x);\n"
"}\n"
"var a = const C(const C(1));\n"
"var b = const C(const C(2));\n"
"var c = const C(const C(3));\n"
"var d = const C(const C(4));\n"
"class Foo {\n"
"}\n"
"Foo value;\n"
"main() {\n"
" value = new Foo();\n"
" a; b; c; d;\n"
" return 'Okay';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"class C {\n"
" final x;\n"
" const C(this.x);\n"
"}\n"
"var a = const C(const C(1));\n"
"var b = const C(const C(2));\n"
"var c = const C(const C(3));\n"
"var d = const C(const C(4));\n"
"class Foo {\n"
" var d = const C(const C(4));\n"
" var c = const C(const C(3));\n"
" var b = const C(const C(2));\n"
" var a = const C(const C(1));\n"
"}\n"
"Foo value;\n"
"main() {\n"
" return '${identical(a, value.a)} ${identical(b, value.b)}'"
" ' ${identical(c, value.c)} ${identical(d, value.d)}';\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
// Verify that we ran field initializers on existing instances and the const
// expressions were properly canonicalized.
EXPECT_STREQ("true true true true", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_TypedefToNotTypedef) {
const char* kScript =
"typedef bool Predicate(dynamic x);\n"