diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart index 9d89aca9d6c..cac5f104513 100644 --- a/pkg/compiler/lib/src/dart2js.dart +++ b/pkg/compiler/lib/src/dart2js.dart @@ -290,7 +290,9 @@ Future compile(List 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; diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart index 0a8b0269312..fd1a4e09ab6 100644 --- a/pkg/compiler/lib/src/ssa/builder_kernel.dart +++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart @@ -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 fieldValues = {}; List constructorChain = []; - _buildInitializers(constructor, constructorChain, fieldValues); + _buildInitializers(node, constructorChain, fieldValues); List constructorArguments = []; // 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 fields = []; _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 typeArguments = []; - 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 parameterMap = {}; 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. diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart index 5b33fe2e491..66260957b9d 100644 --- a/pkg/compiler/lib/src/ssa/locals_handler.dart +++ b/pkg/compiler/lib/src/ssa/locals_handler.dart @@ -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); diff --git a/tests/compiler/dart2js/kernel/run_from_dill_test.dart b/tests/compiler/dart2js/kernel/run_from_dill_test.dart index 4d73a3599dc..eed89d95397 100644 --- a/tests/compiler/dart2js/kernel/run_from_dill_test.dart +++ b/tests/compiler/dart2js/kernel/run_from_dill_test.dart @@ -20,12 +20,22 @@ import '../serialization/helper.dart'; const SOURCE = const { 'main.dart': ''' +import "package:expect/expect.dart"; + +class A { + 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().foo(), int); } ''' }; @@ -68,12 +78,11 @@ Future mainInternal(List 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 --------------------------------------------');