Remove StaticMemberUsage and cleanup codegen world builder
Change-Id: I4fdc6148af671010d1aca55c05d08e55e9c1e9fd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100245
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index ef66b6e..aeca0ec 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -283,11 +283,10 @@
void _registerInstantiatedType(InterfaceType type,
{ConstructorEntity constructor,
bool nativeUsage: false,
- bool globalDependency: false,
- bool isRedirection: false}) {
+ bool globalDependency: false}) {
task.measure(() {
_worldBuilder.registerTypeInstantiation(type, _applyClassUse,
- constructor: constructor, isRedirection: isRedirection);
+ constructor: constructor);
listener.registerInstantiatedType(type,
isGlobal: globalDependency, nativeUsage: nativeUsage);
});
@@ -371,12 +370,6 @@
_registerInstantiatedType(staticUse.type,
constructor: staticUse.element, globalDependency: false);
break;
- case StaticUseKind.REDIRECTION:
- _registerInstantiatedType(staticUse.type,
- constructor: staticUse.element,
- globalDependency: false,
- isRedirection: true);
- break;
default:
break;
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen_listener.dart b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
index 57e2fc0..2306ad6 100644
--- a/pkg/compiler/lib/src/js_backend/codegen_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
@@ -82,8 +82,12 @@
mainImpact.registerStaticUse(
new StaticUse.staticInvoke(mainMethod, callStructure));
}
- mainImpact.registerStaticUse(
- new StaticUse.staticInvoke(mainMethod, CallStructure.NO_ARGS));
+ if (mainMethod.isGetter) {
+ mainImpact.registerStaticUse(new StaticUse.staticGet(mainMethod));
+ } else {
+ mainImpact.registerStaticUse(
+ new StaticUse.staticInvoke(mainMethod, CallStructure.NO_ARGS));
+ }
return mainImpact;
}
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 9eb8195..02eff30 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -171,7 +171,6 @@
switch (staticUse.kind) {
case StaticUseKind.CONSTRUCTOR_INVOKE:
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
- case StaticUseKind.REDIRECTION:
processTypeUse(new TypeUse.instantiation(staticUse.type));
break;
case StaticUseKind.INLINING:
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index e084b4c..04381e4 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -121,8 +121,12 @@
mainImpact.registerStaticUse(
new StaticUse.staticInvoke(mainMethod, callStructure));
}
- mainImpact.registerStaticUse(
- new StaticUse.staticInvoke(mainMethod, CallStructure.NO_ARGS));
+ if (mainMethod.isGetter) {
+ mainImpact.registerStaticUse(new StaticUse.staticGet(mainMethod));
+ } else {
+ mainImpact.registerStaticUse(
+ new StaticUse.staticInvoke(mainMethod, CallStructure.NO_ARGS));
+ }
return mainImpact;
}
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 5094315..c73ae24 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -2107,8 +2107,7 @@
}
});
- for (FunctionEntity element
- in codegenWorldBuilder.staticFunctionsNeedingGetter) {
+ for (FunctionEntity element in codegenWorldBuilder.closurizedStatics) {
FunctionType functionType = _elementEnvironment.getFunctionType(element);
liveTypeVisitor.visitType(functionType, TypeVisitorState.direct);
}
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
index 493afa9..28f512c 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
@@ -141,7 +141,7 @@
bool fieldNeedsGetter(FieldEntity field) {
assert(field.isField);
if (fieldAccessNeverThrows(field)) return false;
- return field.enclosingClass != null &&
+ return field.isInstanceMember &&
_codegenWorldBuilder.hasInvokedGetter(field);
}
@@ -149,7 +149,7 @@
assert(field.isField);
if (fieldAccessNeverThrows(field)) return false;
if (!field.isAssignable) return false;
- return field.enclosingClass != null &&
+ return field.isInstanceMember &&
_codegenWorldBuilder.hasInvokedSetter(field);
}
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index f5b5b0c..a416193 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -1148,8 +1148,8 @@
!element.isConstructor && !element.isGetter && !element.isSetter;
bool canBeApplied = _methodCanBeApplied(element);
- bool needsTearOff = isApplyTarget &&
- _worldBuilder.staticFunctionsNeedingGetter.contains(element);
+ bool needsTearOff =
+ isApplyTarget && _worldBuilder.closurizedStatics.contains(element);
js.Name tearOffName =
needsTearOff ? _namer.staticClosureName(element) : null;
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 1cac12f..e906986 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -1623,6 +1623,7 @@
// avoid redundant declaration of local variable, for instance for
// type arguments.
js.Fun code = field.code;
+ assert(code != null, "No code for $field");
if (code.params.isEmpty &&
code.body.statements.length == 1 &&
code.body.statements.last is js.Return) {
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 6c5852a..3ba7b09 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2092,12 +2092,23 @@
push(js.js('# || #', [arguments[0], right]).withSourceInformation(
node.sourceInformation));
} else {
- CallStructure callStructure = new CallStructure.unnamed(
- arguments.length, node.typeArguments.length);
- _registry.registerStaticUse(element.isConstructor
- ? new StaticUse.constructorInvoke(element, callStructure)
- : new StaticUse.staticInvoke(
- element, callStructure, node.typeArguments));
+ StaticUse staticUse;
+ if (element.isConstructor) {
+ CallStructure callStructure = new CallStructure.unnamed(
+ arguments.length, node.typeArguments.length);
+ staticUse = new StaticUse.constructorInvoke(element, callStructure);
+ } else if (element.isGetter) {
+ staticUse = new StaticUse.staticGet(element);
+ } else if (element.isSetter) {
+ staticUse = new StaticUse.staticSet(element);
+ } else {
+ assert(element.isFunction);
+ CallStructure callStructure = new CallStructure.unnamed(
+ arguments.length, node.typeArguments.length);
+ staticUse = new StaticUse.staticInvoke(
+ element, callStructure, node.typeArguments);
+ }
+ _registry.registerStaticUse(staticUse);
push(_emitter.staticFunctionAccess(element));
push(new js.Call(pop(), arguments,
sourceInformation: node.sourceInformation));
@@ -2108,26 +2119,47 @@
visitInvokeSuper(HInvokeSuper node) {
MemberEntity superElement = node.element;
ClassEntity superClass = superElement.enclosingClass;
+ Selector selector = node.selector;
+ bool useAliasedSuper = _superMemberData.maybeRegisterAliasedSuperMember(
+ superElement, selector);
+ if (selector.isGetter) {
+ if (superElement.isField || superElement.isGetter) {
+ _registry.registerStaticUse(new StaticUse.superGet(superElement));
+ } else {
+ _registry.registerStaticUse(new StaticUse.superTearOff(node.element));
+ }
+ } else if (selector.isSetter) {
+ if (superElement.isField) {
+ _registry.registerStaticUse(new StaticUse.superFieldSet(superElement));
+ } else {
+ assert(superElement.isSetter);
+ _registry.registerStaticUse(new StaticUse.superSetterSet(superElement));
+ }
+ } else {
+ if (_superMemberData.maybeRegisterAliasedSuperMember(
+ superElement, selector)) {
+ _registry.registerStaticUse(new StaticUse.superInvoke(
+ superElement, new CallStructure.unnamed(node.inputs.length)));
+ } else {
+ _registry.registerStaticUse(new StaticUse.superInvoke(
+ superElement, new CallStructure.unnamed(node.inputs.length - 1)));
+ }
+ }
+
if (superElement.isField) {
js.Name fieldName = _namer.instanceFieldPropertyName(superElement);
use(node.inputs[0]);
js.PropertyAccess access = new js.PropertyAccess(pop(), fieldName)
.withSourceInformation(node.sourceInformation);
if (node.isSetter) {
- _registry.registerStaticUse(superElement.isSetter
- ? new StaticUse.superSetterSet(superElement)
- : new StaticUse.superFieldSet(superElement));
use(node.value);
push(new js.Assignment(access, pop())
.withSourceInformation(node.sourceInformation));
} else {
- _registry.registerStaticUse(new StaticUse.superGet(superElement));
push(access);
}
} else {
- Selector selector = node.selector;
- if (!_superMemberData.maybeRegisterAliasedSuperMember(
- superElement, selector)) {
+ if (!useAliasedSuper) {
js.Name methodName;
if (selector.isGetter && !superElement.isGetter) {
// If this is a tear-off, register the fact that a tear-off closure
@@ -2139,13 +2171,11 @@
new CallStructure.unnamed(
node.inputs.length, node.typeArguments.length),
node.typeArguments));
- _registry.registerStaticUse(new StaticUse.superTearOff(node.element));
methodName = _namer.invocationName(selector);
} else {
methodName = _namer.instanceMethodName(superElement);
}
- _registry.registerStaticUse(new StaticUse.superInvoke(
- superElement, new CallStructure.unnamed(node.inputs.length)));
+
push(js.js('#.#.call(#)', [
_emitter.prototypeAccess(superClass, hasBeenInstantiated: true),
methodName,
@@ -2153,8 +2183,6 @@
]).withSourceInformation(node.sourceInformation));
} else {
use(node.receiver);
- _registry.registerStaticUse(new StaticUse.superInvoke(
- superElement, new CallStructure.unnamed(node.inputs.length - 1)));
push(js.js('#.#(#)', [
pop(),
_namer.aliasedSuperMemberPropertyName(superElement),
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index eb54121..d1f075e 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -4,6 +4,7 @@
import 'dart:collection';
+import '../common.dart';
import '../common/names.dart' show Identifiers;
import '../common_elements.dart';
import '../constants/values.dart';
@@ -20,6 +21,8 @@
import 'use.dart'
show ConstantUse, DynamicUse, DynamicUseKind, StaticUse, StaticUseKind;
import 'world_builder.dart';
+import '../js_model/elements.dart' show JSignatureMethod;
+import 'call_structure.dart';
/// World builder specific to codegen.
///
@@ -75,7 +78,6 @@
Map<Selector, SelectorConstraints> setterInvocationsByName(String name);
- Iterable<FunctionEntity> get staticFunctionsNeedingGetter;
Iterable<FunctionEntity> get methodsNeedingSuperGetter;
/// The set of all referenced static fields.
@@ -131,9 +133,6 @@
final Set<FieldEntity> allReferencedStaticFields = new Set<FieldEntity>();
@override
- final Set<FunctionEntity> staticFunctionsNeedingGetter =
- new Set<FunctionEntity>();
- @override
final Set<FunctionEntity> methodsNeedingSuperGetter =
new Set<FunctionEntity>();
final Map<String, Map<Selector, SelectorConstraints>> _invokedNames =
@@ -148,20 +147,10 @@
Map<ClassEntity, ClassUsage> get classUsageForTesting => _processedClasses;
- /// Map of registered usage of static members of live classes.
- final Map<Entity, StaticMemberUsage> _staticMemberUsage =
- <Entity, StaticMemberUsage>{};
-
- Map<Entity, StaticMemberUsage> get staticMemberUsageForTesting =>
- _staticMemberUsage;
-
- /// Map of registered usage of instance members of live classes.
- final Map<MemberEntity, MemberUsage> _instanceMemberUsage =
+ /// Map of registered usage of static and instance members.
+ final Map<MemberEntity, MemberUsage> _memberUsage =
<MemberEntity, MemberUsage>{};
- Map<MemberEntity, MemberUsage> get instanceMemberUsageForTesting =>
- _instanceMemberUsage;
-
/// Map containing instance members of live classes that are not yet live
/// themselves.
final Map<String, Set<MemberUsage>> _instanceMembersByName =
@@ -372,62 +361,23 @@
isChecks.add(type.unaliased);
}
- void _registerStaticUse(StaticUse staticUse) {
- if (staticUse.element is FieldEntity) {
- FieldEntity field = staticUse.element;
- if (field.isTopLevel || field.isStatic) {
- allReferencedStaticFields.add(field);
- }
- }
- switch (staticUse.kind) {
- case StaticUseKind.STATIC_TEAR_OFF:
- staticFunctionsNeedingGetter.add(staticUse.element);
- break;
- case StaticUseKind.SUPER_TEAR_OFF:
- methodsNeedingSuperGetter.add(staticUse.element);
- break;
- case StaticUseKind.SUPER_FIELD_SET:
- case StaticUseKind.FIELD_SET:
- case StaticUseKind.CLOSURE:
- case StaticUseKind.CLOSURE_CALL:
- case StaticUseKind.CALL_METHOD:
- case StaticUseKind.FIELD_GET:
- case StaticUseKind.CONSTRUCTOR_INVOKE:
- case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
- case StaticUseKind.REDIRECTION:
- case StaticUseKind.DIRECT_INVOKE:
- case StaticUseKind.INLINING:
- case StaticUseKind.INVOKE:
- case StaticUseKind.GET:
- case StaticUseKind.SET:
- case StaticUseKind.FIELD_INIT:
- case StaticUseKind.FIELD_CONSTANT_INIT:
- break;
- }
- }
-
void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) {
- Entity element = staticUse.element;
- _registerStaticUse(staticUse);
- StaticMemberUsage usage = _staticMemberUsage.putIfAbsent(element, () {
- if (element is MemberEntity &&
- (element.isStatic || element.isTopLevel) &&
- element.isFunction) {
- return new StaticFunctionUsage(element);
- } else {
- return new GeneralStaticMemberUsage(element);
+ MemberEntity element = staticUse.element;
+ if (element is FieldEntity) {
+ if (element.isTopLevel || element.isStatic) {
+ allReferencedStaticFields.add(element);
}
- });
+ }
+
EnumSet<MemberUse> useSet = new EnumSet<MemberUse>();
+ MemberUsage usage = _getMemberUsage(element, useSet);
switch (staticUse.kind) {
case StaticUseKind.STATIC_TEAR_OFF:
closurizedStatics.add(element);
- useSet.addAll(usage.tearOff());
+ useSet.addAll(usage.read());
break;
case StaticUseKind.FIELD_GET:
case StaticUseKind.FIELD_SET:
- case StaticUseKind.CLOSURE:
- case StaticUseKind.CLOSURE_CALL:
case StaticUseKind.CALL_METHOD:
// TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and
// [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue.
@@ -436,30 +386,39 @@
break;
case StaticUseKind.INVOKE:
registerStaticInvocation(staticUse);
- useSet.addAll(usage.normalUse());
+ // We don't track parameters in the codegen world builder, so we
+ // pass `null` instead of the concrete call structure.
+ useSet.addAll(usage.invoke(null));
break;
case StaticUseKind.SUPER_FIELD_SET:
- case StaticUseKind.SUPER_TEAR_OFF:
- case StaticUseKind.GET:
case StaticUseKind.SET:
+ useSet.addAll(usage.write());
+ break;
+ case StaticUseKind.SUPER_TEAR_OFF:
+ methodsNeedingSuperGetter.add(element);
+ useSet.addAll(usage.read());
+ break;
+ case StaticUseKind.GET:
+ useSet.addAll(usage.read());
+ break;
case StaticUseKind.FIELD_INIT:
+ useSet.addAll(usage.init());
+ break;
case StaticUseKind.FIELD_CONSTANT_INIT:
- useSet.addAll(usage.normalUse());
+ useSet.addAll(usage.constantInit(staticUse.constant));
break;
case StaticUseKind.CONSTRUCTOR_INVOKE:
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
- case StaticUseKind.REDIRECTION:
- useSet.addAll(usage.normalUse());
+ // We don't track parameters in the codegen world builder, so we
+ // pass `null` instead of the concrete call structure.
+ useSet.addAll(usage.invoke(null));
break;
case StaticUseKind.DIRECT_INVOKE:
MemberEntity member = staticUse.element;
- MemberUsage instanceUsage = _getMemberUsage(member, memberUsed);
// We don't track parameters in the codegen world builder, so we
// pass `null` instead of the concrete call structure.
- memberUsed(instanceUsage.entity, instanceUsage.invoke(null));
- _instanceMembersByName[instanceUsage.entity.name]
- ?.remove(instanceUsage);
- useSet.addAll(usage.normalUse());
+ useSet.addAll(usage.invoke(null));
+ _instanceMembersByName[usage.entity.name]?.remove(usage);
if (staticUse.typeArguments?.isNotEmpty ?? false) {
registerDynamicInvocation(
new Selector.call(member.memberName, staticUse.callStructure),
@@ -469,6 +428,10 @@
case StaticUseKind.INLINING:
registerStaticInvocation(staticUse);
break;
+ case StaticUseKind.CLOSURE:
+ case StaticUseKind.CLOSURE_CALL:
+ failedAt(CURRENT_ELEMENT_SPANNABLE,
+ "Static use ${staticUse.kind} is not supported during codegen.");
}
if (useSet.isNotEmpty) {
memberUsed(usage.entity, useSet);
@@ -488,57 +451,76 @@
});
}
- void _processInstantiatedClassMember(ClassEntity cls,
- covariant MemberEntity member, MemberUsedCallback memberUsed,
+ void _processInstantiatedClassMember(
+ ClassEntity cls, MemberEntity member, MemberUsedCallback memberUsed,
{bool dryRun: false}) {
if (!member.isInstanceMember) return;
- _getMemberUsage(member, memberUsed);
+ EnumSet<MemberUse> useSet = new EnumSet<MemberUse>();
+ _getMemberUsage(member, useSet);
+ if (useSet.isNotEmpty) {
+ memberUsed(member, useSet);
+ }
}
- MemberUsage _getMemberUsage(
- covariant MemberEntity member, MemberUsedCallback memberUsed,
+ MemberUsage _getMemberUsage(MemberEntity member, EnumSet<MemberUse> useSet,
{bool dryRun: false}) {
// TODO(johnniwinther): Change [TypeMask] to not apply to a superclass
// member unless the class has been instantiated. Similar to
// [StrongModeConstraint].
- MemberUsage usage = _instanceMemberUsage[member];
+ MemberUsage usage = _memberUsage[member];
if (usage == null) {
- String memberName = member.name;
- ClassEntity cls = member.enclosingClass;
- bool isNative = _nativeBasicData.isNativeClass(cls);
- usage = new MemberUsage(member, isNative: isNative);
- EnumSet<MemberUse> useSet = new EnumSet<MemberUse>();
- useSet.addAll(usage.appliedUse);
- if (!usage.hasRead && hasInvokedGetter(member)) {
- useSet.addAll(usage.read());
- }
- if (!usage.hasWrite && hasInvokedSetter(member)) {
- useSet.addAll(usage.write());
- }
- if (!usage.hasInvoke && hasInvocation(member)) {
- // We don't track parameters in the codegen world builder, so we
- // pass `null` instead of the concrete call structures.
- useSet.addAll(usage.invoke(null));
- }
+ if (member.isInstanceMember) {
+ String memberName = member.name;
+ ClassEntity cls = member.enclosingClass;
+ bool isNative = _nativeBasicData.isNativeClass(cls);
+ usage = new MemberUsage(member);
+ if (member.isField && !isNative) {
+ useSet.addAll(usage.init());
+ }
+ if (member is JSignatureMethod) {
+ // We mark signature methods as "always used" to prevent them from being
+ // optimized away.
+ // TODO(johnniwinther): Make this a part of the regular enqueueing.
+ useSet.addAll(usage.invoke(CallStructure.NO_ARGS));
+ }
- if (!dryRun) {
- if (usage.hasPendingClosurizationUse) {
- // Store the member in [instanceFunctionsByName] to catch
- // getters on the function.
- _instanceFunctionsByName
- .putIfAbsent(usage.entity.name, () => new Set<MemberUsage>())
- .add(usage);
+ if (!usage.hasRead && hasInvokedGetter(member)) {
+ useSet.addAll(usage.read());
}
- if (usage.hasPendingNormalUse) {
- // The element is not yet used. Add it to the list of instance
- // members to still be processed.
- _instanceMembersByName
- .putIfAbsent(memberName, () => new Set<MemberUsage>())
- .add(usage);
+ if (!usage.hasWrite && hasInvokedSetter(member)) {
+ useSet.addAll(usage.write());
}
- _instanceMemberUsage[member] = usage;
+ if (!usage.hasInvoke && hasInvocation(member)) {
+ // We don't track parameters in the codegen world builder, so we
+ // pass `null` instead of the concrete call structures.
+ useSet.addAll(usage.invoke(null));
+ }
+
+ if (!dryRun) {
+ if (usage.hasPendingClosurizationUse) {
+ // Store the member in [instanceFunctionsByName] to catch
+ // getters on the function.
+ _instanceFunctionsByName
+ .putIfAbsent(usage.entity.name, () => new Set<MemberUsage>())
+ .add(usage);
+ }
+ if (usage.hasPendingNormalUse) {
+ // The element is not yet used. Add it to the list of instance
+ // members to still be processed.
+ _instanceMembersByName
+ .putIfAbsent(memberName, () => new Set<MemberUsage>())
+ .add(usage);
+ }
+ }
+ } else {
+ usage = new MemberUsage(member);
+ if (member.isField) {
+ useSet.addAll(usage.init());
+ }
}
- memberUsed(member, useSet);
+ if (!dryRun) {
+ _memberUsage[member] = usage;
+ }
} else {
if (dryRun) {
usage = usage.clone();
@@ -640,7 +622,7 @@
}
}
- _instanceMemberUsage.forEach(processMemberUse);
+ _memberUsage.forEach(processMemberUse);
return functions;
}
@@ -658,7 +640,7 @@
}
}
- _instanceMemberUsage.forEach(processMemberUse);
+ _memberUsage.forEach(processMemberUse);
return functions;
}
@@ -674,8 +656,7 @@
}
}
- _instanceMemberUsage.forEach(processMemberUse);
- _staticMemberUsage.forEach(processMemberUse);
+ _memberUsage.forEach(processMemberUse);
return functions;
}
diff --git a/pkg/compiler/lib/src/universe/member_usage.dart b/pkg/compiler/lib/src/universe/member_usage.dart
index e368cbb..f80d47c 100644
--- a/pkg/compiler/lib/src/universe/member_usage.dart
+++ b/pkg/compiler/lib/src/universe/member_usage.dart
@@ -7,7 +7,6 @@
import '../common.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
-import '../js_model/elements.dart' show JSignatureMethod;
import '../util/enumset.dart';
import 'call_structure.dart';
@@ -21,12 +20,12 @@
}
/// Returns the uses of [entity] that have been registered.
- EnumSet<T> get appliedUse => _originalUse.minus(_pendingUse);
+ EnumSet<T> get _appliedUse => _originalUse.minus(_pendingUse);
EnumSet<T> get _originalUse;
- /// `true` if the [appliedUse] is non-empty.
- bool get hasUse => appliedUse.isNotEmpty;
+ /// `true` if the [_appliedUse] is non-empty.
+ bool get hasUse => _appliedUse.isNotEmpty;
/// Returns `true` if [other] has the same original and pending usage as this.
bool hasSameUsage(AbstractUsage<T> other) {
@@ -45,13 +44,12 @@
MemberUsage.cloned(this.entity, EnumSet<MemberUse> pendingUse)
: super.cloned(pendingUse);
- factory MemberUsage(MemberEntity member,
- {bool isNative: false, bool trackParameters: false}) {
+ factory MemberUsage(MemberEntity member, {bool trackParameters: false}) {
if (member.isField) {
if (member.isAssignable) {
- return new FieldUsage(member, isNative: isNative);
+ return new FieldUsage(member);
} else {
- return new FinalFieldUsage(member, isNative: isNative);
+ return new FinalFieldUsage(member);
}
} else if (member.isGetter) {
return new GetterUsage(member);
@@ -63,8 +61,15 @@
} else {
return new ConstructorUsage(member);
}
+ } else if (member.isConstructor) {
+ if (trackParameters) {
+ return new ParameterTrackingConstructorUsage(member);
+ } else {
+ return new ConstructorUsage(member);
+ }
} else {
- assert(member.isFunction, failedAt(member, "Unexpected member: $member"));
+ assert(member is FunctionEntity,
+ failedAt(member, "Unexpected member: $member"));
if (trackParameters) {
return new ParameterTrackingFunctionUsage(member);
} else {
@@ -178,11 +183,11 @@
fullyUsed == other.fullyUsed &&
isFullyInvoked == other.isFullyInvoked &&
_pendingUse == other._pendingUse &&
- appliedUse == other.appliedUse;
+ _appliedUse == other._appliedUse;
}
@override
- String toString() => '$entity:${appliedUse.iterable(MemberUse.values)}';
+ String toString() => '$entity:${_appliedUse.iterable(MemberUse.values)}';
}
class FieldUsage extends MemberUsage {
@@ -199,16 +204,11 @@
{this.hasInit, this.hasRead, this.hasWrite})
: super.cloned(field, pendingUse);
- FieldUsage(FieldEntity field, {bool isNative: false})
+ FieldUsage(FieldEntity field)
: hasInit = false,
hasRead = false,
hasWrite = false,
- super.internal(field) {
- // TODO(johnniwinther): Track native fields through member usage.
- if (!isNative) {
- init();
- }
- }
+ super.internal(field);
@override
Iterable<ConstantValue> get initialConstants => _initialConstants ?? const [];
@@ -301,14 +301,10 @@
{this.hasInit, this.hasRead})
: super.cloned(field, pendingUse);
- FinalFieldUsage(FieldEntity field, {bool isNative: false})
+ FinalFieldUsage(FieldEntity field)
: this.hasInit = false,
this.hasRead = false,
- super.internal(field) {
- if (!isNative) {
- init();
- }
- }
+ super.internal(field);
@override
Iterable<ConstantValue> get initialConstants => _initialConstants ?? const [];
@@ -389,14 +385,7 @@
FunctionUsage(FunctionEntity function)
: this.hasInvoke = false,
this.hasRead = false,
- super.internal(function) {
- if (function is JSignatureMethod) {
- // We mark signature methods as "always used" to prevent them from being
- // optimized away.
- // TODO(johnniwinther): Make this a part of the regular enqueueing.
- invoke(function.parameterStructure.callStructure);
- }
- }
+ super.internal(function);
@override
FunctionEntity get entity => super.entity;
@@ -472,14 +461,7 @@
ParameterTrackingFunctionUsage(FunctionEntity function)
: hasRead = false,
_parameterUsage = new ParameterUsage(function.parameterStructure),
- super.internal(function) {
- if (function is JSignatureMethod) {
- // We mark signature methods as "always used" to prevent them from being
- // optimized away.
- // TODO(johnniwinther): Make this a part of the regular enqueueing.
- invoke(CallStructure.NO_ARGS);
- }
- }
+ super.internal(function);
@override
bool get hasInvoke => _parameterUsage.hasInvoke;
@@ -804,7 +786,7 @@
EnumSet<ClassUse> get _originalUse => ClassUses.ALL;
@override
- String toString() => '$cls:${appliedUse.iterable(ClassUse.values)}';
+ String toString() => '$cls:${_appliedUse.iterable(ClassUse.values)}';
}
/// Enum class for the possible kind of use of [ClassEntity] objects.
@@ -822,179 +804,6 @@
typedef void ClassUsedCallback(ClassEntity cls, EnumSet<ClassUse> useSet);
-// TODO(johnniwinther): Merge this with [MemberUsage].
-abstract class StaticMemberUsage extends AbstractUsage<MemberUse>
- implements MemberUsage {
- @override
- final MemberEntity entity;
-
- bool hasNormalUse;
- bool get hasClosurization => false;
-
- StaticMemberUsage.cloned(this.entity, EnumSet<MemberUse> pendingUse,
- {this.hasNormalUse: false})
- : super.cloned(pendingUse);
-
- StaticMemberUsage.internal(this.entity)
- : this.hasNormalUse = false,
- super();
-
- EnumSet<MemberUse> normalUse() {
- if (hasNormalUse) {
- return MemberUses.NONE;
- }
- hasNormalUse = true;
- return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
- }
-
- EnumSet<MemberUse> tearOff();
-
- @override
- EnumSet<MemberUse> init() => normalUse();
-
- @override
- EnumSet<MemberUse> constantInit(ConstantValue constant) => normalUse();
-
- @override
- EnumSet<MemberUse> read() => tearOff();
-
- @override
- EnumSet<MemberUse> write() => normalUse();
-
- @override
- EnumSet<MemberUse> invoke(CallStructure callStructure) => normalUse();
-
- @override
- EnumSet<MemberUse> fullyUse() => normalUse();
-
- @override
- Iterable<ConstantValue> get initialConstants => null;
-
- @override
- bool get hasPendingNormalUse => _pendingUse.contains(MemberUse.NORMAL);
-
- @override
- bool get isFullyInvoked => hasInvoke;
-
- @override
- EnumSet<MemberUse> get _originalUse => MemberUses.NORMAL_ONLY;
-
- @override
- bool dataEquals(MemberUsage other) {
- assert(entity == other.entity);
- return hasInit == other.hasInit &&
- hasRead == other.hasRead &&
- hasInvoke == other.hasInvoke &&
- hasWrite == other.hasWrite &&
- hasPendingClosurizationUse == other.hasPendingClosurizationUse &&
- hasPendingNormalUse == other.hasPendingNormalUse &&
- fullyUsed == other.fullyUsed &&
- isFullyInvoked == other.isFullyInvoked &&
- _pendingUse == other._pendingUse &&
- appliedUse == other.appliedUse;
- }
-
- @override
- String toString() => '$entity:${appliedUse.iterable(MemberUse.values)}';
-}
-
-class GeneralStaticMemberUsage extends StaticMemberUsage {
- GeneralStaticMemberUsage(MemberEntity entity) : super.internal(entity);
-
- GeneralStaticMemberUsage.cloned(
- MemberEntity entity, EnumSet<MemberUse> pendingUse,
- {bool hasNormalUse})
- : super.cloned(entity, pendingUse, hasNormalUse: hasNormalUse);
-
- @override
- EnumSet<MemberUse> tearOff() => normalUse();
-
- @override
- bool get hasInit => true;
-
- @override
- bool get fullyUsed => hasNormalUse;
-
- @override
- bool get hasInvoke => hasNormalUse;
-
- @override
- bool get hasWrite => hasNormalUse;
-
- @override
- bool get hasRead => hasNormalUse;
-
- @override
- bool get hasPendingClosurizationUse => false;
-
- @override
- ParameterStructure get invokedParameters => null;
-
- @override
- MemberUsage clone() {
- return new GeneralStaticMemberUsage.cloned(entity, _pendingUse.clone(),
- hasNormalUse: hasNormalUse);
- }
-}
-
-class StaticFunctionUsage extends StaticMemberUsage {
- @override
- bool hasClosurization;
-
- StaticFunctionUsage(FunctionEntity entity)
- : hasClosurization = false,
- super.internal(entity);
-
- StaticFunctionUsage.cloned(
- FunctionEntity entity, EnumSet<MemberUse> pendingUse,
- {bool hasNormalUse, this.hasClosurization})
- : super.cloned(entity, pendingUse, hasNormalUse: hasNormalUse);
-
- @override
- FunctionEntity get entity => super.entity;
-
- @override
- bool get hasInit => true;
-
- @override
- EnumSet<MemberUse> tearOff() {
- if (hasClosurization) {
- return MemberUses.NONE;
- }
- hasNormalUse = hasClosurization = true;
- return _pendingUse.removeAll(MemberUses.ALL_STATIC);
- }
-
- @override
- EnumSet<MemberUse> get _originalUse => MemberUses.ALL_STATIC;
-
- @override
- bool get hasPendingClosurizationUse =>
- _pendingUse.contains(MemberUse.CLOSURIZE_STATIC);
-
- @override
- bool get fullyUsed => hasNormalUse && hasClosurization;
-
- @override
- bool get hasInvoke => hasNormalUse;
-
- @override
- bool get hasWrite => hasNormalUse;
-
- @override
- bool get hasRead => hasClosurization;
-
- @override
- ParameterStructure get invokedParameters =>
- hasInvoke ? entity.parameterStructure : null;
-
- @override
- MemberUsage clone() {
- return new StaticFunctionUsage.cloned(entity, _pendingUse.clone(),
- hasNormalUse: hasNormalUse, hasClosurization: hasClosurization);
- }
-}
-
/// Object used for tracking parameter use in constructor and method
/// invocations.
class ParameterUsage {
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index 7415ea2..09d2c6a 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -104,7 +104,7 @@
// TODO(johnniwinther): Support unknown type arguments for generic types.
void registerTypeInstantiation(
InterfaceType type, ClassUsedCallback classUsed,
- {ConstructorEntity constructor, bool isRedirection: false});
+ {ConstructorEntity constructor});
/// Computes usage for all members declared by [cls]. Calls [membersUsed] with
/// the usage changes for each member.
@@ -139,23 +139,19 @@
class Instance {
final InterfaceType type;
final Instantiation kind;
- final bool isRedirection;
- Instance(this.type, this.kind, {this.isRedirection: false});
+ Instance(this.type, this.kind);
@override
int get hashCode {
- return Hashing.objectHash(
- type, Hashing.objectHash(kind, Hashing.objectHash(isRedirection)));
+ return Hashing.objectHash(type, Hashing.objectHash(kind));
}
@override
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! Instance) return false;
- return type == other.type &&
- kind == other.kind &&
- isRedirection == other.isRedirection;
+ return type == other.type && kind == other.kind;
}
@override
@@ -169,9 +165,6 @@
} else if (kind == Instantiation.UNINSTANTIATED) {
sb.write(' none');
}
- if (isRedirection) {
- sb.write(' redirect');
- }
return sb.toString();
}
}
@@ -242,12 +235,11 @@
/// Register [type] as the instantiation [kind] using [constructor].
void addInstantiation(
- ConstructorEntity constructor, InterfaceType type, Instantiation kind,
- {bool isRedirection: false}) {
+ ConstructorEntity constructor, InterfaceType type, Instantiation kind) {
instantiationMap ??= <ConstructorEntity, Set<Instance>>{};
instantiationMap
.putIfAbsent(constructor, () => new Set<Instance>())
- .add(new Instance(type, kind, isRedirection: isRedirection));
+ .add(new Instance(type, kind));
switch (kind) {
case Instantiation.DIRECTLY_INSTANTIATED:
isDirectlyInstantiated = true;
@@ -338,26 +330,6 @@
Map<MemberEntity, MemberUsage> get memberUsageForTesting => _memberUsage;
- Map<MemberEntity, MemberUsage> get staticMemberUsageForTesting {
- Map<MemberEntity, MemberUsage> map = <MemberEntity, MemberUsage>{};
- _memberUsage.forEach((MemberEntity member, MemberUsage usage) {
- if (!member.isInstanceMember) {
- map[member] = usage;
- }
- });
- return map;
- }
-
- Map<MemberEntity, MemberUsage> get instanceMemberUsageForTesting {
- Map<MemberEntity, MemberUsage> map = <MemberEntity, MemberUsage>{};
- _memberUsage.forEach((MemberEntity member, MemberUsage usage) {
- if (member.isInstanceMember) {
- map[member] = usage;
- }
- });
- return map;
- }
-
/// Map containing instance members of live classes that are not yet fully
/// live themselves.
final Map<String, Set<MemberUsage>> _instanceMembersByName =
@@ -546,7 +518,7 @@
@override
void registerTypeInstantiation(
InterfaceType type, ClassUsedCallback classUsed,
- {ConstructorEntity constructor, bool isRedirection: false}) {
+ {ConstructorEntity constructor}) {
ClassEntity cls = type.element;
InstantiationInfo info =
_instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo());
@@ -563,8 +535,7 @@
kind = Instantiation.DIRECTLY_INSTANTIATED;
}
}
- info.addInstantiation(constructor, type, kind,
- isRedirection: isRedirection);
+ info.addInstantiation(constructor, type, kind);
if (kind != Instantiation.UNINSTANTIATED) {
_classHierarchyBuilder.updateClassHierarchyNodeForClass(cls,
directlyInstantiated: info.isDirectlyInstantiated,
@@ -788,7 +759,6 @@
break;
case StaticUseKind.CONSTRUCTOR_INVOKE:
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
- case StaticUseKind.REDIRECTION:
useSet.addAll(usage.invoke(staticUse.callStructure));
break;
case StaticUseKind.DIRECT_INVOKE:
@@ -882,9 +852,10 @@
// Note: this assumes that there are no non-native fields on native
// classes, which may not be the case when a native class is subclassed.
bool isNative = _nativeBasicData.isNativeClass(cls);
- usage =
- new MemberUsage(member, isNative: isNative, trackParameters: true);
- useSet.addAll(usage.appliedUse);
+ usage = new MemberUsage(member, trackParameters: true);
+ if (member.isField && !isNative) {
+ useSet.addAll(usage.init());
+ }
if (!dryRun) {
if (member.isField && isNative) {
registerUsedElement(member);
@@ -931,11 +902,13 @@
}
} else {
usage = new MemberUsage(member, trackParameters: true);
- useSet.addAll(usage.appliedUse);
+ if (member.isField) {
+ useSet.addAll(usage.init());
+ }
}
- }
- if (!dryRun) {
- _memberUsage[member] = usage;
+ if (!dryRun) {
+ _memberUsage[member] = usage;
+ }
}
return usage;
}
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 01b0d07..da78e72 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -154,7 +154,6 @@
CALL_METHOD,
CONSTRUCTOR_INVOKE,
CONST_CONSTRUCTOR_INVOKE,
- REDIRECTION,
DIRECT_INVOKE,
INLINING,
INVOKE,
@@ -262,6 +261,8 @@
element,
"Static invoke element $element must be a top-level "
"or static method."));
+ assert(element.isFunction,
+ failedAt(element, "Static get element $element must be a function."));
assert(
callStructure != null,
failedAt(element,
@@ -280,6 +281,8 @@
element,
"Static tear-off element $element must be a top-level "
"or static method."));
+ assert(element.isFunction,
+ failedAt(element, "Static get element $element must be a function."));
return new StaticUse.internal(element, StaticUseKind.STATIC_TEAR_OFF,
deferredImport: deferredImport);
}
@@ -292,7 +295,7 @@
failedAt(
element,
"Static get element $element must be a top-level "
- "or static method."));
+ "or static field or getter."));
assert(
element.isField || element.isGetter,
failedAt(element,
@@ -311,7 +314,7 @@
"Static set element $element "
"must be a top-level or static method."));
assert(
- element.isField || element.isSetter,
+ (element.isField && element.isAssignable) || element.isSetter,
failedAt(element,
"Static set element $element must be a field or a setter."));
return new StaticUse.internal(element, StaticUseKind.SET,
@@ -530,19 +533,6 @@
deferredImport: deferredImport);
}
- /// Constructor redirection to [element] on [type].
- factory StaticUse.constructorRedirect(
- ConstructorEntity element, InterfaceType type) {
- assert(type != null,
- failedAt(element, "No type provided for constructor redirection."));
- assert(
- element.isConstructor,
- failedAt(element,
- "Constructor redirection element $element must be a constructor."));
- return new StaticUse.internal(element, StaticUseKind.REDIRECTION,
- type: type);
- }
-
/// Initialization of an instance field [element].
factory StaticUse.fieldInit(FieldEntity element) {
assert(
@@ -654,7 +644,7 @@
element,
"Type argument count mismatch. Call structure has "
"${callStructure?.typeArgumentCount ?? 0} but "
- "${typeArguments?.length ?? 0} were passed."));
+ "${typeArguments?.length ?? 0} were passed in $this."));
}
GenericStaticUse.methodInlining(FunctionEntity entity, this.typeArguments)
diff --git a/tests/compiler/dart2js_extra/field_access_test.dart b/tests/compiler/dart2js_extra/field_access_test.dart
new file mode 100644
index 0000000..044baf4
--- /dev/null
+++ b/tests/compiler/dart2js_extra/field_access_test.dart
@@ -0,0 +1,88 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test the all variants of field/property access/update are emitted.
+//
+// This is needed because getter/setters are now registered as read from and
+// written to, respectively, instead of being invoked.
+
+var field1a;
+
+var field1b;
+
+var field1c;
+
+@pragma('dart2js:noInline')
+get field2a => 42;
+
+@pragma('dart2js:noInline')
+set field2a(_) {}
+
+@pragma('dart2js:noInline')
+get field2b => 42;
+
+@pragma('dart2js:noInline')
+set field2b(_) {}
+
+@pragma('dart2js:noInline')
+get field2c => 42;
+
+@pragma('dart2js:noInline')
+set field2c(_) {}
+
+class Class {
+ @pragma('dart2js:noElision')
+ var field1a;
+
+ var field1b;
+
+ var field1c;
+
+ @pragma('dart2js:noInline')
+ get field2a => 42;
+
+ @pragma('dart2js:noInline')
+ set field2a(_) {}
+
+ @pragma('dart2js:noInline')
+ get field2b => 42;
+
+ @pragma('dart2js:noInline')
+ set field2b(_) {}
+
+ @pragma('dart2js:noInline')
+ get field2c => 42;
+
+ set field2c(_) {}
+
+ var field3a = 0;
+
+ var field3b;
+
+ @pragma('dart2js:noInline')
+ Class([this.field3b]);
+
+ @pragma('dart2js:noInline')
+ test() {
+ field1a;
+ field1b = 42;
+ field1c = field1c;
+
+ field2a;
+ field2b = 42;
+ field2c = field2c;
+ }
+}
+
+main() {
+ field1a;
+ field1b = 42;
+ field1c = field1c;
+
+ field2a;
+ field2b = 42;
+ field2c = field2c;
+
+ new Class().test();
+}