[vm, reload] Eagerly assign static field initializers a PatchClass owner.

Static field initializers are not added as members of their owning class, so they must be pre-emptively given a patch class to avoid the meaning of their kernel/token position changing during a reload. Member functions and fields have their owner changed to patch class only when the class is changed during a reload.

Curiously, this was originally done in the C++ front end before hot reload: https://codereview.chromium.org//1317753004

Bug: https://github.com/dart-lang/sdk/issues/32497
Change-Id: I236c188a4b9e05a1e3c011d27e123979db1ca2e5
Reviewed-on: https://dart-review.googlesource.com/46124
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
Ryan Macnak 2018-03-12 21:12:29 +00:00 committed by commit-bot@chromium.org
parent 3c8d3b6870
commit 66af0113de
2 changed files with 41 additions and 5 deletions

View file

@ -17,9 +17,6 @@ namespace dart {
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
// TODO(johnmccutchan):
// - Tests involving generics.
int64_t SimpleInvoke(Dart_Handle lib, const char* method) {
Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
EXPECT_VALID(result);
@ -3500,6 +3497,31 @@ TEST_CASE(IsolateReload_TypedefAddParameter) {
EXPECT_STREQ("false", SimpleInvokeStr(lib, "main"));
}
TEST_CASE(IsolateReload_PatchStaticInitializerWithClosure) {
const char* kScript =
"dynamic field = (a) => 'a$a';\n"
"main() {\n"
" dynamic f = field;\n"
" return f('b');\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
EXPECT_STREQ("ab", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"extraFunction() => 'Just here to change kernel offsets';\n"
"dynamic field = (_, __) => 'Not executed';\n"
"main() {\n"
" dynamic f = field;\n"
" return f('c');\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
EXPECT_STREQ("ac", SimpleInvokeStr(lib, "main"));
}
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
} // namespace dart

View file

@ -1607,8 +1607,22 @@ RawFunction* CreateFieldInitializerFunction(Thread* thread,
String& init_name = String::Handle(zone, field.name());
init_name = Symbols::FromConcat(thread, Symbols::InitPrefix(), init_name);
// Static field initializers are not added as members of their owning class,
// so they must be pre-emptively given a patch class to avoid the meaning of
// their kernel/token position changing during a reload. Compare
// Class::PatchFieldsAndFunctions().
// This might also be necessary for lazy computation of local var descriptors.
// Compare https://codereview.chromium.org//1317753004
const Script& script = Script::Handle(zone, field.Script());
const Class& field_owner = Class::Handle(zone, field.Owner());
const PatchClass& initializer_owner =
PatchClass::Handle(zone, PatchClass::New(field_owner, script));
const Library& lib = Library::Handle(zone, field_owner.library());
initializer_owner.set_library_kernel_data(
TypedData::Handle(zone, lib.kernel_data()));
initializer_owner.set_library_kernel_offset(lib.kernel_offset());
// Create a static initializer.
const Object& owner = Object::Handle(field.RawOwner());
const Function& initializer_fun = Function::Handle(
zone, Function::New(init_name,
// TODO(alexmarkov): Consider creating a separate
@ -1619,7 +1633,7 @@ RawFunction* CreateFieldInitializerFunction(Thread* thread,
false, // is_abstract
false, // is_external
false, // is_native
owner, TokenPosition::kNoSource));
initializer_owner, TokenPosition::kNoSource));
initializer_fun.set_kernel_offset(field.kernel_offset());
initializer_fun.set_result_type(AbstractType::Handle(zone, field.type()));
initializer_fun.set_is_debuggable(false);