mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:18:13 +00:00
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:
parent
a1f5474f80
commit
5599c80edd
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 --------------------------------------------');
|
||||
|
|
Loading…
Reference in a new issue