[vm, reload] Use a more stable hash code for implicit closure functions.
The old hash code used the absolute token position, which made the hash code of a closure change for any insertions or deletions above it in the same file. TEST=vm/cc/IsolateReload_ClosureHashStablity Bug: https://github.com/flutter/flutter/issues/153536 Change-Id: I75da3f0cdca1862637179467ec23cf20b9878d8d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387602 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
Commit Queue
parent
ef56c81d1c
commit
c7f9914497
@@ -6815,6 +6815,74 @@ abstract class A5 { }
|
||||
check_class_hierarchy_state();
|
||||
}
|
||||
|
||||
// https://github.com/flutter/flutter/issues/153536
|
||||
TEST_CASE(IsolateReload_ClosureHashStablity) {
|
||||
const char* kScript =
|
||||
"var retained;\n"
|
||||
"var retainedHashes;\n"
|
||||
"static1() {} \n"
|
||||
"static2<T>() {} \n"
|
||||
"static3<T extends num>() {} \n"
|
||||
"class Foo {\n"
|
||||
" method1() {}\n"
|
||||
" method2<T>() {}\n"
|
||||
" method3<T extends num>() {}\n"
|
||||
"}\n"
|
||||
"extension Ext on Foo {\n"
|
||||
" extensionMethod1() {}\n"
|
||||
" extensionMethod2<T>() {}\n"
|
||||
" extensionMethod3<T extends num>() {}\n"
|
||||
"}\n"
|
||||
"main() {\n"
|
||||
" local1() {}\n"
|
||||
" local2<T>() {}\n"
|
||||
" local3<T extends num>() {}\n"
|
||||
" var f = new Foo();\n"
|
||||
" retained = [ static1, static2<String>, static3,\n"
|
||||
" f.method1, f.method2<String>, f.method3,\n"
|
||||
" f.extensionMethod1, f.extensionMethod2<String>,\n"
|
||||
" f.extensionMethod3,\n"
|
||||
" local1, local2<String>, local3 ];\n"
|
||||
" retainedHashes = retained.map((c) => c.hashCode).toList();\n"
|
||||
" return 'Setup';\n"
|
||||
"}\n";
|
||||
|
||||
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
|
||||
EXPECT_VALID(lib);
|
||||
EXPECT_VALID(Dart_FinalizeAllClasses());
|
||||
EXPECT_STREQ("Setup", SimpleInvokeStr(lib, "main"));
|
||||
|
||||
const char* kReloadScript =
|
||||
"extraFunctionShiftingDownAllTokenPositions() {}\n"
|
||||
"var retained;\n"
|
||||
"var retainedHashes;\n"
|
||||
"static1() {} \n"
|
||||
"static2<T>() {} \n"
|
||||
"static3<T extends num>() {} \n"
|
||||
"class Foo {\n"
|
||||
" method1() {}\n"
|
||||
" method2<T>() {}\n"
|
||||
" method3<T extends num>() {}\n"
|
||||
"}\n"
|
||||
"extension Ext on Foo {\n"
|
||||
" extensionMethod1() {}\n"
|
||||
" extensionMethod2<T>() {}\n"
|
||||
" extensionMethod3<T extends num>() {}\n"
|
||||
"}\n"
|
||||
"main() {\n"
|
||||
" for (var i = 0; i < retained.length; i++) {\n"
|
||||
" if (retained[i].hashCode != retainedHashes[i]){\n"
|
||||
" return 'Changed: ${retained[i]}';\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" return 'Okay';\n"
|
||||
"}\n";
|
||||
|
||||
lib = TestCase::ReloadTestScript(kReloadScript);
|
||||
EXPECT_VALID(lib);
|
||||
EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
|
||||
}
|
||||
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -8067,12 +8067,12 @@ void PatchClass::set_script(const Script& value) const {
|
||||
}
|
||||
|
||||
uword Function::Hash() const {
|
||||
uword hash = String::HashRawSymbol(name());
|
||||
if (IsClosureFunction()) {
|
||||
hash = hash ^ token_pos().Hash();
|
||||
uint32_t hash = String::HashRawSymbol(name());
|
||||
if (IsNonImplicitClosureFunction()) {
|
||||
hash = CombineHashes(hash, token_pos().Hash());
|
||||
}
|
||||
if (Owner()->IsClass()) {
|
||||
hash = hash ^ Class::Hash(Class::RawCast(Owner()));
|
||||
hash = CombineHashes(hash, Class::Hash(Class::RawCast(Owner())));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user