Skip to content

Commit 9e8e8e5

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,dynamic_modules] Support members which are overridden implictly (transitively) by a dynamic module
Consider the following situation: member M1 is overridden by another member M2; M2 is overridden in a dynamic module. Members which can be overridden in a dynamic module (such as M2) should be specified as 'can-be-overridden' in the dynamic interface. Members which are overridden implicitly/transitively (such as M1) are not required to be mentioned in the dynamic interface. However, when determining possible targets for a call with interface target M1, compiler should treat it as potentially overridden in a dynamic module. This change adds such handling to the VM/AOT. Dynamic interface annotator now marks members such as M1 with 'dyn-module:can-be-overridden-implicitly' pragma, and VM/AOT takes both can-be-overridden and can-be-overridden-implicitly into account. This change also simplifies handling of implicitly extenable classes in the VM/AOT - now VM handles both extendable and implicitly-extendable pragmas (from dynamic interface annotator) instead of recalculating implicitly extendable classes on its own. TEST=pkg/vm/test/transformations/dynamic_interface_annotator_test.dart TEST=dynamic_modules_suite/implicitly_extendable Fixes #59880 Change-Id: Id4570cc86303f8e45a061d696e9bca0d0b2b4b81 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403951 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Nate Biggs <[email protected]>
1 parent 493de63 commit 9e8e8e5

File tree

12 files changed

+148
-71
lines changed

12 files changed

+148
-71
lines changed

pkg/vm/lib/transformations/dynamic_interface_annotator.dart

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:front_end/src/api_prototype/dynamic_module_validator.dart'
66
show DynamicInterfaceSpecification;
77
import 'package:kernel/ast.dart';
8+
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
89
import 'package:kernel/core_types.dart' show CoreTypes;
910

1011
import 'pragma.dart'
@@ -13,7 +14,8 @@ import 'pragma.dart'
1314
kDynModuleCallablePragmaName,
1415
kDynModuleExtendablePragmaName,
1516
kDynModuleImplicitlyCallablePragmaName,
16-
kDynModuleImplicitlyExtendablePragmaName;
17+
kDynModuleImplicitlyExtendablePragmaName,
18+
kDynModuleCanBeOverriddenImplicitlyPragmaName;
1719

1820
const bool _debug = false;
1921

@@ -33,13 +35,28 @@ void annotateComponent(String dynamicInterfaceSpecification, Uri baseUri,
3335
annotateFinalClasses: false,
3436
annotateStaticMembers: false,
3537
annotateInstanceMembers: false);
36-
annotateImplicitlyExtendable(coreTypes, extendableAnnotator.annotatedClasses);
37-
annotateNodes(spec.canBeOverridden, kDynModuleCanBeOverriddenPragmaName,
38-
baseUri, coreTypes,
38+
39+
_ImplicitExtendableAnnotator(
40+
pragmaConstant(coreTypes, kDynModuleImplicitlyExtendablePragmaName),
41+
extendableAnnotator.annotatedClasses)
42+
.annotate();
43+
44+
final canBeOverriddenAnnotator = annotateNodes(spec.canBeOverridden,
45+
kDynModuleCanBeOverriddenPragmaName, baseUri, coreTypes,
3946
annotateClasses: false,
4047
annotateFinalClasses: true,
4148
annotateStaticMembers: false,
4249
annotateInstanceMembers: true);
50+
51+
final hierarchy = ClassHierarchy(component, coreTypes);
52+
pragmaConstant(coreTypes, kDynModuleCanBeOverriddenImplicitlyPragmaName);
53+
_ImplicitOverridesAnnotator(
54+
pragmaConstant(
55+
coreTypes, kDynModuleCanBeOverriddenImplicitlyPragmaName),
56+
hierarchy,
57+
canBeOverriddenAnnotator.annotatedMembers)
58+
.annotate();
59+
4360
final callableAnnotator = annotateNodes(
4461
spec.callable, kDynModuleCallablePragmaName, baseUri, coreTypes,
4562
annotateClasses: true,
@@ -171,16 +188,73 @@ class _Annotator extends RecursiveVisitor {
171188
}
172189
}
173190

174-
void annotateImplicitlyExtendable(
175-
CoreTypes coreTypes, Set<Class> extendableClasses) {
176-
final pragma =
177-
pragmaConstant(coreTypes, kDynModuleImplicitlyExtendablePragmaName);
178-
for (final cls in [...extendableClasses]) {
191+
class _ImplicitExtendableAnnotator {
192+
final Constant pragma;
193+
final Set<Class> extendableClasses;
194+
final Set<Class> implicitlyExtendable = Set<Class>.identity();
195+
196+
_ImplicitExtendableAnnotator(this.pragma, this.extendableClasses);
197+
198+
void annotate() {
199+
for (final cls in extendableClasses) {
200+
annotateSupertypesOf(cls);
201+
}
202+
}
203+
204+
void annotateSupertypesOf(Class cls) {
179205
for (final supertype in cls.supers) {
180206
final supertypeClass = supertype.classNode;
181-
if (extendableClasses.add(supertypeClass)) {
207+
if (implicitlyExtendable.add(supertypeClass) &&
208+
!extendableClasses.contains(supertypeClass)) {
182209
supertypeClass.addAnnotation(ConstantExpression(pragma));
210+
annotateSupertypesOf(supertypeClass);
211+
}
212+
}
213+
}
214+
}
215+
216+
class _ImplicitOverridesAnnotator {
217+
final Constant pragma;
218+
final ClassHierarchy hierarchy;
219+
final Set<Member> overriddenMembers;
220+
final Set<Member> implicitlyOverriddenSetters = Set<Member>.identity();
221+
final Set<Member> implicitlyOverriddenNonSetters = Set<Member>.identity();
222+
223+
_ImplicitOverridesAnnotator(
224+
this.pragma, this.hierarchy, this.overriddenMembers);
225+
226+
void annotate() {
227+
for (final member in overriddenMembers) {
228+
final cls = member.enclosingClass!;
229+
if (member.hasGetter) {
230+
annotateSupertypesOf(cls, member.name, setter: false);
231+
}
232+
if (member.hasSetter) {
233+
annotateSupertypesOf(cls, member.name, setter: true);
234+
}
235+
}
236+
}
237+
238+
void annotateSupertypesOf(Class cls, Name memberName,
239+
{required bool setter}) {
240+
for (final supertype in cls.supers) {
241+
final supertypeClass = supertype.classNode;
242+
final member = ClassHierarchy.findMemberByName(
243+
hierarchy.getDeclaredMembers(supertypeClass, setters: setter),
244+
memberName);
245+
if (member != null) {
246+
final implicitlyOverridden = setter
247+
? implicitlyOverriddenSetters
248+
: implicitlyOverriddenNonSetters;
249+
if (implicitlyOverridden.add(member) &&
250+
!overriddenMembers.contains(member)) {
251+
member.addAnnotation(ConstantExpression(pragma));
252+
} else {
253+
// The member is already annotated - do not go deeper.
254+
continue;
255+
}
183256
}
257+
annotateSupertypesOf(supertypeClass, memberName, setter: setter);
184258
}
185259
}
186260
}

pkg/vm/lib/transformations/pragma.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const kDynModuleExtendablePragmaName = "dyn-module:extendable";
2626
const kDynModuleImplicitlyExtendablePragmaName =
2727
"dyn-module:implicitly-extendable";
2828
const kDynModuleCanBeOverriddenPragmaName = "dyn-module:can-be-overridden";
29+
const kDynModuleCanBeOverriddenImplicitlyPragmaName =
30+
"dyn-module:can-be-overridden-implicitly";
2931
const kDynModuleCallablePragmaName = "dyn-module:callable";
3032
const kDynModuleImplicitlyCallablePragmaName = "dyn-module:implicitly-callable";
3133
const kDynModuleEntryPointPragmaName = "dyn-module:entry-point";

pkg/vm/testcases/transformations/dynamic_interface_annotator/dynamic_interface.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extendable:
1818

1919
can-be-overridden:
2020
- library: 'lib1.dart'
21-
class: ['A', 'U']
21+
class: ['A', 'Q', 'U']
2222
- library: 'lib2.dart'
2323
class: 'D'
2424
member: 'build'

pkg/vm/testcases/transformations/dynamic_interface_annotator/lib1.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,17 @@ class N {}
7979

8080
class O extends N {}
8181

82-
class P {}
82+
class P1 implements P2 {
83+
void foo() {}
84+
}
8385

84-
class Q implements P {}
86+
abstract class P2 {
87+
void foo();
88+
}
89+
90+
class Q implements P1 {
91+
void foo() {}
92+
}
8593

8694
final class R {}
8795

pkg/vm/testcases/transformations/dynamic_interface_annotator/lib1.dart.expect

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,19 +141,36 @@ class O extends self::N {
141141
}
142142
@#C11
143143
@#C5
144-
class P extends core::Object {
144+
class P1 extends core::Object implements self::P2 {
145145
@#C5
146-
synthetic constructor •() → self::P
146+
synthetic constructor •() → self::P1
147147
: super core::Object::•()
148148
;
149+
@#C13
150+
@#C5
151+
method foo() → void {}
152+
}
153+
@#C11
154+
@#C5
155+
abstract class P2 extends core::Object {
156+
@#C5
157+
synthetic constructor •() → self::P2
158+
: super core::Object::•()
159+
;
160+
@#C13
161+
@#C5
162+
abstract method foo() → void;
149163
}
150164
@#C3
151165
@#C5
152-
class Q extends core::Object implements self::P {
166+
class Q extends core::Object implements self::P1 {
153167
@#C5
154168
synthetic constructor •() → self::Q
155169
: super core::Object::•()
156170
;
171+
@#C7
172+
@#C5
173+
method foo() → void {}
157174
}
158175
@#C5
159176
final class R extends core::Object {
@@ -199,7 +216,7 @@ base class V extends core::Object {
199216
static field core::Object? sfield9;
200217
static field core::Object? _sfield10;
201218
@#C5
202-
static const field core::List<core::Object> const11 = #C16;
219+
static const field core::List<core::Object> const11 = #C18;
203220
@#C5
204221
static method smethod10() → void {}
205222
static method _smethod11() → void {}
@@ -215,9 +232,11 @@ constants {
215232
#C9 = core::pragma {name:#C8, options:#C2}
216233
#C10 = "dyn-module:implicitly-extendable"
217234
#C11 = core::pragma {name:#C10, options:#C2}
218-
#C12 = 2
219-
#C13 = 1
220-
#C14 = self::_E2 {_y:#C12, _x:#C13}
221-
#C15 = redirecting-factory-tearoff self::_F::_foo
222-
#C16 = <core::Object>[#C14, #C15]
235+
#C12 = "dyn-module:can-be-overridden-implicitly"
236+
#C13 = core::pragma {name:#C12, options:#C2}
237+
#C14 = 2
238+
#C15 = 1
239+
#C16 = self::_E2 {_y:#C14, _x:#C15}
240+
#C17 = redirecting-factory-tearoff self::_F::_foo
241+
#C18 = <core::Object>[#C16, #C17]
223242
}

runtime/tests/vm/dart/dynamic_module_pragmas_il_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ void testIsA1(obj) {
5555
myprint(obj is C1);
5656
}
5757

58+
@pragma('dyn-module:implicitly-extendable')
5859
abstract class A2 {
5960
void foo();
61+
@pragma('dyn-module:can-be-overridden-implicitly')
6062
void bar();
6163
void baz();
6264
}

runtime/vm/class_finalizer.cc

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -589,10 +589,6 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
589589
if (is_future_subtype && !cls.is_abstract()) {
590590
MarkClassCanBeFuture(zone, cls);
591591
}
592-
if (cls.is_dynamically_extendable()) {
593-
MarkClassHasDynamicallyExtendableSubtypes(zone, cls);
594-
}
595-
596592
ClassHiearchyUpdater(zone).Register(cls);
597593
#endif // !defined(DART_PRECOMPILED_RUNTIME)
598594

@@ -687,25 +683,6 @@ void ClassFinalizer::MarkClassCanBeFuture(Zone* zone, const Class& cls) {
687683
}
688684
}
689685

690-
void ClassFinalizer::MarkClassHasDynamicallyExtendableSubtypes(
691-
Zone* zone,
692-
const Class& cls) {
693-
if (cls.has_dynamically_extendable_subtypes()) return;
694-
695-
cls.set_has_dynamically_extendable_subtypes(true);
696-
697-
Class& base = Class::Handle(zone, cls.SuperClass());
698-
if (!base.IsNull()) {
699-
MarkClassHasDynamicallyExtendableSubtypes(zone, base);
700-
}
701-
auto& interfaces = Array::Handle(zone, cls.interfaces());
702-
auto& type = AbstractType::Handle(zone);
703-
for (intptr_t i = 0; i < interfaces.Length(); ++i) {
704-
type ^= interfaces.At(i);
705-
base = type.type_class();
706-
MarkClassHasDynamicallyExtendableSubtypes(zone, base);
707-
}
708-
}
709686
#endif // defined(DART_PRECOMPILED_RUNTIME)
710687

711688
void ClassFinalizer::FinalizeClass(const Class& cls) {

runtime/vm/class_finalizer.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@ class ClassFinalizer : public AllStatic {
5454
#if !defined(DART_PRECOMPILED_RUNTIME)
5555
// Mark [cls], its superclass and superinterfaces as can_be_future().
5656
static void MarkClassCanBeFuture(Zone* zone, const Class& cls);
57-
58-
// Mark [cls] and all its superclasses and superinterfaces as
59-
// has_dynamically_extendable_subtypes().
60-
static void MarkClassHasDynamicallyExtendableSubtypes(Zone* zone,
61-
const Class& cls);
6257
#endif // !defined(DART_PRECOMPILED_RUNTIME)
6358

6459
// Ensures members of the class are loaded, class layout is finalized and size

runtime/vm/kernel_loader.cc

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,8 +1383,9 @@ void KernelLoader::LoadClass(const Library& library,
13831383
if (HasPragma::decode(pragma_bits)) {
13841384
out_class->set_has_pragma(true);
13851385
}
1386-
if (DynModuleExtendablePragma::decode(pragma_bits)) {
1387-
out_class->set_is_dynamically_extendable(true);
1386+
if (DynModuleExtendablePragma::decode(pragma_bits) ||
1387+
DynModuleImplicitlyExtendablePragma::decode(pragma_bits)) {
1388+
out_class->set_has_dynamically_extendable_subtypes(true);
13881389
IG->set_has_dynamically_extendable_classes(true);
13891390
}
13901391
class_helper.SetJustRead(ClassHelper::kAnnotations);
@@ -1622,8 +1623,6 @@ void KernelLoader::FinishClassLoading(const Class& klass,
16221623
signature.set_result_type(T.ReceiverType(klass));
16231624
function.set_has_pragma(HasPragma::decode(pragma_bits));
16241625
function.set_is_visible(!InvisibleFunctionPragma::decode(pragma_bits));
1625-
function.SetIsDynamicallyOverridden(
1626-
DynModuleCanBeOverriddenPragma::decode(pragma_bits));
16271626

16281627
FunctionNodeHelper function_node_helper(&helper_);
16291628
function_node_helper.ReadUntilExcluding(
@@ -1806,11 +1805,21 @@ void KernelLoader::ReadVMAnnotations(intptr_t annotation_count,
18061805
"dyn-module:extendable")) {
18071806
*pragma_bits = DynModuleExtendablePragma::update(true, *pragma_bits);
18081807
}
1808+
if (constant_reader.IsStringConstant(
1809+
name_index, "dyn-module:implicitly-extendable")) {
1810+
*pragma_bits =
1811+
DynModuleImplicitlyExtendablePragma::update(true, *pragma_bits);
1812+
}
18091813
if (constant_reader.IsStringConstant(name_index,
18101814
"dyn-module:can-be-overridden")) {
18111815
*pragma_bits =
18121816
DynModuleCanBeOverriddenPragma::update(true, *pragma_bits);
18131817
}
1818+
if (constant_reader.IsStringConstant(
1819+
name_index, "dyn-module:can-be-overridden-implicitly")) {
1820+
*pragma_bits = DynModuleCanBeOverriddenImplicitlyPragma::update(
1821+
true, *pragma_bits);
1822+
}
18141823
}
18151824
} else {
18161825
helper_.SkipExpression();
@@ -1877,7 +1886,8 @@ void KernelLoader::LoadProcedure(const Library& library,
18771886
is_synthetic);
18781887
function.set_is_visible(!InvisibleFunctionPragma::decode(pragma_bits));
18791888
function.SetIsDynamicallyOverridden(
1880-
DynModuleCanBeOverriddenPragma::decode(pragma_bits));
1889+
DynModuleCanBeOverriddenPragma::decode(pragma_bits) ||
1890+
DynModuleCanBeOverriddenImplicitlyPragma::decode(pragma_bits));
18811891
if (register_function) {
18821892
functions_.Add(&function);
18831893
} else {

runtime/vm/kernel_loader.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,12 @@ class KernelLoader : public ValueObject {
238238
using SharedPragma = BitField<uint32_t, bool, FfiNativePragma::kNextBit>;
239239
using DynModuleExtendablePragma =
240240
BitField<uint32_t, bool, SharedPragma::kNextBit>;
241-
using DynModuleCanBeOverriddenPragma =
241+
using DynModuleImplicitlyExtendablePragma =
242242
BitField<uint32_t, bool, DynModuleExtendablePragma::kNextBit>;
243+
using DynModuleCanBeOverriddenPragma =
244+
BitField<uint32_t, bool, DynModuleImplicitlyExtendablePragma::kNextBit>;
245+
using DynModuleCanBeOverriddenImplicitlyPragma =
246+
BitField<uint32_t, bool, DynModuleCanBeOverriddenPragma::kNextBit>;
243247

244248
void FinishTopLevelClassLoading(const Class& toplevel_class,
245249
const Library& library,

0 commit comments

Comments
 (0)