mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
Include FieldInitializer in allocator analysis
Change-Id: Id3ce8113816193408f704045c130e65fe65e6244 Reviewed-on: https://dart-review.googlesource.com/c/93424 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Stephen Adams <sra@google.com>
This commit is contained in:
parent
8db489cb10
commit
596e0aa645
10 changed files with 324 additions and 55 deletions
|
@ -1758,7 +1758,7 @@ class PositionalArgumentReference extends ConstantExpression {
|
|||
@override
|
||||
ConstantValue evaluate(
|
||||
EvaluationEnvironment environment, ConstantSystem constantSystem) {
|
||||
throw new UnsupportedError('PositionalArgumentReference.evaluate');
|
||||
return new NonConstantValue();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1797,7 +1797,7 @@ class NamedArgumentReference extends ConstantExpression {
|
|||
@override
|
||||
ConstantValue evaluate(
|
||||
EvaluationEnvironment environment, ConstantSystem constantSystem) {
|
||||
throw new UnsupportedError('NamedArgumentReference.evaluate');
|
||||
return new NonConstantValue();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -9,7 +9,7 @@ import '../js_model/elements.dart' show JField;
|
|||
import '../js_model/js_world_builder.dart';
|
||||
import '../kernel/element_map.dart';
|
||||
import '../kernel/kernel_strategy.dart';
|
||||
import '../kernel/kelements.dart' show KClass, KField;
|
||||
import '../kernel/kelements.dart' show KClass, KField, KConstructor;
|
||||
import '../options.dart';
|
||||
import '../serialization/serialization.dart';
|
||||
|
||||
|
@ -34,7 +34,7 @@ abstract class AllocatorAnalysis {}
|
|||
class KAllocatorAnalysis implements AllocatorAnalysis {
|
||||
final KernelToElementMap _elementMap;
|
||||
|
||||
final Map<KField, ConstantValue> _fixedInitializers = {};
|
||||
final Map<KField, AllocatorData> _fixedInitializers = {};
|
||||
|
||||
KAllocatorAnalysis(KernelFrontEndStrategy kernelStrategy)
|
||||
: _elementMap = kernelStrategy.elementMap;
|
||||
|
@ -44,36 +44,133 @@ class KAllocatorAnalysis implements AllocatorAnalysis {
|
|||
void registerInstantiatedClass(KClass class_) {
|
||||
ir.Class classNode = _elementMap.getClassNode(class_);
|
||||
|
||||
Map<ir.Field, ConstantValue> inits = {};
|
||||
Map<ir.Field, AllocatorData> fieldData = {};
|
||||
for (ir.Field field in classNode.fields) {
|
||||
if (!field.isInstanceMember) continue;
|
||||
ir.Expression expression = field.initializer;
|
||||
ConstantValue value = _elementMap.getConstantValue(expression,
|
||||
requireConstant: false, implicitNull: true);
|
||||
if (value != null && value.isConstant) {
|
||||
inits[field] = value;
|
||||
fieldData[field] = new AllocatorData(value);
|
||||
}
|
||||
}
|
||||
|
||||
for (ir.Constructor constructor in classNode.constructors) {
|
||||
KConstructor constructorElement = _elementMap.getConstructor(constructor);
|
||||
for (ir.Initializer initializer in constructor.initializers) {
|
||||
if (initializer is ir.FieldInitializer) {
|
||||
// TODO(sra): Check explicit initializer value to see if consistent
|
||||
// over all constructors.
|
||||
inits.remove(initializer.field);
|
||||
AllocatorData data = fieldData[initializer.field];
|
||||
if (data == null) {
|
||||
// TODO(johnniwinther): Support initializers with side-effects?
|
||||
|
||||
// The field has a non-constant initializer.
|
||||
continue;
|
||||
}
|
||||
|
||||
Initializer initializerValue = const Initializer.complex();
|
||||
ir.Expression value = initializer.value;
|
||||
ConstantValue constantValue = _elementMap.getConstantValue(value,
|
||||
requireConstant: false, implicitNull: true);
|
||||
if (constantValue != null && constantValue.isConstant) {
|
||||
initializerValue = new Initializer.direct(constantValue);
|
||||
} else if (value is ir.VariableGet) {
|
||||
ir.VariableDeclaration parameter = value.variable;
|
||||
int position =
|
||||
constructor.function.positionalParameters.indexOf(parameter);
|
||||
if (position != -1) {
|
||||
if (position >= constructor.function.requiredParameterCount) {
|
||||
constantValue = _elementMap.getConstantValue(
|
||||
parameter.initializer,
|
||||
requireConstant: false,
|
||||
implicitNull: true);
|
||||
if (constantValue != null && constantValue.isConstant) {
|
||||
initializerValue =
|
||||
new Initializer.positional(position, constantValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
position =
|
||||
constructor.function.namedParameters.indexOf(parameter);
|
||||
if (position != -1) {
|
||||
constantValue = _elementMap.getConstantValue(
|
||||
parameter.initializer,
|
||||
requireConstant: false,
|
||||
implicitNull: true);
|
||||
if (constantValue != null && constantValue.isConstant) {
|
||||
initializerValue =
|
||||
new Initializer.named(parameter.name, constantValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data.initializers[constructorElement] = initializerValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inits.forEach((ir.Field fieldNode, ConstantValue value) {
|
||||
_fixedInitializers[_elementMap.getField(fieldNode)] = value;
|
||||
fieldData.forEach((ir.Field fieldNode, AllocatorData data) {
|
||||
_fixedInitializers[_elementMap.getField(fieldNode)] = data;
|
||||
});
|
||||
}
|
||||
|
||||
ConstantValue getFixedInitializerForTesting(KField field) =>
|
||||
AllocatorData getFixedInitializerForTesting(KField field) =>
|
||||
_fixedInitializers[field];
|
||||
}
|
||||
|
||||
class AllocatorData {
|
||||
final ConstantValue initialValue;
|
||||
final Map<KConstructor, Initializer> initializers = {};
|
||||
|
||||
AllocatorData(this.initialValue);
|
||||
}
|
||||
|
||||
enum InitializerKind {
|
||||
direct,
|
||||
positional,
|
||||
named,
|
||||
complex,
|
||||
}
|
||||
|
||||
class Initializer {
|
||||
final InitializerKind kind;
|
||||
final int index;
|
||||
final String name;
|
||||
final ConstantValue value;
|
||||
|
||||
Initializer.direct(this.value)
|
||||
: kind = InitializerKind.direct,
|
||||
index = null,
|
||||
name = null;
|
||||
|
||||
Initializer.positional(this.index, this.value)
|
||||
: kind = InitializerKind.positional,
|
||||
name = null;
|
||||
|
||||
Initializer.named(this.name, this.value)
|
||||
: kind = InitializerKind.named,
|
||||
index = null;
|
||||
|
||||
const Initializer.complex()
|
||||
: kind = InitializerKind.complex,
|
||||
index = null,
|
||||
name = null,
|
||||
value = null;
|
||||
|
||||
String shortText() {
|
||||
switch (kind) {
|
||||
case InitializerKind.direct:
|
||||
return value.toStructuredText();
|
||||
case InitializerKind.positional:
|
||||
return '$index:${value.toStructuredText()}';
|
||||
case InitializerKind.named:
|
||||
return '$name:${value.toStructuredText()}';
|
||||
case InitializerKind.complex:
|
||||
return '?';
|
||||
}
|
||||
throw new UnsupportedError('Unexpected kind $kind');
|
||||
}
|
||||
}
|
||||
|
||||
class JAllocatorAnalysis implements AllocatorAnalysis {
|
||||
/// Tag used for identifying serialized [JAllocatorAnalysis] objects in a
|
||||
/// debugging data stream.
|
||||
|
@ -114,12 +211,20 @@ class JAllocatorAnalysis implements AllocatorAnalysis {
|
|||
JsToFrontendMap map, CompilerOptions options) {
|
||||
var result = JAllocatorAnalysis._();
|
||||
|
||||
kAnalysis._fixedInitializers.forEach((KField kField, ConstantValue value) {
|
||||
if (value.isNull || value.isInt || value.isBool || value.isString) {
|
||||
// TODO(johnniwinther): Support non-primitive constants.
|
||||
JField jField = map.toBackendMember(kField);
|
||||
if (jField != null) {
|
||||
result._fixedInitializers[jField] = map.toBackendConstant(value);
|
||||
kAnalysis._fixedInitializers.forEach((KField kField, AllocatorData data) {
|
||||
// TODO(johnniwinther): Use liveness of constructors and elided optional
|
||||
// parameters to recognize more constant initializers.
|
||||
if (data.initialValue != null && data.initializers.isEmpty) {
|
||||
ConstantValue value = data.initialValue;
|
||||
if (value.isNull || value.isInt || value.isBool || value.isString) {
|
||||
// TODO(johnniwinther,sra): Support non-primitive constants in
|
||||
// allocators when it does cause allocators to deoptimized because
|
||||
// of deferred loading.
|
||||
|
||||
JField jField = map.toBackendMember(kField);
|
||||
if (jField != null) {
|
||||
result._fixedInitializers[jField] = map.toBackendConstant(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -169,25 +169,6 @@ class KFactoryConstructor extends KConstructor {
|
|||
bool get isGenerativeConstructor => false;
|
||||
}
|
||||
|
||||
class KConstructorBody extends KFunction implements ConstructorBodyEntity {
|
||||
final ConstructorEntity constructor;
|
||||
|
||||
KConstructorBody(this.constructor)
|
||||
: super(
|
||||
constructor.library,
|
||||
constructor.enclosingClass,
|
||||
constructor.memberName,
|
||||
constructor.parameterStructure,
|
||||
AsyncMarker.SYNC,
|
||||
isStatic: false,
|
||||
isExternal: false);
|
||||
|
||||
@override
|
||||
bool get isFunction => true;
|
||||
|
||||
String get _kind => 'constructor_body';
|
||||
}
|
||||
|
||||
class KMethod extends KFunction {
|
||||
final bool isAbstract;
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// 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.
|
||||
|
||||
main() {
|
||||
new Class1.a();
|
||||
new Class1.b();
|
||||
}
|
||||
|
||||
class Class1 {
|
||||
var field1 = 0;
|
||||
var field2;
|
||||
var field3;
|
||||
|
||||
/*element: Class1.field4:initial=IntConstant(4)*/
|
||||
var field4 = 4;
|
||||
|
||||
var field5 = 5;
|
||||
|
||||
Class1.a()
|
||||
: field1 = 1,
|
||||
field2 = 1,
|
||||
field3 = 3,
|
||||
field5 = 5;
|
||||
|
||||
Class1.b()
|
||||
: field2 = 2,
|
||||
field3 = 3,
|
||||
field5 = 5;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// 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.
|
||||
|
||||
main() {
|
||||
new Class1(0);
|
||||
new Class1(0, 1);
|
||||
new Class2(0);
|
||||
new Class2(0, field2: 1);
|
||||
}
|
||||
|
||||
class Class1 {
|
||||
var field1;
|
||||
var field2;
|
||||
var field3;
|
||||
|
||||
Class1(this.field1, [this.field2 = 2, this.field3 = 3]);
|
||||
}
|
||||
|
||||
class Class2 {
|
||||
var field1;
|
||||
var field2;
|
||||
var field3;
|
||||
|
||||
Class2(this.field1, {this.field2 = 2, this.field3 = 3});
|
||||
}
|
|
@ -5,7 +5,6 @@
|
|||
import 'dart:io';
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:compiler/src/compiler.dart';
|
||||
import 'package:compiler/src/constants/values.dart';
|
||||
import 'package:compiler/src/elements/entities.dart';
|
||||
import 'package:compiler/src/ir/util.dart';
|
||||
import 'package:compiler/src/js_backend/allocator_analysis.dart';
|
||||
|
@ -39,11 +38,17 @@ class KAllocatorAnalysisDataComputer extends DataComputer<Features> {
|
|||
KAllocatorAnalysis allocatorAnalysis =
|
||||
compiler.backend.allocatorResolutionAnalysisForTesting;
|
||||
ir.Member node = frontendStrategy.elementMap.getMemberNode(member);
|
||||
ConstantValue initialValue =
|
||||
AllocatorData data =
|
||||
allocatorAnalysis.getFixedInitializerForTesting(member);
|
||||
Features features = new Features();
|
||||
if (initialValue != null) {
|
||||
features[Tags.initialValue] = initialValue.toStructuredText();
|
||||
if (data != null) {
|
||||
if (data.initialValue != null) {
|
||||
features[Tags.initialValue] = data.initialValue.toStructuredText();
|
||||
}
|
||||
data.initializers.forEach((constructor, value) {
|
||||
features['${constructor.enclosingClass.name}.${constructor.name}'] =
|
||||
value?.shortText();
|
||||
});
|
||||
}
|
||||
Id id = computeEntityId(node);
|
||||
actualMap[id] = new ActualData<Features>(
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// 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.
|
||||
|
||||
main() {
|
||||
new Class1.a();
|
||||
new Class1.b();
|
||||
}
|
||||
|
||||
class Class1 {
|
||||
/*element: Class1.field1:
|
||||
Class1.a=IntConstant(1),
|
||||
initial=IntConstant(0)
|
||||
*/
|
||||
var field1 = 0;
|
||||
|
||||
/*element: Class1.field2:
|
||||
Class1.a=IntConstant(1),
|
||||
Class1.b=IntConstant(2),
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field2;
|
||||
|
||||
/*element: Class1.field3:
|
||||
Class1.a=IntConstant(3),
|
||||
Class1.b=IntConstant(3),
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field3;
|
||||
|
||||
/*element: Class1.field4:initial=IntConstant(4)*/
|
||||
var field4 = 4;
|
||||
|
||||
/*element: Class1.field5:
|
||||
Class1.a=IntConstant(5),
|
||||
Class1.b=IntConstant(5),
|
||||
initial=IntConstant(5)
|
||||
*/
|
||||
var field5 = 5;
|
||||
|
||||
Class1.a()
|
||||
: field1 = 1,
|
||||
field2 = 1,
|
||||
field3 = 3,
|
||||
field5 = 5;
|
||||
|
||||
Class1.b()
|
||||
: field2 = 2,
|
||||
field3 = 3,
|
||||
field5 = 5;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// 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.
|
||||
|
||||
main() {
|
||||
new Class1(0);
|
||||
new Class1(0, 1);
|
||||
new Class2(0);
|
||||
new Class2(0, field2: 1);
|
||||
}
|
||||
|
||||
class Class1 {
|
||||
/*element: Class1.field1:
|
||||
Class1.=?,
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field1;
|
||||
|
||||
/*element: Class1.field2:
|
||||
Class1.=1:IntConstant(2),
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field2;
|
||||
|
||||
/*element: Class1.field3:
|
||||
Class1.=2:IntConstant(3),
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field3;
|
||||
|
||||
Class1(this.field1, [this.field2 = 2, this.field3 = 3]);
|
||||
}
|
||||
|
||||
class Class2 {
|
||||
/*element: Class2.field1:
|
||||
Class2.=?,
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field1;
|
||||
|
||||
/*element: Class2.field2:
|
||||
Class2.=field2:IntConstant(2),
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field2;
|
||||
|
||||
/*element: Class2.field3:
|
||||
Class2.=field3:IntConstant(3),
|
||||
initial=NullConstant
|
||||
*/
|
||||
var field3;
|
||||
|
||||
Class2(this.field1, {this.field2 = 2, this.field3 = 3});
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// 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.
|
||||
|
||||
main() {
|
||||
new Class1();
|
||||
}
|
||||
|
||||
method1() => 1;
|
||||
|
||||
class Class1 {
|
||||
var field1 = method1();
|
||||
var field2 = throw 'foo';
|
||||
var field3 = method1();
|
||||
|
||||
Class1() : field3 = null;
|
||||
}
|
|
@ -57,46 +57,46 @@ class Class1 {
|
|||
}
|
||||
|
||||
class Class2 {
|
||||
/*element: Class2.field1:*/
|
||||
/*element: Class2.field1:Class2.=NullConstant,initial=NullConstant*/
|
||||
var field1;
|
||||
|
||||
/*element: Class2.field2:*/
|
||||
/*element: Class2.field2:Class2.=BoolConstant(true),initial=NullConstant*/
|
||||
var field2;
|
||||
|
||||
/*element: Class2.field3:*/
|
||||
/*element: Class2.field3:Class2.=BoolConstant(false),initial=NullConstant*/
|
||||
var field3;
|
||||
|
||||
/*element: Class2.field4:*/
|
||||
/*element: Class2.field4:Class2.=IntConstant(0),initial=NullConstant*/
|
||||
var field4;
|
||||
|
||||
/*element: Class2.field5:*/
|
||||
/*element: Class2.field5:Class2.=IntConstant(1),initial=NullConstant*/
|
||||
var field5;
|
||||
|
||||
/*element: Class2.field6:*/
|
||||
/*element: Class2.field6:Class2.=StringConstant(""),initial=NullConstant*/
|
||||
var field6;
|
||||
|
||||
/*element: Class2.field7:*/
|
||||
/*element: Class2.field7:Class2.=StringConstant("foo"),initial=NullConstant*/
|
||||
var field7;
|
||||
|
||||
/*element: Class2.field8:*/
|
||||
/*element: Class2.field8:Class2.=DoubleConstant(0.5),initial=NullConstant*/
|
||||
var field8;
|
||||
|
||||
/*element: Class2.field9:*/
|
||||
/*element: Class2.field9:Class2.=ListConstant([]),initial=NullConstant*/
|
||||
var field9;
|
||||
|
||||
/*element: Class2.field10:*/
|
||||
/*element: Class2.field10:Class2.=MapConstant({}),initial=NullConstant*/
|
||||
var field10;
|
||||
|
||||
/*element: Class2.field11:*/
|
||||
/*element: Class2.field11:Class2.=ConstructedConstant(Symbol(_name=StringConstant("foo"))),initial=NullConstant*/
|
||||
var field11;
|
||||
|
||||
/*element: Class2.field12:*/
|
||||
/*element: Class2.field12:Class2.=IntConstant(5),initial=NullConstant*/
|
||||
var field12;
|
||||
|
||||
/*element: Class2.field13:*/
|
||||
/*element: Class2.field13:Class2.=BoolConstant(true),initial=NullConstant*/
|
||||
var field13;
|
||||
|
||||
/*element: Class2.field14:*/
|
||||
/*element: Class2.field14:Class2.=?,initial=NullConstant*/
|
||||
var field14;
|
||||
|
||||
Class2()
|
||||
|
|
Loading…
Reference in a new issue