Skip to content

Commit cfac481

Browse files
committed
1. Figure out the modified libraries from the specifeid kernel file during
reload instead of computing it based on the source modification information. 2. Fix for failure in Unit test case #30322 3. Fix crash in test that was being skipped in #30109 and turn that test on. This CL is work towards completing issue #28051 [email protected] Review-Url: https://codereview.chromium.org/2998983002 .
1 parent 60a7160 commit cfac481

File tree

10 files changed

+147
-48
lines changed

10 files changed

+147
-48
lines changed

pkg/front_end/test/src/incremental/hot_reload_e2e_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ main() {
136136
await hotReload();
137137
await programIsDone;
138138
expect(await lines[2], "part1 part4");
139-
}, skip: true /* VM crashes on reload */);
139+
});
140140

141141
test('reload after whole program modification', () async {
142142
await startProgram(1);

runtime/bin/dfe.cc

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ void DFE::SetKernelBinaries(const char* name) {
5252
File::PathSeparator(), kVMServiceIOBinaryName);
5353
}
5454

55-
Dart_Handle DFE::ReloadScript(Dart_Isolate isolate, const char* url_string) {
55+
Dart_Handle DFE::ReadKernelBinary(Dart_Isolate isolate,
56+
const char* url_string) {
5657
ASSERT(!Dart_IsServiceIsolate(isolate) && !Dart_IsKernelIsolate(isolate));
5758
// First check if the URL points to a Kernel IR file in which case we
5859
// skip the compilation step and directly reload the file.
@@ -75,17 +76,7 @@ Dart_Handle DFE::ReloadScript(Dart_Isolate isolate, const char* url_string) {
7576
}
7677
void* kernel_program = Dart_ReadKernelBinary(kernel_ir, kernel_ir_size);
7778
ASSERT(kernel_program != NULL);
78-
Dart_Handle result = Dart_LoadKernel(kernel_program);
79-
if (Dart_IsError(result)) {
80-
return result;
81-
}
82-
// Finalize loading. This will complete any futures for completed deferred
83-
// loads.
84-
result = Dart_FinalizeLoading(true);
85-
if (Dart_IsError(result)) {
86-
return result;
87-
}
88-
return Dart_Null();
79+
return Dart_NewExternalTypedData(Dart_TypedData_kUint64, kernel_program, 1);
8980
}
9081

9182
void* DFE::CompileAndReadScript(const char* script_uri,

runtime/bin/dfe.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ class DFE {
3838
bool kernel_file_specified() const { return kernel_file_specified_; }
3939
void set_kernel_file_specified(bool value) { kernel_file_specified_ = value; }
4040

41-
// Method to reload a script into a running a isolate.
41+
// Method to read a kernel file into a kernel program blob.
4242
// If the specified script [url] is not a kernel IR, compile it first using
43-
// DFE and then reload the resulting kernel IR into the isolate.
43+
// DFE and then read the resulting kernel file into a kernel program blob.
4444
// Returns Dart_Null if successful, otherwise an error object is returned.
45-
Dart_Handle ReloadScript(Dart_Isolate isolate, const char* url_string);
45+
Dart_Handle ReadKernelBinary(Dart_Isolate isolate, const char* url_string);
4646

4747
// Compiles a script and reads the resulting kernel file.
4848
// If the compilation is successful, returns a valid in memory kernel

runtime/bin/loader.cc

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -673,20 +673,14 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
673673
if (Dart_IsError(result)) {
674674
return result;
675675
}
676-
if (tag == Dart_kScriptTag) {
677-
if (dfe.UseDartFrontend() || dfe.kernel_file_specified()) {
678-
Dart_Isolate current = Dart_CurrentIsolate();
679-
// Check if we are trying to reload a kernel file or if the '--dfe'
680-
// option was specified and we need to compile sources using DFE.
681-
if (!Dart_IsServiceIsolate(current) && !Dart_IsKernelIsolate(current)) {
682-
// When using DFE the library tag handler should be called only when
683-
// we are reloading scripts.
684-
return dfe.ReloadScript(current, url_string);
685-
}
686-
}
687-
// TODO(asiva) We need to ensure that the kernel and service isolates
688-
// are always loaded from a kernel IR and do not use this path.
689-
} else {
676+
if (tag == Dart_kKernelTag) {
677+
ASSERT(dfe.UseDartFrontend() || dfe.kernel_file_specified());
678+
Dart_Isolate current = Dart_CurrentIsolate();
679+
ASSERT(!Dart_IsServiceIsolate(current) && !Dart_IsKernelIsolate(current));
680+
return dfe.ReadKernelBinary(current, url_string);
681+
}
682+
ASSERT(!dfe.UseDartFrontend() && !dfe.kernel_file_specified());
683+
if (tag != Dart_kScriptTag) {
690684
// Special case for handling dart: imports and parts.
691685
// Grab the library's url.
692686
Dart_Handle library_url = Dart_LibraryUrl(library);
@@ -707,7 +701,6 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
707701
url_string);
708702
}
709703
}
710-
711704
if (DartUtils::IsDartExtensionSchemeURL(url_string)) {
712705
// Handle early error cases for dart-ext: imports.
713706
if (tag != Dart_kImportTag) {

runtime/include/dart_api.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,6 +2686,7 @@ typedef enum {
26862686
Dart_kScriptTag,
26872687
Dart_kSourceTag,
26882688
Dart_kImportTag,
2689+
Dart_kKernelTag,
26892690
} Dart_LibraryTag;
26902691

26912692
/**
@@ -2725,6 +2726,15 @@ typedef enum {
27252726
* "import" directive. Once the script is loaded, the embedder should
27262727
* call Dart_LoadLibrary to provide the script source to the VM. The
27272728
* return value should be an error or null.
2729+
*
2730+
* Dart_kKernelTag
2731+
*
2732+
* This tag is used to load the intermediate file (kernel) generated by
2733+
* the Dart front end. This tag is typically used when a 'hot-reload'
2734+
* of an application is needed and the VM is 'use dart front end' mode.
2735+
* The dart front end typically compiles all the scripts, imports and part
2736+
* files into one intermediate file hence we don't use the source/import or
2737+
* script tags.
27282738
*/
27292739
typedef Dart_Handle (*Dart_LibraryTagHandler)(
27302740
Dart_LibraryTag tag,

runtime/tests/vm/vm.status

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,6 @@ cc/IsolateReload_EnumToNotEnum: Skip
327327
cc/IsolateReload_ExportedLibModified: Crash
328328
cc/IsolateReload_ImportedLibModified: Crash
329329
cc/IsolateReload_ImportedMixinFunction: Crash
330-
cc/IsolateReload_KernelIncrementalCompileGenerics: Crash # Issue 30322
331330
cc/IsolateReload_LibraryHide: Crash
332331
cc/IsolateReload_LibraryLookup: Fail
333332
cc/IsolateReload_LibraryShow: Crash

runtime/vm/isolate_reload.cc

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "vm/dart_api_impl.h"
1111
#include "vm/hash_table.h"
1212
#include "vm/isolate.h"
13+
#include "vm/kernel_reader.h"
1314
#include "vm/log.h"
1415
#include "vm/object.h"
1516
#include "vm/object_store.h"
@@ -485,6 +486,7 @@ class Aborted : public ReasonForCancelling {
485486
}
486487
};
487488

489+
#if !defined(DART_PRECOMPILED_RUNTIME)
488490
static intptr_t CommonSuffixLength(const char* a, const char* b) {
489491
const intptr_t a_length = strlen(a);
490492
const intptr_t b_length = strlen(b);
@@ -533,8 +535,57 @@ void IsolateReloadContext::Reload(bool force_reload,
533535
old_root_lib_url.Length() - common_suffix_length + 1);
534536
}
535537

536-
// Check to see which libraries have been modified.
537-
modified_libs_ = FindModifiedLibraries(force_reload);
538+
Object& result = Object::Handle(thread->zone());
539+
kernel::Program* kernel_program = NULL;
540+
String& packages_url = String::Handle();
541+
if (packages_url_ != NULL) {
542+
packages_url = String::New(packages_url_);
543+
}
544+
if (isolate()->use_dart_frontend()) {
545+
// Load the kernel program and figure out the modified libraries.
546+
const GrowableObjectArray& libs =
547+
GrowableObjectArray::Handle(object_store()->libraries());
548+
intptr_t num_libs = libs.Length();
549+
modified_libs_ = new (Z) BitVector(Z, num_libs);
550+
TIR_Print("---- ENTERING TAG HANDLER\n");
551+
{
552+
TransitionVMToNative transition(thread);
553+
Api::Scope api_scope(thread);
554+
Dart_Handle retval = (I->library_tag_handler())(
555+
Dart_kKernelTag, Api::NewHandle(thread, packages_url.raw()),
556+
Api::NewHandle(thread, root_lib_url.raw()));
557+
if (Dart_IsError(retval)) {
558+
// Compilation of the new sources failed, abort reload and report
559+
// error.
560+
result = Api::UnwrapHandle(retval);
561+
} else {
562+
uint64_t data;
563+
intptr_t data_len = 0;
564+
Dart_TypedData_Type data_type;
565+
ASSERT(Dart_IsTypedData(retval));
566+
Dart_Handle val = Dart_TypedDataAcquireData(
567+
retval, &data_type, reinterpret_cast<void**>(&data), &data_len);
568+
ASSERT(!Dart_IsError(val));
569+
ASSERT(data_type == Dart_TypedData_kUint64);
570+
ASSERT(data_len == 1);
571+
kernel_program = reinterpret_cast<kernel::Program*>(data);
572+
Dart_TypedDataReleaseData(retval);
573+
kernel::KernelReader reader(kernel_program);
574+
reader.FindModifiedLibraries(I, modified_libs_, force_reload);
575+
}
576+
}
577+
if (result.IsError()) {
578+
TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
579+
AddReasonForCancelling(new Aborted(zone_, ApiError::Cast(result)));
580+
ReportReasonsForCancelling();
581+
CommonFinalizeTail();
582+
return;
583+
}
584+
TIR_Print("---- EXITED TAG HANDLER\n");
585+
} else {
586+
// Check to see which libraries have been modified.
587+
modified_libs_ = FindModifiedLibraries(force_reload);
588+
}
538589
if (!modified_libs_->Contains(old_root_lib.index())) {
539590
ASSERT(modified_libs_->IsEmpty());
540591
reload_skipped_ = true;
@@ -589,26 +640,33 @@ void IsolateReloadContext::Reload(bool force_reload,
589640
// returned by the tag handler. The tag handler can return other errors,
590641
// for example, top level parse errors. We want to capture these errors while
591642
// propagating the UnwindError or an UnhandledException error.
592-
Object& result = Object::Handle(thread->zone());
593643

594-
String& packages_url = String::Handle();
595-
if (packages_url_ != NULL) {
596-
packages_url = String::New(packages_url_);
597-
}
598-
599-
TIR_Print("---- ENTERING TAG HANDLER\n");
600-
{
644+
if (isolate()->use_dart_frontend()) {
645+
// Read the kernel program.
646+
kernel::KernelReader reader(kernel_program);
647+
const Object& tmp = reader.ReadProgram();
648+
if (!tmp.IsError()) {
649+
Library& lib = Library::Handle(thread->zone());
650+
lib ^= tmp.raw();
651+
isolate()->object_store()->set_root_library(lib);
652+
FinalizeLoading();
653+
result = Object::null();
654+
} else {
655+
result = tmp.raw();
656+
}
657+
} else {
658+
TIR_Print("---- ENTERING TAG HANDLER\n");
601659
TransitionVMToNative transition(thread);
602660
Api::Scope api_scope(thread);
603661

604662
Dart_Handle retval = (I->library_tag_handler())(
605663
Dart_kScriptTag, Api::NewHandle(thread, packages_url.raw()),
606664
Api::NewHandle(thread, root_lib_url.raw()));
607665
result = Api::UnwrapHandle(retval);
666+
TIR_Print("---- EXITED TAG HANDLER\n");
608667
}
609668
//
610669
// WEIRD CONTROL FLOW ENDS.
611-
TIR_Print("---- EXITED TAG HANDLER\n");
612670

613671
// Re-enable the background compiler. Do this before propagating any errors.
614672
BackgroundCompiler::Enable();
@@ -633,6 +691,12 @@ void IsolateReloadContext::Reload(bool force_reload,
633691
FinalizeFailedLoad(Error::Cast(result));
634692
}
635693
}
694+
#else
695+
// NOTE: This function returns *after* FinalizeLoading is called.
696+
void IsolateReloadContext::Reload(bool force_reload,
697+
const char* root_script_url,
698+
const char* packages_url_) {}
699+
#endif // !defined(DART_PRECOMPILED_RUNTIME)
636700

637701
void IsolateReloadContext::RegisterClass(const Class& new_cls) {
638702
const Class& old_cls = Class::Handle(OldClassOrNull(new_cls));
@@ -663,10 +727,9 @@ void IsolateReloadContext::RegisterClass(const Class& new_cls) {
663727
// FinalizeLoading will be called *before* Reload() returns but will not be
664728
// called if the embedder fails to load sources.
665729
void IsolateReloadContext::FinalizeLoading() {
666-
if (reload_skipped_) {
730+
if (reload_skipped_ || reload_finalized_) {
667731
return;
668732
}
669-
ASSERT(!reload_finalized_);
670733
BuildLibraryMapping();
671734
TIR_Print("---- LOAD SUCCEEDED\n");
672735
if (ValidateReload()) {

runtime/vm/kernel_reader.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,43 @@ Object& KernelReader::ReadProgram() {
211211
return error;
212212
}
213213

214+
void KernelReader::FindModifiedLibraries(Isolate* isolate,
215+
BitVector* modified_libs,
216+
bool force_reload) {
217+
LongJumpScope jump;
218+
if (setjmp(*jump.Set()) == 0) {
219+
if (force_reload) {
220+
// If a reload is being forced we mark all libraries as having
221+
// been modified.
222+
const GrowableObjectArray& libs =
223+
GrowableObjectArray::Handle(isolate->object_store()->libraries());
224+
intptr_t num_libs = libs.Length();
225+
Library& lib = dart::Library::Handle(Z);
226+
for (intptr_t i = 0; i < num_libs; i++) {
227+
lib ^= libs.At(i);
228+
if (!lib.is_dart_scheme()) {
229+
modified_libs->Add(lib.index());
230+
}
231+
}
232+
return;
233+
}
234+
// Now go through all the libraries that are present in the incremental
235+
// kernel files, these will constitute the modified libraries.
236+
intptr_t length = program_->library_count();
237+
for (intptr_t i = 0; i < length; i++) {
238+
intptr_t kernel_offset = library_offset(i);
239+
builder_.SetOffset(kernel_offset);
240+
LibraryHelper library_helper(&builder_);
241+
library_helper.ReadUntilIncluding(LibraryHelper::kCanonicalName);
242+
dart::Library& lib = LookupLibrary(library_helper.canonical_name_);
243+
if (!lib.IsNull() && !lib.is_dart_scheme()) {
244+
// This is a library that already exists so mark it as being modified.
245+
modified_libs->Add(lib.index());
246+
}
247+
}
248+
}
249+
}
250+
214251
void KernelReader::ReadLibrary(intptr_t kernel_offset) {
215252
builder_.SetOffset(kernel_offset);
216253
LibraryHelper library_helper(&builder_);

runtime/vm/kernel_reader.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ class KernelReader {
6060
// was no main procedure, or a failure object if there was an error.
6161
Object& ReadProgram();
6262

63+
// Finds all libraries that have been modified in this incremental
64+
// version of the kernel program file.
65+
void FindModifiedLibraries(Isolate* isolate,
66+
BitVector* modified_libs,
67+
bool force_reload);
68+
6369
void ReadLibrary(intptr_t kernel_offset);
6470

6571
const String& DartSymbol(StringIndex index) {

runtime/vm/unit_test.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
215215
if (FLAG_use_dart_frontend) {
216216
// Reload request.
217217

218+
ASSERT(tag == Dart_kKernelTag);
218219
const char* urlstr = NULL;
219220
Dart_Handle result = Dart_StringToCString(url, &urlstr);
220221
if (Dart_IsError(result)) {
@@ -238,11 +239,10 @@ static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
238239
ASSERT(kernel_reload_key != kUnsetThreadLocalKey);
239240
kernel_pgm =
240241
reinterpret_cast<void*>(OSThread::GetThreadLocal(kernel_reload_key));
241-
ASSERT(kernel_pgm != NULL);
242242
OSThread::SetThreadLocal(kernel_reload_key, 0);
243243
}
244-
return Dart_LoadScript(url, Dart_Null(),
245-
reinterpret_cast<Dart_Handle>(kernel_pgm), 0, 0);
244+
ASSERT(kernel_pgm != NULL);
245+
return Dart_NewExternalTypedData(Dart_TypedData_kUint64, kernel_pgm, 1);
246246
}
247247
if (tag == Dart_kCanonicalizeUrl) {
248248
Dart_Handle library_url = Dart_LibraryUrl(library);

0 commit comments

Comments
 (0)