Skip to content

Commit 93a4247

Browse files
rmacnak-googleCommit Bot
authored and
Commit Bot
committed
Reapply "Account for @pragma("vm:entry-point") creating additional "root" libraries when partitioning the program into loading units."
Weaken assertion in gen_snapshot requiring all libraries to have a loading unit as there can still be unreachable libraries: - Google3 and Fuchsia will compile all the sources in a package to a single dill file, then present multiple input dill files to the AOT compilation. Since the set of libraries was derived from package membership instead of imports, many can be unreachable. - When the root library's main comes from an export, the frontend's representation will incorrectly report the library containing main as the root library and the true root library may be unreachable from it. Instead, assert only that surviving compiled code is assigned a loading unit. TEST=gallery Bug: flutter/gallery#545 Bug: #49325 Bug: #41974 Bug: b/237016312 Change-Id: Ia52563a6f517308d041368be11dcc85270f19acc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/249724 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Alexander Markov <[email protected]>
1 parent e0820bb commit 93a4247

16 files changed

+191
-42
lines changed

pkg/vm/lib/kernel_front_end.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ Future runGlobalTransformations(
510510
// it does it will need the obfuscation prohibitions.
511511
obfuscationProhibitions.transformComponent(component, coreTypes, target);
512512

513-
deferred_loading.transformComponent(component);
513+
deferred_loading.transformComponent(component, coreTypes, target);
514514
}
515515

516516
/// Runs given [action] with [CompilerContext]. This is needed to

pkg/vm/lib/transformations/deferred_loading.dart

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
library vm.transformations.deferred_loading;
66

77
import 'package:kernel/ast.dart';
8+
import 'package:kernel/core_types.dart' show CoreTypes;
9+
import 'package:kernel/target/targets.dart' show Target;
10+
811
import '../dominators.dart';
912
import '../metadata/loading_units.dart';
13+
import 'pragma.dart';
1014

1115
class _LoadingUnitBuilder {
1216
late int id;
@@ -37,7 +41,42 @@ class _LibraryVertex extends Vertex<_LibraryVertex> {
3741
String toString() => "_LibraryVertex(${library.importUri})";
3842
}
3943

40-
List<LoadingUnit> computeLoadingUnits(Component component) {
44+
class HasEntryPointVisitor extends RecursiveVisitor {
45+
final PragmaAnnotationParser parser;
46+
bool _hasEntryPoint = false;
47+
48+
HasEntryPointVisitor(this.parser);
49+
50+
visitAnnotations(List<Expression> annotations) {
51+
for (var ann in annotations) {
52+
ParsedPragma? pragma = parser.parsePragma(ann);
53+
if (pragma is ParsedEntryPointPragma) {
54+
_hasEntryPoint = true;
55+
return;
56+
}
57+
}
58+
}
59+
60+
@override
61+
visitClass(Class klass) {
62+
visitAnnotations(klass.annotations);
63+
klass.visitChildren(this);
64+
}
65+
66+
@override
67+
defaultMember(Member node) {
68+
visitAnnotations(node.annotations);
69+
}
70+
71+
bool hasEntryPoint(Library lib) {
72+
_hasEntryPoint = false;
73+
visitLibrary(lib);
74+
return _hasEntryPoint;
75+
}
76+
}
77+
78+
List<LoadingUnit> computeLoadingUnits(
79+
Component component, HasEntryPointVisitor visitor) {
4180
// 1. Build the dominator tree for the library import graph.
4281
final map = <Library, _LibraryVertex>{};
4382
for (final lib in component.libraries) {
@@ -51,10 +90,15 @@ List<LoadingUnit> computeLoadingUnits(Component component) {
5190
}
5291
final root = map[component.mainMethod!.enclosingLibrary]!;
5392

54-
// Fake imports from root library to every core library so they end up in
55-
// the same loading unit attributed to the user's root library.
93+
// Fake imports from root library to every core library or library containing
94+
// an entry point pragma so that they end up in the same loading unit
95+
// attributed to the user's root library.
5696
for (final vertex in map.values) {
57-
if (vertex.library.importUri.isScheme("dart")) {
97+
if (vertex == root) {
98+
continue;
99+
}
100+
if (vertex.library.importUri.isScheme("dart") ||
101+
visitor.hasEntryPoint(vertex.library)) {
58102
root.successors.add(vertex);
59103
vertex.isLoadingRoot = false;
60104
}
@@ -127,8 +171,12 @@ List<LoadingUnit> computeLoadingUnits(Component component) {
127171
return loadingUnits.map((u) => u.asLoadingUnit()).toList();
128172
}
129173

130-
Component transformComponent(Component component) {
131-
final metadata = new LoadingUnitsMetadata(computeLoadingUnits(component));
174+
Component transformComponent(
175+
Component component, CoreTypes coreTypes, Target target) {
176+
final parser = ConstantPragmaAnnotationParser(coreTypes, target);
177+
final visitor = HasEntryPointVisitor(parser);
178+
final metadata =
179+
new LoadingUnitsMetadata(computeLoadingUnits(component, visitor));
132180
final repo = new LoadingUnitsMetadataRepository();
133181
component.addMetadataRepository(repo);
134182
repo.mapping[component] = metadata;

pkg/vm/test/transformations/deferred_loading_test.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:io';
66

77
import 'package:kernel/target/targets.dart';
88
import 'package:kernel/ast.dart';
9+
import 'package:kernel/core_types.dart';
910
import 'package:kernel/kernel.dart';
1011
import 'package:test/test.dart';
1112
import 'package:vm/transformations/deferred_loading.dart'
@@ -24,7 +25,9 @@ runTestCase(Uri source) async {
2425
final reversed = component.libraries.reversed.toList();
2526
component.libraries.setAll(0, reversed);
2627

27-
component = transformComponent(component);
28+
final coreTypes = CoreTypes(component);
29+
30+
component = transformComponent(component, coreTypes, target);
2831

2932
// Remove core libraries so the expected output isn't enormous and broken by
3033
// core libraries changes.

runtime/vm/app_snapshot.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6916,10 +6916,8 @@ bool Serializer::InCurrentLoadingUnitOrRoot(ObjectPtr obj) {
69166916

69176917
intptr_t unit_id = heap_->GetLoadingUnit(obj);
69186918
if (unit_id == WeakTable::kNoValue) {
6919-
// Not found in early assignment. Conservatively choose the root.
6920-
// TODO(41974): Are these always type testing stubs?
6921-
unit_id = LoadingUnit::kRootId;
6922-
heap_->SetLoadingUnit(obj, unit_id);
6919+
FATAL("Missing loading unit assignment: %s\n",
6920+
Object::Handle(obj).ToCString());
69236921
}
69246922
return unit_id == LoadingUnit::kRootId || unit_id == current_loading_unit_id_;
69256923
}

runtime/vm/heap/heap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,9 @@ class Heap {
219219
}
220220
void ResetObjectIdTable();
221221

222-
void SetLoadingUnit(ObjectPtr raw_obj, intptr_t object_id) {
222+
void SetLoadingUnit(ObjectPtr raw_obj, intptr_t unit_id) {
223223
ASSERT(Thread::Current()->IsMutatorThread());
224-
SetWeakEntry(raw_obj, kLoadingUnits, object_id);
224+
SetWeakEntry(raw_obj, kLoadingUnits, unit_id);
225225
}
226226
intptr_t GetLoadingUnit(ObjectPtr raw_obj) const {
227227
ASSERT(Thread::Current()->IsMutatorThread());

runtime/vm/program_visitor.cc

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,30 +1429,50 @@ void ProgramVisitor::Dedup(Thread* thread) {
14291429
}
14301430

14311431
#if defined(DART_PRECOMPILER)
1432-
class AssignLoadingUnitsCodeVisitor : public CodeVisitor {
1432+
class AssignLoadingUnitsCodeVisitor : public ObjectVisitor {
14331433
public:
14341434
explicit AssignLoadingUnitsCodeVisitor(Zone* zone)
14351435
: heap_(Thread::Current()->heap()),
1436+
code_(Code::Handle(zone)),
14361437
func_(Function::Handle(zone)),
14371438
cls_(Class::Handle(zone)),
14381439
lib_(Library::Handle(zone)),
14391440
unit_(LoadingUnit::Handle(zone)),
14401441
obj_(Object::Handle(zone)) {}
14411442

1443+
void VisitObject(ObjectPtr obj) {
1444+
if (obj->IsCode()) {
1445+
code_ ^= obj;
1446+
VisitCode(code_);
1447+
}
1448+
}
1449+
14421450
void VisitCode(const Code& code) {
14431451
intptr_t id;
14441452
if (code.IsFunctionCode()) {
14451453
func_ ^= code.function();
1446-
cls_ = func_.Owner();
1454+
obj_ = func_.Owner();
1455+
cls_ ^= obj_.ptr();
14471456
lib_ = cls_.library();
1448-
unit_ = lib_.loading_unit();
1449-
id = unit_.id();
1457+
if (lib_.IsNull()) {
1458+
// E.g., dynamic.
1459+
id = LoadingUnit::kRootId;
1460+
} else {
1461+
unit_ = lib_.loading_unit();
1462+
if (unit_.IsNull()) {
1463+
return; // Assignment remains LoadingUnit::kIllegalId
1464+
}
1465+
id = unit_.id();
1466+
}
14501467
} else if (code.IsAllocationStubCode()) {
14511468
cls_ ^= code.owner();
14521469
lib_ = cls_.library();
14531470
unit_ = lib_.loading_unit();
1471+
if (unit_.IsNull()) {
1472+
return; // Assignment remains LoadingUnit::kIllegalId
1473+
}
14541474
id = unit_.id();
1455-
} else if (code.IsStubCode()) {
1475+
} else if (code.IsTypeTestStubCode() || code.IsStubCode()) {
14561476
id = LoadingUnit::kRootId;
14571477
} else {
14581478
UNREACHABLE();
@@ -1484,6 +1504,7 @@ class AssignLoadingUnitsCodeVisitor : public CodeVisitor {
14841504

14851505
private:
14861506
Heap* heap_;
1507+
Code& code_;
14871508
Function& func_;
14881509
Class& cls_;
14891510
Library& lib_;
@@ -1493,31 +1514,16 @@ class AssignLoadingUnitsCodeVisitor : public CodeVisitor {
14931514

14941515
void ProgramVisitor::AssignUnits(Thread* thread) {
14951516
StackZone stack_zone(thread);
1496-
Zone* zone = stack_zone.GetZone();
1497-
1498-
// VM stubs.
1499-
Instructions& inst = Instructions::Handle(zone);
1500-
Code& code = Code::Handle(zone);
1501-
for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
1502-
inst = StubCode::EntryAt(i).instructions();
1503-
thread->heap()->SetLoadingUnit(inst.ptr(), LoadingUnit::kRootId);
1504-
}
1517+
Heap* heap = thread->heap();
15051518

1506-
// Isolate stubs.
1507-
ObjectStore* object_store = thread->isolate_group()->object_store();
1508-
ObjectPtr* from = object_store->from();
1509-
ObjectPtr* to = object_store->to_snapshot(Snapshot::kFullAOT);
1510-
for (ObjectPtr* p = from; p <= to; p++) {
1511-
if ((*p)->IsHeapObject() && (*p)->IsCode()) {
1512-
code ^= *p;
1513-
inst = code.instructions();
1514-
thread->heap()->SetLoadingUnit(inst.ptr(), LoadingUnit::kRootId);
1515-
}
1516-
}
1519+
// Oddballs.
1520+
heap->SetLoadingUnit(Object::null(), LoadingUnit::kRootId);
1521+
heap->SetLoadingUnit(Object::empty_object_pool().ptr(), LoadingUnit::kRootId);
15171522

1518-
// Function code / allocation stubs.
1519-
AssignLoadingUnitsCodeVisitor visitor(zone);
1520-
WalkProgram(zone, thread->isolate_group(), &visitor);
1523+
AssignLoadingUnitsCodeVisitor visitor(thread->zone());
1524+
HeapIterationScope iter(thread);
1525+
iter.IterateVMIsolateObjects(&visitor);
1526+
iter.IterateObjects(&visitor);
15211527
}
15221528

15231529
class ProgramHashVisitor : public CodeVisitor {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
main() {
6+
print("Usurper to the role of root library!");
7+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
export "exported_main_lib.dart";
6+
7+
@pragma("vm:entry-point")
8+
foo() {
9+
// The frontend will not recognize that this is the root library. Though this
10+
// library is not reachable from what the frontend considers the root library,
11+
// the entry point pragma will still cause this function to compiled by
12+
// gen_snaption, so it is important that this library is assigned to a
13+
// loading unit.
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
export "loading_unit_root_has_only_export_lib2.dart";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
foo() => "in lib2";
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import "package:expect/expect.dart";
6+
import "loading_unit_root_has_only_export_lib1.dart" deferred as lib;
7+
8+
main() async {
9+
await lib.loadLibrary();
10+
Expect.equals(lib.foo(), "in lib2");
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// @dart = 2.9
6+
7+
main() {
8+
print("Usurper to the role of root library!");
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// @dart = 2.9
6+
7+
export "exported_main_lib.dart";
8+
9+
@pragma("vm:entry-point")
10+
foo() {
11+
// The frontend will not recognize that this is the root library. Though this
12+
// library is not reachable from what the frontend considers the root library,
13+
// the entry point pragma will still cause this function to compiled by
14+
// gen_snaption, so it is important that this library is assigned to a
15+
// loading unit.
16+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// @dart = 2.9
6+
7+
export "loading_unit_root_has_only_export_lib2.dart";
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// @dart = 2.9
6+
7+
foo() => "in lib2";
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// @dart = 2.9
6+
7+
import "package:expect/expect.dart";
8+
import "loading_unit_root_has_only_export_lib1.dart" deferred as lib;
9+
10+
main() async {
11+
await lib.loadLibrary();
12+
Expect.equals(lib.foo(), "in lib2");
13+
}

0 commit comments

Comments
 (0)