Skip to content

Commit 6e8180a

Browse files
natebiggsCommit Queue
authored andcommitted
[dart2js] Fix timing issue in protobuf conditional impact enqueueing.
Prior to this fix, the "processedMembers" field on the ResolutionWorldBuilder was getting used as the signal that a member was active and therefore any conditional uses dependent on it should be active. In some cases the following would occur: 1) The listener gets a signal a member is active. It checks if there are any conditional uses for that member and sees none. 2) A conditional use is registered and the member is not indicated as active yet so the use is stored as pending in ResolutionEnqueuerListener. 3) "processedMembers" in ResolutionWorldBuilder is updated for a member that would mark the conditional use active. This doesn't trigger a check of the pending conditional uses. If the enqueues happen in this order (which is not always the case), the conditional impact will not be marked active and the field will be erroneously tree shaken. The solution here is to remove step 3 and add an analogous "usedMembers" update in step 1. Step 1 will always occur before step 2 so the conditional impact ledger and the usedMembers ledger will always stay in sync. Change-Id: Ib732a4fe5dcc8fc7cbe9a6d37e1c239e287595ff Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/395740 Reviewed-by: Mayank Patke <[email protected]> Commit-Queue: Nate Biggs <[email protected]>
1 parent 6f4cf56 commit 6e8180a

File tree

4 files changed

+23
-20
lines changed

4 files changed

+23
-20
lines changed

pkg/compiler/lib/src/enqueue.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ abstract class EnqueuerListener {
4040
/// backend specific [WorldImpact] of this is returned.
4141
WorldImpact registerUsedElement(MemberEntity member);
4242

43-
/// Called to register that [use] is a pending condition.
44-
/// [ConditionalUse.originalConditions] must only contain members that are not known
45-
/// to be live yet.
46-
void registerPendingConditionalUse(ConditionalUse use);
43+
/// Called to register a new conditional impact, [use]. If the conditional
44+
/// impact's condition is satisfied, the returned [WorldImpact] will contain
45+
/// the implied impact.
46+
WorldImpact registerConditionalUse(ConditionalUse use);
4747

4848
/// Called to register that [value] is statically known to be used. Any
4949
/// backend specific [WorldImpact] of this is returned.

pkg/compiler/lib/src/js_backend/codegen_listener.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ class CodegenEnqueuerListener extends EnqueuerListener {
357357
}
358358

359359
@override
360-
void registerPendingConditionalUse(ConditionalUse use) {
360+
WorldImpact registerConditionalUse(ConditionalUse use) {
361361
throw UnsupportedError(
362362
'Codegen enqueuer does not support conditional impacts.');
363363
}

pkg/compiler/lib/src/js_backend/resolution_listener.dart

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import '../universe/call_structure.dart' show CallStructure;
1818
import '../universe/use.dart' show ConditionalUse, StaticUse, TypeUse;
1919
import '../universe/world_impact.dart'
2020
show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
21-
import 'field_analysis.dart';
2221
import 'backend_impact.dart';
2322
import 'backend_usage.dart';
2423
import 'checked_mode_helpers.dart';
2524
import 'custom_elements_analysis.dart';
25+
import 'field_analysis.dart';
2626
import 'interceptor_data.dart';
2727
import 'native_data.dart' show NativeBasicData;
2828
import 'no_such_method_registry.dart';
@@ -258,10 +258,13 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
258258
return impactBuilder;
259259
}
260260

261+
final Set<MemberEntity> _usedMembers = {};
262+
261263
@override
262264
WorldImpact registerUsedElement(MemberEntity member) {
263265
WorldImpactBuilderImpl worldImpact = WorldImpactBuilderImpl();
264266
_customElementsAnalysis.registerStaticUse(member);
267+
_usedMembers.add(member);
265268
final conditionalUses = _pendingConditionalUses.remove(member);
266269
if (conditionalUses != null) {
267270
// Apply any newly satisfied conditional impacts and remove the condition
@@ -501,9 +504,16 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
501504
}
502505

503506
@override
504-
void registerPendingConditionalUse(ConditionalUse use) {
505-
for (final condition in use.originalConditions) {
506-
(_pendingConditionalUses[condition] ??= {}).add(use);
507+
WorldImpact registerConditionalUse(ConditionalUse use) {
508+
WorldImpactBuilderImpl impactBuilder = WorldImpactBuilderImpl();
509+
if (use.originalConditions.any(_usedMembers.contains)) {
510+
// If any condition is already satisfied, apply the impact immediately.
511+
impactBuilder.addImpact(use.impact);
512+
} else {
513+
for (final condition in use.originalConditions) {
514+
(_pendingConditionalUses[condition] ??= {}).add(use);
515+
}
507516
}
517+
return impactBuilder;
508518
}
509519
}

pkg/compiler/lib/src/resolution/enqueuer.dart

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import '../common.dart';
88
import '../common/elements.dart' show ElementEnvironment;
99
import '../common/tasks.dart' show CompilerTask;
1010
import '../common/work.dart' show WorkItem;
11-
import '../enqueue.dart';
1211
import '../elements/entities.dart';
1312
import '../elements/types.dart';
13+
import '../enqueue.dart';
1414
import '../js_backend/annotations.dart';
15+
import '../js_backend/resolution_listener.dart';
1516
import '../universe/member_usage.dart';
1617
import '../universe/resolution_world_builder.dart' show ResolutionWorldBuilder;
1718
import '../universe/use.dart'
@@ -32,7 +33,7 @@ class ResolutionEnqueuer extends Enqueuer {
3233
final CompilerTask task;
3334
final String name;
3435
@override
35-
final EnqueuerListener listener;
36+
final ResolutionEnqueuerListener listener;
3637

3738
final Set<ClassEntity> _recentClasses = Setlet<ClassEntity>();
3839
bool _recentConstants = false;
@@ -337,14 +338,6 @@ class ResolutionEnqueuer extends Enqueuer {
337338

338339
@override
339340
void processConditionalUse(ConditionalUse conditionalUse) {
340-
// Only register a conditional use as pending if no condition member is
341-
// live. If any condition member is live then immediately apply the impact.
342-
// `worldBuilder.isMemberProcessed` checks whether the member is used
343-
// including all static and instance members.
344-
if (conditionalUse.originalConditions.any(worldBuilder.isMemberProcessed)) {
345-
applyImpact(conditionalUse.impact);
346-
} else {
347-
listener.registerPendingConditionalUse(conditionalUse);
348-
}
341+
applyImpact(listener.registerConditionalUse(conditionalUse));
349342
}
350343
}

0 commit comments

Comments
 (0)