Chromium Code Reviews| Index: pkg/compiler/lib/src/ssa/builder_kernel.dart |
| diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart |
| index 88cfe1809e999e1aa68ab945d61165da7babd9a7..f805cc87dbf9c59eb13b06ab83b8760c8b3aa93e 100644 |
| --- a/pkg/compiler/lib/src/ssa/builder_kernel.dart |
| +++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart |
| @@ -8,14 +8,14 @@ import '../common.dart'; |
| import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| import '../common/tasks.dart' show CompilerTask; |
| import '../compiler.dart'; |
| +import '../dart_types.dart'; |
| import '../elements/elements.dart'; |
| import '../io/source_information.dart'; |
| import '../js_backend/backend.dart' show JavaScriptBackend; |
| import '../kernel/kernel.dart'; |
| -import '../kernel/kernel_visitor.dart'; |
| -import '../resolution/tree_elements.dart'; |
| import '../tree/dartstring.dart'; |
| import '../types/masks.dart'; |
| +import '../universe/selector.dart'; |
| import 'graph_builder.dart'; |
| import 'kernel_ast_adapter.dart'; |
| @@ -37,23 +37,16 @@ class SsaKernelBuilderTask extends CompilerTask { |
| return measure(() { |
| AstElement element = work.element.implementation; |
| Kernel kernel = backend.kernelTask.kernel; |
| - ir.Procedure function = kernel.functions[element]; |
| - KernelSsaBuilder builder = new KernelSsaBuilder( |
| - function, |
| - element, |
| - work.resolvedAst, |
| - backend.compiler, |
| - work.registry, |
| - sourceInformationFactory, |
| - kernel); |
| + KernelSsaBuilder builder = new KernelSsaBuilder(element, work.resolvedAst, |
| + backend.compiler, work.registry, sourceInformationFactory, kernel); |
| return builder.build(); |
| }); |
| } |
| } |
| class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| - final ir.Procedure function; |
| - final FunctionElement functionElement; |
| + ir.Node target; |
| + final AstElement targetElement; |
| final ResolvedAst resolvedAst; |
| final Compiler compiler; |
| final CodegenRegistry registry; |
| @@ -64,45 +57,79 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| KernelAstAdapter astAdapter; |
| KernelSsaBuilder( |
| - this.function, |
| - this.functionElement, |
| + this.targetElement, |
| this.resolvedAst, |
| this.compiler, |
| this.registry, |
| SourceInformationStrategy sourceInformationFactory, |
| Kernel kernel) { |
| - graph.element = functionElement; |
| + graph.element = targetElement; |
| // TODO(het): Should sourceInformationBuilder be in GraphBuilder? |
| this.sourceInformationBuilder = |
| sourceInformationFactory.createBuilderForContext(resolvedAst); |
| graph.sourceInformation = |
| sourceInformationBuilder.buildVariableDeclaration(); |
| - this.localsHandler = |
| - new LocalsHandler(this, functionElement, null, compiler); |
| + this.localsHandler = new LocalsHandler(this, targetElement, null, compiler); |
| this.astAdapter = new KernelAstAdapter( |
| compiler.backend, |
| resolvedAst, |
| kernel.nodeToAst, |
| kernel.nodeToElement, |
| + kernel.fields, |
| kernel.functions, |
| kernel.classes, |
| kernel.libraries); |
| + Element originTarget = targetElement; |
| + if (originTarget.isPatch) { |
| + originTarget = originTarget.origin; |
| + } |
| + if (originTarget is FunctionElement) { |
| + target = kernel.functions[originTarget]; |
| + } else if (originTarget is FieldElement) { |
| + target = kernel.fields[originTarget]; |
| + } |
| } |
| HGraph build() { |
| // TODO(het): no reason to do this here... |
| HInstruction.idCounter = 0; |
| - if (function.kind == ir.ProcedureKind.Method || |
| - function.kind == ir.ProcedureKind.Operator) { |
| - buildMethod(function, functionElement); |
| + if (target is ir.Procedure) { |
| + buildProcedure(target); |
| + } else if (target is ir.Field) { |
| + buildField(target); |
| + } else if (target is ir.Constructor) { |
| + // TODO(het): Actually handle this correctly |
| + HBasicBlock block = graph.addNewBlock(); |
| + open(graph.entry); |
| + close(new HGoto()).addSuccessor(block); |
| + open(block); |
| + closeAndGotoExit(new HGoto()); |
| + graph.finalize(); |
| + } |
| + assert(graph.isValid()); |
| + return graph; |
| + } |
| + |
| + void buildProcedure(ir.Procedure procedure) { |
| + if (procedure.kind == ir.ProcedureKind.Method || |
| + procedure.kind == ir.ProcedureKind.Operator || |
| + procedure.kind == ir.ProcedureKind.Getter || |
| + procedure.kind == ir.ProcedureKind.Factory) { |
| + buildMethod(procedure); |
| } else { |
| compiler.reporter.internalError( |
| - functionElement, |
| + targetElement, |
| "Unable to convert this kind of Kernel " |
| - "procedure to SSA: ${function.kind}"); |
| + "procedure to SSA: ${procedure.kind}"); |
| } |
| - assert(graph.isValid()); |
| - return graph; |
| + } |
| + |
| + void buildField(ir.Field field) { |
| + openFunction(); |
| + field.initializer.accept(this); |
| + HInstruction value = pop(); |
| + closeAndGotoExit(new HReturn(value, null)); |
| + closeFunction(); |
| } |
| @override |
| @@ -123,17 +150,16 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| } |
| /// Builds a SSA graph for [method]. |
| - void buildMethod(ir.Procedure method, FunctionElement functionElement) { |
| - openFunction(functionElement); |
| + void buildMethod(ir.Procedure method) { |
| + openFunction(); |
| method.function.body.accept(this); |
| closeFunction(); |
| } |
| - // TODO(het): get function element from astAdapter? |
| - void openFunction(FunctionElement functionElement) { |
| + void openFunction() { |
| HBasicBlock block = graph.addNewBlock(); |
| open(graph.entry); |
| - localsHandler.startFunction(functionElement, resolvedAst.node); |
| + localsHandler.startFunction(targetElement, resolvedAst.node); |
| close(new HGoto()).addSuccessor(block); |
| open(block); |
| @@ -145,6 +171,12 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| } |
| @override |
| + void defaultExpression(ir.Expression expression) { |
| + // TODO(het): This is only to get tests working |
| + stack.add(graph.addConstantNull(compiler)); |
| + } |
| + |
| + @override |
| void visitBlock(ir.Block block) { |
| assert(!isAborted()); |
| for (ir.Statement statement in block.statements) { |
| @@ -166,7 +198,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| } |
| @override |
| - visitExpressionStatement(ir.ExpressionStatement exprStatement) { |
| + void visitExpressionStatement(ir.ExpressionStatement exprStatement) { |
| exprStatement.expression.accept(this); |
| pop(); |
| } |
| @@ -189,52 +221,154 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| @override |
| void visitIfStatement(ir.IfStatement ifStatement) { |
| - SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler); |
| - branchBuilder.handleIf( |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); |
| + brancher.handleIf( |
| () => ifStatement.condition.accept(this), |
| () => ifStatement.then.accept(this), |
| () => ifStatement.otherwise?.accept(this)); |
| } |
| @override |
| + void visitConditionalExpression(ir.ConditionalExpression conditional) { |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); |
| + brancher.handleConditional( |
| + () => conditional.condition.accept(this), |
| + () => conditional.then.accept(this), |
| + () => conditional.otherwise.accept(this)); |
| + } |
| + |
| + @override |
| + void visitLogicalExpression(ir.LogicalExpression logicalExpression) { |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); |
| + brancher.handleLogicalBinary(() => logicalExpression.left.accept(this), |
| + () => logicalExpression.right.accept(this), |
| + isAnd: logicalExpression.operator == '&&'); |
| + } |
| + |
| + @override |
| void visitIntLiteral(ir.IntLiteral intLiteral) { |
| stack.add(graph.addConstantInt(intLiteral.value, compiler)); |
| } |
| @override |
| - visitDoubleLiteral(ir.DoubleLiteral doubleLiteral) { |
| + void visitDoubleLiteral(ir.DoubleLiteral doubleLiteral) { |
| stack.add(graph.addConstantDouble(doubleLiteral.value, compiler)); |
| } |
| @override |
| - visitBoolLiteral(ir.BoolLiteral boolLiteral) { |
| + void visitBoolLiteral(ir.BoolLiteral boolLiteral) { |
| stack.add(graph.addConstantBool(boolLiteral.value, compiler)); |
| } |
| @override |
| - visitStringLiteral(ir.StringLiteral stringLiteral) { |
| + void visitStringLiteral(ir.StringLiteral stringLiteral) { |
| stack.add(graph.addConstantString( |
| new DartString.literal(stringLiteral.value), compiler)); |
| } |
| @override |
| - visitSymbolLiteral(ir.SymbolLiteral symbolLiteral) { |
| + void visitSymbolLiteral(ir.SymbolLiteral symbolLiteral) { |
| stack.add(graph.addConstant( |
| astAdapter.getConstantForSymbol(symbolLiteral), compiler)); |
| registry?.registerConstSymbol(symbolLiteral.value); |
| } |
| @override |
| - visitNullLiteral(ir.NullLiteral nullLiteral) { |
| + void visitNullLiteral(ir.NullLiteral nullLiteral) { |
| stack.add(graph.addConstantNull(compiler)); |
| } |
| @override |
| - visitVariableGet(ir.VariableGet variableGet) { |
| + void visitStaticGet(ir.StaticGet staticGet) { |
| + Element element = astAdapter.getElement(staticGet.target); |
|
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
nit: consider adding a variable for target
Membe
Harry Terkelsen
2016/09/14 00:07:24
Done.
|
| + if (staticGet.target is ir.Procedure) { |
| + element = element.declaration; |
| + ir.Procedure target = staticGet.target; |
|
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
(with a variable above, type promotion would work
Harry Terkelsen
2016/09/14 00:07:24
Done.
|
| + if (target.kind == ir.ProcedureKind.Getter) { |
| + // We must invoke the getter |
| + _pushStaticInvocation( |
| + target, const <HInstruction>[], astAdapter.returnTypeOf(target)); |
| + } else { |
| + push(new HStatic(element, astAdapter.inferredTypeOf(staticGet.target))); |
|
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
nit: maybe add a comment that this is a tear-off?
Harry Terkelsen
2016/09/14 00:07:24
Done.
|
| + } |
| + } else { |
| + push(new HStatic(element, astAdapter.inferredTypeOf(staticGet.target))); |
|
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
A couple questions here:
(a) shouldn't this elemen
Harry Terkelsen
2016/09/14 00:07:24
a) Yes. Done
b) Yes, there are more cases that ne
|
| + } |
| + } |
| + |
| + @override |
| + void visitStaticSet(ir.StaticSet staticSet) { |
| + VariableElement field = astAdapter.getElement(staticSet.target); |
| + staticSet.value.accept(this); |
| + HInstruction value = pop(); |
| + add(new HStaticStore(field, value)); |
| + stack.add(value); |
| + } |
| + |
| + @override |
| + void visitPropertyGet(ir.PropertyGet propertyGet) { |
| + propertyGet.receiver.accept(this); |
| + HInstruction receiver = pop(); |
| + |
| + List<HInstruction> inputs = <HInstruction>[]; |
| + bool isIntercepted = astAdapter.isIntercepted(propertyGet); |
| + if (isIntercepted) { |
| + HInterceptor interceptor = _interceptorFor(receiver); |
| + inputs.add(interceptor); |
| + } |
| + inputs.add(receiver); |
| + |
| + TypeMask type = astAdapter.selectorGetterTypeOf(propertyGet); |
| + |
| + push(new HInvokeDynamicGetter(astAdapter.getGetterSelector(propertyGet), |
| + astAdapter.typeOfGet(propertyGet), null, inputs, type)); |
| + } |
| + |
| + @override |
| + void visitVariableGet(ir.VariableGet variableGet) { |
| LocalElement local = astAdapter.getElement(variableGet.variable); |
| stack.add(localsHandler.readLocal(local)); |
| } |
| + @override |
| + void visitVariableSet(ir.VariableSet variableSet) { |
| + variableSet.value.accept(this); |
| + HInstruction value = pop(); |
| + _visitLocalSetter(variableSet.variable, value); |
| + } |
| + |
| + @override |
| + void visitVariableDeclaration(ir.VariableDeclaration declaration) { |
| + LocalElement local = astAdapter.getElement(declaration); |
| + if (declaration.initializer == null) { |
| + HInstruction initialValue = graph.addConstantNull(compiler); |
| + localsHandler.updateLocal(local, initialValue); |
| + } else { |
| + // TODO(het): handle case where the variable is top-level or static |
| + declaration.initializer.accept(this); |
| + HInstruction initialValue = pop(); |
| + |
| + _visitLocalSetter(declaration, initialValue); |
| + |
| + // Ignore value |
| + pop(); |
| + } |
| + } |
| + |
| + void _visitLocalSetter(ir.VariableDeclaration variable, HInstruction value) { |
| + // TODO(het): handle case where the variable is top-level or static |
| + LocalElement local = astAdapter.getElement(variable); |
| + |
| + // Give the value a name if it doesn't have one already. |
| + if (value.sourceElement == null) { |
| + value.sourceElement = local; |
| + } |
| + |
| + stack.add(value); |
| + // TODO(het): check or trust type |
| + localsHandler.updateLocal(local, value); |
| + } |
| + |
| // TODO(het): Also extract type arguments |
| /// Extracts the list of instructions for the expressions in the arguments. |
| List<HInstruction> _visitArguments(ir.Arguments arguments) { |
| @@ -253,12 +387,18 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| } |
| @override |
| - visitStaticInvocation(ir.StaticInvocation invocation) { |
| + void visitStaticInvocation(ir.StaticInvocation invocation) { |
| ir.Procedure target = invocation.target; |
| - bool targetCanThrow = astAdapter.getCanThrow(target); |
| TypeMask typeMask = astAdapter.returnTypeOf(target); |
| - var arguments = _visitArguments(invocation.arguments); |
| + List<HInstruction> arguments = _visitArguments(invocation.arguments); |
| + |
| + _pushStaticInvocation(target, arguments, typeMask); |
| + } |
| + |
| + void _pushStaticInvocation( |
| + ir.Node target, List<HInstruction> arguments, TypeMask typeMask) { |
| + bool targetCanThrow = astAdapter.getCanThrow(target); |
| HInstruction instruction = new HInvokeStatic( |
| astAdapter.getElement(target).declaration, arguments, typeMask, |
| @@ -270,7 +410,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| // TODO(het): Decide when to inline |
| @override |
| - visitMethodInvocation(ir.MethodInvocation invocation) { |
| + void visitMethodInvocation(ir.MethodInvocation invocation) { |
| invocation.receiver.accept(this); |
| HInstruction receiver = pop(); |
| @@ -281,9 +421,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| bool isIntercepted = astAdapter.isIntercepted(invocation); |
| if (isIntercepted) { |
| - HInterceptor interceptor = |
| - new HInterceptor(receiver, backend.nonNullType); |
| - add(interceptor); |
| + HInterceptor interceptor = _interceptorFor(receiver); |
| inputs.add(interceptor); |
| } |
| inputs.addAll(arguments); |
| @@ -294,13 +432,92 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| astAdapter.typeOfInvocation(invocation), inputs, type, isIntercepted)); |
| } |
| + HInterceptor _interceptorFor(HInstruction intercepted) { |
| + HInterceptor interceptor = |
| + new HInterceptor(intercepted, backend.nonNullType); |
| + add(interceptor); |
| + return interceptor; |
| + } |
| + |
| + ir.Class containingClass(ir.TreeNode node) { |
|
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
nit => make static and private?
Harry Terkelsen
2016/09/14 00:07:24
Done.
|
| + while (node != null) { |
| + if (node is ir.Class) return node; |
| + node = node.parent; |
| + } |
| + return null; |
| + } |
| + |
| + @override |
| + void visitSuperMethodInvocation(ir.SuperMethodInvocation invocation) { |
| + List<HInstruction> arguments = _visitArguments(invocation.arguments); |
| + HInstruction receiver = localsHandler.readThis(); |
| + Selector selector = astAdapter.getSelector(invocation); |
| + ir.Class surroundingClass = containingClass(invocation); |
| + |
| + List<HInstruction> inputs = <HInstruction>[]; |
| + if (astAdapter.isIntercepted(invocation)) { |
| + inputs.add(_interceptorFor(receiver)); |
| + } |
| + inputs.add(receiver); |
| + inputs.addAll(arguments); |
| + |
| + HInstruction instruction = new HInvokeSuper( |
| + astAdapter.getElement(invocation.interfaceTarget), |
| + astAdapter.getElement(surroundingClass), |
| + selector, |
| + inputs, |
| + astAdapter.returnTypeOf(invocation.interfaceTarget), |
| + null, |
| + isSetter: selector.isSetter || selector.isIndexSet); |
| + instruction.sideEffects = |
| + compiler.world.getSideEffectsOfSelector(selector, null); |
| + push(instruction); |
| + } |
| + |
| + @override |
| + void visitConstructorInvocation(ir.ConstructorInvocation invocation) { |
| + ir.Constructor target = invocation.target; |
| + List<HInstruction> arguments = _visitArguments(invocation.arguments); |
| + TypeMask typeMask = new TypeMask.nonNullExact( |
| + astAdapter.getElement(target.enclosingClass), compiler.world); |
| + _pushStaticInvocation(target, arguments, typeMask); |
| + } |
| + |
| + @override |
| + void visitIsExpression(ir.IsExpression isExpression) { |
| + isExpression.operand.accept(this); |
| + HInstruction expression = pop(); |
| + |
| + DartType type = astAdapter.getDartType(isExpression.type); |
| + |
| + if (backend.hasDirectCheckFor(type)) { |
| + push(new HIs.direct(type, expression, backend.boolType)); |
| + return; |
| + } |
| + |
| + // The interceptor is not always needed. It is removed by optimization |
| + // when the receiver type or tested type permit. |
| + HInterceptor interceptor = _interceptorFor(expression); |
| + push(new HIs.raw(type, expression, interceptor, backend.boolType)); |
| + } |
| + |
| + @override |
| + void visitThrow(ir.Throw throwNode) { |
| + throwNode.expression.accept(this); |
| + HInstruction expression = pop(); |
| + if (isReachable) { |
| + push(new HThrowExpression(expression, null)); |
| + isReachable = false; |
| + } |
| + } |
| + |
| @override |
| - visitThisExpression(ir.ThisExpression thisExpression) { |
| + void visitThisExpression(ir.ThisExpression thisExpression) { |
| stack.add(localsHandler.readThis()); |
| } |
| @override |
| - visitNot(ir.Not not) { |
| + void visitNot(ir.Not not) { |
| not.operand.accept(this); |
| push(new HNot(popBoolified(), backend.boolType)); |
| } |