Don't create HParameterValue nodes for type arguments when inlining

Change-Id: If44fc4cbb39336f7ac01b906702f5aaa2ed1cd90
Reviewed-on: https://dart-review.googlesource.com/28721
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Johnni Winther 2017-12-13 10:10:23 +00:00
parent a1f5474f80
commit 5599c80edd
4 changed files with 88 additions and 78 deletions

View file

@ -290,7 +290,9 @@ Future<api.CompilationResult> compile(List<String> argv,
void setUseKernel(String argument) {
useKernel = true;
// TODO(sigmund): remove once we support inlining with `useKernel`.
options.add(Flags.disableInlining);
if (disableInliningForKernel) {
options.add(Flags.disableInlining);
}
passThrough(argument);
}
@ -1145,3 +1147,6 @@ class _BufferedOutputSink implements api.OutputSink {
// Do nothing.
}
}
// TODO(johnniwinther): Remove once we support inlining with `useKernel`.
bool disableInliningForKernel = true;

View file

@ -190,9 +190,10 @@ class KernelSsaGraphBuilder extends ir.Visitor
if (target is ir.Procedure) {
if (target.isExternal) {
buildExternalFunctionNode(
_ensureDefaultArgumentValues(target.function));
targetElement, _ensureDefaultArgumentValues(target.function));
} else {
buildFunctionNode(_ensureDefaultArgumentValues(target.function));
buildFunctionNode(
targetElement, _ensureDefaultArgumentValues(target.function));
}
} else if (target is ir.Field) {
if (handleConstantField(targetElement, registry, closedWorld)) {
@ -204,9 +205,11 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
buildField(target);
} else if (target is ir.FunctionExpression) {
buildFunctionNode(_ensureDefaultArgumentValues(target.function));
buildFunctionNode(
targetElement, _ensureDefaultArgumentValues(target.function));
} else if (target is ir.FunctionDeclaration) {
buildFunctionNode(_ensureDefaultArgumentValues(target.function));
buildFunctionNode(
targetElement, _ensureDefaultArgumentValues(target.function));
} else {
throw 'No case implemented to handle target: '
'$target for $targetElement';
@ -215,7 +218,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
case MemberKind.constructor:
ir.Constructor constructor = definition.node;
_ensureDefaultArgumentValues(constructor.function);
buildConstructor(constructor);
buildConstructor(targetElement, constructor);
break;
case MemberKind.constructorBody:
ir.Constructor constructor = definition.node;
@ -284,37 +287,37 @@ class KernelSsaGraphBuilder extends ir.Visitor
return _elementMap.getFieldConstantValue(field);
}
void buildField(ir.Field field) {
_inLazyInitializerExpression = field.isStatic;
openFunction();
if (field.isInstanceMember && options.enableTypeAssertions) {
void buildField(ir.Field node) {
_inLazyInitializerExpression = node.isStatic;
FieldEntity field = _elementMap.getMember(node);
openFunction(field);
if (node.isInstanceMember && options.enableTypeAssertions) {
HInstruction thisInstruction = localsHandler.readThis(
sourceInformation: _sourceInformationBuilder.buildGet(field));
sourceInformation: _sourceInformationBuilder.buildGet(node));
// Use dynamic type because the type computed by the inferrer is
// narrowed to the type annotation.
FieldEntity fieldEntity = _elementMap.getMember(field);
HInstruction parameter =
new HParameterValue(fieldEntity, commonMasks.dynamicType);
new HParameterValue(field, commonMasks.dynamicType);
// Add the parameter as the last instruction of the entry block.
// If the method is intercepted, we want the actual receiver
// to be the first parameter.
graph.entry.addBefore(graph.entry.last, parameter);
HInstruction value = typeBuilder.potentiallyCheckOrTrustType(
parameter, _getDartTypeIfValid(field.type));
add(new HFieldSet(fieldEntity, thisInstruction, value));
parameter, _getDartTypeIfValid(node.type));
add(new HFieldSet(field, thisInstruction, value));
} else {
if (field.initializer != null) {
field.initializer.accept(this);
if (node.initializer != null) {
node.initializer.accept(this);
HInstruction fieldValue = pop();
HInstruction checkInstruction = typeBuilder.potentiallyCheckOrTrustType(
fieldValue, _getDartTypeIfValid(field.type));
fieldValue, _getDartTypeIfValid(node.type));
stack.add(checkInstruction);
} else {
stack.add(graph.addConstantNull(closedWorld));
}
HInstruction value = pop();
closeAndGotoExit(
new HReturn(value, _sourceInformationBuilder.buildReturn(field)));
new HReturn(value, _sourceInformationBuilder.buildReturn(node)));
}
closeFunction();
}
@ -344,16 +347,20 @@ class KernelSsaGraphBuilder extends ir.Visitor
/// parameters. If the class has type parameters but does not need them, bind
/// to `dynamic` (represented as `null`) so the bindings are available for
/// building types up the inheritance chain of generative constructors.
void _addClassTypeVariablesIfNeeded(ir.Member constructor) {
ir.Class enclosing = constructor.enclosingClass;
ClassEntity cls = _elementMap.getClass(enclosing);
bool needParameters;
enclosing.typeParameters.forEach((ir.TypeParameter typeParameter) {
TypeVariableType typeVariableType =
_elementMap.getDartType(new ir.TypeParameterType(typeParameter));
void _addClassTypeVariablesIfNeeded(MemberEntity member) {
if (!member.isConstructor && member is! ConstructorBodyEntity) {
return;
}
ClassEntity cls = member.enclosingClass;
InterfaceType thisType = _elementMap.elementEnvironment.getThisType(cls);
if (thisType.typeArguments.isEmpty) {
return;
}
bool needsRti = rtiNeed.classNeedsRti(cls);
thisType.typeArguments.forEach((DartType _typeVariable) {
TypeVariableType typeVariableType = _typeVariable;
HInstruction param;
needParameters ??= rtiNeed.classNeedsRti(cls);
if (needParameters) {
if (needsRti) {
param = addParameter(typeVariableType.element, commonMasks.nonNullType);
} else {
// Unused, so bind to `dynamic`.
@ -391,34 +398,31 @@ class KernelSsaGraphBuilder extends ir.Visitor
/// implication is that a class cannot be extended or mixed-in twice. If we in
/// future support repeated uses of a mixin class, we should do so by cloning
/// the mixin class in the Kernel input.
void buildConstructor(ir.Constructor constructor) {
void buildConstructor(ConstructorEntity constructor, ir.Constructor node) {
SourceInformation sourceInformation =
_sourceInformationBuilder.buildCreate(constructor);
ir.Class constructedClass = constructor.enclosingClass;
_sourceInformationBuilder.buildCreate(node);
ClassEntity cls = constructor.enclosingClass;
if (_inliningStack.isEmpty) {
openFunction(constructor.function);
openFunction(constructor, node.function);
}
_addClassTypeVariablesIfNeeded(constructor);
_potentiallyAddFunctionParameterTypeChecks(constructor.function);
// [fieldValues] accumulates the field initializer values, which may be
// overwritten by initializer-list initializers.
Map<FieldEntity, HInstruction> fieldValues = <FieldEntity, HInstruction>{};
List<ir.Constructor> constructorChain = <ir.Constructor>[];
_buildInitializers(constructor, constructorChain, fieldValues);
_buildInitializers(node, constructorChain, fieldValues);
List<HInstruction> constructorArguments = <HInstruction>[];
// Doing this instead of fieldValues.forEach because we haven't defined the
// order of the arguments here. We can define that with JElements.
ClassEntity cls = _elementMap.getClass(constructedClass);
bool isCustomElement = nativeData.isNativeOrExtendsNative(cls) &&
!nativeData.isJsInteropClass(cls);
InterfaceType thisType = _elementMap.elementEnvironment.getThisType(cls);
List<FieldEntity> fields = <FieldEntity>[];
_worldBuilder.forEachInstanceField(cls,
(ClassEntity enclosingClass, FieldEntity member) {
var value = fieldValues[member];
HInstruction value = fieldValues[member];
if (value == null) {
assert(isCustomElement || reporter.hasReportedError,
'No initializer value for field ${member}');
@ -450,10 +454,11 @@ class KernelSsaGraphBuilder extends ir.Visitor
// Read the values of the type arguments and create a HTypeInfoExpression
// to set on the newly create object.
List<HInstruction> typeArguments = <HInstruction>[];
for (ir.DartType typeParameter
in constructedClass.thisType.typeArguments) {
HInstruction argument = localsHandler.readLocal(localsHandler
.getTypeVariableAsLocal(_elementMap.getDartType(typeParameter)));
InterfaceType thisType =
_elementMap.elementEnvironment.getThisType(cls);
for (DartType typeVariable in thisType.typeArguments) {
HInstruction argument = localsHandler
.readLocal(localsHandler.getTypeVariableAsLocal(typeVariable));
typeArguments.add(argument);
}
@ -534,15 +539,12 @@ class KernelSsaGraphBuilder extends ir.Visitor
ConstructorBodyEntity constructorBody =
_elementMap.getConstructorBody(body);
if (!isCustomElement && // TODO(13836): Fix inlining.
_tryInlineMethod(constructorBody, null, null, bodyCallInputs,
constructor, sourceInformation)) {
_tryInlineMethod(constructorBody, null, null, bodyCallInputs, node,
sourceInformation)) {
pop();
} else {
_invokeConstructorBody(
body,
bodyCallInputs,
_sourceInformationBuilder
.buildDeclaration(_elementMap.getMember(constructor)));
_invokeConstructorBody(body, bodyCallInputs,
_sourceInformationBuilder.buildDeclaration(constructor));
}
});
}
@ -848,31 +850,23 @@ class KernelSsaGraphBuilder extends ir.Visitor
/// Builds generative constructor body.
void buildConstructorBody(ir.Constructor constructor) {
openFunction(constructor.function);
_addClassTypeVariablesIfNeeded(constructor);
_potentiallyAddFunctionParameterTypeChecks(constructor.function);
openFunction(
_elementMap.getConstructorBody(constructor), constructor.function);
constructor.function.body.accept(this);
closeFunction();
}
/// Builds a SSA graph for FunctionNodes, found in FunctionExpressions and
/// Procedures.
void buildFunctionNode(ir.FunctionNode functionNode) {
openFunction(functionNode);
ir.TreeNode parent = functionNode.parent;
if (parent is ir.Procedure && parent.kind == ir.ProcedureKind.Factory) {
_addClassTypeVariablesIfNeeded(parent);
}
_potentiallyAddFunctionParameterTypeChecks(functionNode);
void buildFunctionNode(
FunctionEntity function, ir.FunctionNode functionNode) {
openFunction(function, functionNode);
// If [functionNode] is `operator==` we explicitly add a null check at the
// beginning of the method. This is to avoid having call sites do the null
// check.
if (parent is ir.Procedure &&
parent.kind == ir.ProcedureKind.Operator &&
parent.name.name == '==') {
FunctionEntity method = _elementMap.getMethod(parent);
if (!_commonElements.operatorEqHandlesNullArgument(method)) {
if (function.name == '==') {
if (!_commonElements.operatorEqHandlesNullArgument(function)) {
handleIf(
visitCondition: () {
HParameterValue parameter = parameters.values.first;
@ -921,16 +915,12 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
/// Builds a SSA graph for FunctionNodes of external methods.
void buildExternalFunctionNode(ir.FunctionNode functionNode) {
void buildExternalFunctionNode(
FunctionEntity function, ir.FunctionNode functionNode) {
// TODO(johnniwinther): Non-js-interop external functions should
// throw a runtime error.
assert(functionNode.body == null);
openFunction(functionNode);
ir.TreeNode parent = functionNode.parent;
if (parent is ir.Procedure && parent.kind == ir.ProcedureKind.Factory) {
_addClassTypeVariablesIfNeeded(parent);
}
_potentiallyAddFunctionParameterTypeChecks(functionNode);
openFunction(function, functionNode);
if (closedWorld.nativeData.isNativeMember(targetElement)) {
nativeEmitter.nativeMethods.add(targetElement);
@ -1009,7 +999,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
}
void openFunction([ir.FunctionNode function]) {
void openFunction(MemberEntity member, [ir.FunctionNode function]) {
Map<Local, TypeMask> parameterMap = <Local, TypeMask>{};
if (function != null) {
void handleParameter(ir.VariableDeclaration node) {
@ -1038,6 +1028,13 @@ class KernelSsaGraphBuilder extends ir.Visitor
close(new HGoto()).addSuccessor(block);
open(block);
_addClassTypeVariablesIfNeeded(member);
if (function != null) {
_potentiallyAddFunctionParameterTypeChecks(function);
}
_insertTraceCall(member);
_insertCoverageCall(member);
}
void closeFunction() {
@ -4022,6 +4019,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
TypeMask typeMask = new TypeMask.nonNullExact(cls, closedWorld);
InterfaceType instanceType = _elementMap.createInterfaceType(
target.enclosingClass, node.arguments.types);
instanceType = localsHandler.substInContext(instanceType);
if (_checkAllTypeVariableBounds(
constructor, instanceType, sourceInformation)) {
@ -4044,7 +4042,6 @@ class KernelSsaGraphBuilder extends ir.Visitor
if (closedWorld.rtiNeed.classNeedsRti(cls)) {
_addTypeArguments(arguments, node.arguments, sourceInformation);
}
instanceType = localsHandler.substInContext(instanceType);
addImplicitInstantiation(instanceType);
_pushStaticInvocation(constructor, arguments, typeMask,
sourceInformation: sourceInformation, instanceType: instanceType);
@ -4692,7 +4689,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
MemberDefinition definition = _elementMap.getMemberDefinition(function);
switch (definition.kind) {
case MemberKind.constructor:
buildConstructor(definition.node);
buildConstructor(function, definition.node);
return;
case MemberKind.constructorBody:
ir.Constructor constructor = definition.node;
@ -4738,7 +4735,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
return _allInlinedFunctionsCalledOnce && _isFunctionCalledOnce(element);
}
void _insertTraceCall(FunctionEntity element) {
void _insertTraceCall(MemberEntity element) {
if (JavaScriptBackend.TRACE_METHOD == 'console') {
if (element == commonElements.traceHelper) return;
n(e) => e == null ? '' : e.name;
@ -4750,7 +4747,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
}
}
void _insertCoverageCall(FunctionEntity element) {
void _insertCoverageCall(MemberEntity element) {
if (JavaScriptBackend.TRACE_METHOD == 'post') {
if (element == commonElements.traceHelper) return;
// TODO(sigmund): create a better uuid for elements.

View file

@ -76,7 +76,6 @@ class LocalsHandler {
/// Substituted type variables occurring in [type] into the context of
/// [contextClass].
DartType substInContext(DartType type) {
//DartType input = type;
DartType newType = type;
if (instanceType != null) {
ClassEntity typeContext = DartTypes.getClassContext(newType);

View file

@ -20,12 +20,22 @@ import '../serialization/helper.dart';
const SOURCE = const {
'main.dart': '''
import "package:expect/expect.dart";
class A<T> {
foo() {
bar() => T;
return bar();
}
}
main() {
for (int i = 0; i < 10; i++) {
if (i == 5) continue;
print('Hello World: \$i!');
if (i == 7) break;
}
Expect.equals(new A<int>().foo(), int);
}
'''
};
@ -68,12 +78,11 @@ Future<ResultKind> mainInternal(List<String> args,
dillFile.toString(),
'-o$output',
Flags.useKernel,
Flags.disableTypeInference,
Flags.disableInlining,
Flags.enableAssertMessage
];
print('Running: dart2js ${dart2jsArgs.join(' ')}');
dart2js.disableInliningForKernel = false;
await dart2js.internalMain(dart2jsArgs);
print('---- run from dill --------------------------------------------');