From 28ad17bee905b1cbe915dc7d2504b327e6671549 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Tue, 18 Aug 2020 00:28:56 +0000 Subject: [PATCH] [gen_snapshot] Include library URIs in the loading unit manifest. Bug: https://github.com/dart-lang/sdk/issues/41974 Change-Id: Ifb7de4698563b5c1210d388bd3d069986fc0f541 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158725 Commit-Queue: Ryan Macnak Reviewed-by: Alexander Markov --- runtime/bin/gen_snapshot.cc | 19 +++++++- runtime/include/dart_api.h | 2 + .../dart/incompatible_loading_unit_test.dart | 30 +++++++++++- .../incompatible_loading_unit_test.dart | 30 +++++++++++- runtime/vm/dart_api_impl.cc | 47 +++++++++++++++++-- 5 files changed, 119 insertions(+), 9 deletions(-) diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc index f2d33c5ef6b..187cf925e7c 100644 --- a/runtime/bin/gen_snapshot.cc +++ b/runtime/bin/gen_snapshot.cc @@ -603,11 +603,26 @@ static void WriteLoadingUnitManifest(File* manifest_file, const char* path) { TextBuffer line(128); if (id != 1) { - line.Printf(","); + line.AddString(",\n"); } line.Printf("{ \"id\": %" Pd ", \"path\": \"", id); line.AddEscapedString(path); - line.Printf("\" }"); + line.AddString("\", \"libraries\": [\n"); + Dart_Handle uris = Dart_LoadingUnitLibraryUris(id); + CHECK_RESULT(uris); + intptr_t length; + CHECK_RESULT(Dart_ListLength(uris, &length)); + for (intptr_t i = 0; i < length; i++) { + const char* uri; + CHECK_RESULT(Dart_StringToCString(Dart_ListGetAt(uris, i), &uri)); + if (i != 0) { + line.AddString(",\n"); + } + line.AddString("\""); + line.AddEscapedString(uri); + line.AddString("\""); + } + line.AddString("]}"); if (!manifest_file->Print("%s\n", line.buffer())) { PrintErrAndExit("Error: Unable to write file: %s\n\n", loading_unit_manifest_filename); diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h index 8eebaed2ba2..d12d6c74194 100644 --- a/runtime/include/dart_api.h +++ b/runtime/include/dart_api.h @@ -3685,6 +3685,8 @@ typedef void (*Dart_StreamingWriteCallback)(void* callback_data, intptr_t size); typedef void (*Dart_StreamingCloseCallback)(void* callback_data); +DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id); + // On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name. // Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual // symbol names in the objects are given by the '...AsmSymbol' definitions. diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart index 1663e3ab4a0..5facc47e40b 100644 --- a/runtime/tests/vm/dart/incompatible_loading_unit_test.dart +++ b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart @@ -27,6 +27,25 @@ main(List args) async { throw "Cannot run test as $genSnapshot not available"; } + sanitizedPartitioning(manifest) { + // Filter core libraries, relativize URIs, and sort to make the results less + // sensitive to compiler or test harness changes. + print(manifest); + var units = >[]; + for (var unit in manifest['loadingUnits']) { + var uris = []; + for (var uri in unit['libraries']) { + if (uri.startsWith("dart:")) continue; + uris.add(Uri.file(uri).pathSegments.last); + } + uris.sort((a, b) => a.compareTo(b)); + units.add(uris); + } + units.sort((a, b) => a.first.compareTo(b.first)); + print(units); + return units; + } + await withTempDir("incompatible-loading-unit-test", (String tempDir) async { final source1 = path.join( sdkDir, "runtime/tests/vm/dart_2/incompatible_loading_unit_1.dart"); @@ -67,6 +86,11 @@ main(List args) async { ]); var manifest = jsonDecode(await new File(manifest1).readAsString()); Expect.equals(2, manifest["loadingUnits"].length); + // Note package:expect doesn't do deep equals on collections. + Expect.equals( + "[[incompatible_loading_unit_1.dart]," + " [incompatible_loading_unit_1_deferred.dart]]", + sanitizedPartitioning(manifest).toString()); Expect.isTrue(await new File(deferredSnapshot1).exists()); await run(genSnapshot, [ @@ -76,8 +100,12 @@ main(List args) async { "--loading-unit-manifest=$manifest2", dill2, ]); - manifest = jsonDecode(await new File(manifest1).readAsString()); + manifest = jsonDecode(await new File(manifest2).readAsString()); Expect.equals(2, manifest["loadingUnits"].length); + Expect.equals( + "[[incompatible_loading_unit_2.dart]," + " [incompatible_loading_unit_2_deferred.dart]]", + sanitizedPartitioning(manifest).toString()); Expect.isTrue(await new File(deferredSnapshot2).exists()); // Works when used normally. diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart index 1663e3ab4a0..5facc47e40b 100644 --- a/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart +++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart @@ -27,6 +27,25 @@ main(List args) async { throw "Cannot run test as $genSnapshot not available"; } + sanitizedPartitioning(manifest) { + // Filter core libraries, relativize URIs, and sort to make the results less + // sensitive to compiler or test harness changes. + print(manifest); + var units = >[]; + for (var unit in manifest['loadingUnits']) { + var uris = []; + for (var uri in unit['libraries']) { + if (uri.startsWith("dart:")) continue; + uris.add(Uri.file(uri).pathSegments.last); + } + uris.sort((a, b) => a.compareTo(b)); + units.add(uris); + } + units.sort((a, b) => a.first.compareTo(b.first)); + print(units); + return units; + } + await withTempDir("incompatible-loading-unit-test", (String tempDir) async { final source1 = path.join( sdkDir, "runtime/tests/vm/dart_2/incompatible_loading_unit_1.dart"); @@ -67,6 +86,11 @@ main(List args) async { ]); var manifest = jsonDecode(await new File(manifest1).readAsString()); Expect.equals(2, manifest["loadingUnits"].length); + // Note package:expect doesn't do deep equals on collections. + Expect.equals( + "[[incompatible_loading_unit_1.dart]," + " [incompatible_loading_unit_1_deferred.dart]]", + sanitizedPartitioning(manifest).toString()); Expect.isTrue(await new File(deferredSnapshot1).exists()); await run(genSnapshot, [ @@ -76,8 +100,12 @@ main(List args) async { "--loading-unit-manifest=$manifest2", dill2, ]); - manifest = jsonDecode(await new File(manifest1).readAsString()); + manifest = jsonDecode(await new File(manifest2).readAsString()); Expect.equals(2, manifest["loadingUnits"].length); + Expect.equals( + "[[incompatible_loading_unit_2.dart]," + " [incompatible_loading_unit_2_deferred.dart]]", + sanitizedPartitioning(manifest).toString()); Expect.isTrue(await new File(deferredSnapshot2).exists()); // Works when used normally. diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index a9dfc833aa7..a7882d75c2b 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -6745,14 +6745,20 @@ static void Split(Dart_CreateLoadingUnitCallback next_callback, for (intptr_t id = 1; id < loading_units.Length(); id++) { void* write_callback_data = nullptr; void* write_debug_callback_data = nullptr; - next_callback(next_callback_data, id, &write_callback_data, - &write_debug_callback_data); + { + TransitionVMToNative transition(T); + next_callback(next_callback_data, id, &write_callback_data, + &write_debug_callback_data); + } CreateAppAOTSnapshot(write_callback, write_callback_data, strip, as_elf, write_debug_callback_data, &data, data[id], program_hash); - close_callback(write_callback_data); - if (write_debug_callback_data != nullptr) { - close_callback(write_debug_callback_data); + { + TransitionVMToNative transition(T); + close_callback(write_callback_data); + if (write_debug_callback_data != nullptr) { + close_callback(write_debug_callback_data); + } } } } @@ -6899,6 +6905,37 @@ Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback, #endif } +DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id) { +#if defined(TARGET_ARCH_IA32) + return Api::NewError("AOT compilation is not supported on IA32."); +#elif !defined(DART_PRECOMPILER) + return Api::NewError( + "This VM was built without support for AOT compilation."); +#else + DARTSCOPE(Thread::Current()); + API_TIMELINE_DURATION(T); + + const GrowableObjectArray& result = + GrowableObjectArray::Handle(Z, GrowableObjectArray::New()); + const GrowableObjectArray& libs = + GrowableObjectArray::Handle(Z, T->isolate()->object_store()->libraries()); + Library& lib = Library::Handle(Z); + LoadingUnit& unit = LoadingUnit::Handle(Z); + String& uri = String::Handle(Z); + for (intptr_t i = 0; i < libs.Length(); i++) { + lib ^= libs.At(i); + unit = lib.loading_unit(); + if (unit.IsNull() || (unit.id() != loading_unit_id)) { + continue; + } + uri = lib.url(); + result.Add(uri); + } + + return Api::NewHandle(T, Array::MakeFixedLength(result)); +#endif +} + #if (!defined(TARGET_ARCH_IA32) && !defined(DART_PRECOMPILED_RUNTIME)) // Any flag that affects how we compile code might cause a problem when the