| // Copyright (c) 2016, 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. |
| |
| import 'package:kernel/ast.dart' as ir; |
| |
| import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| import '../common/tasks.dart' show CompilerTask; |
| import '../compiler.dart'; |
| import '../diagnostics/spannable.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 'graph_builder.dart'; |
| import 'kernel_ast_adapter.dart'; |
| import 'locals_handler.dart'; |
| import 'nodes.dart'; |
| |
| class SsaKernelBuilderTask extends CompilerTask { |
| final JavaScriptBackend backend; |
| final SourceInformationStrategy sourceInformationFactory; |
| |
| String get name => 'SSA kernel builder'; |
| |
| SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) |
| : backend = backend, |
| super(backend.compiler.measurer); |
| |
| HGraph build(CodegenWorkItem work) { |
| return measure(() { |
| AstElement element = work.element.implementation; |
| TreeElements treeElements = work.resolvedAst.elements; |
| Kernel kernel = new Kernel(backend.compiler); |
| KernelVisitor visitor = new KernelVisitor(element, treeElements, kernel); |
| IrFunction function; |
| try { |
| function = visitor.buildFunction(); |
| } catch (e) { |
| throw "Failed to convert to Kernel IR: $e"; |
| } |
| KernelSsaBuilder builder = new KernelSsaBuilder( |
| function, |
| element, |
| work.resolvedAst, |
| backend.compiler, |
| work.registry, |
| sourceInformationFactory, |
| visitor); |
| return builder.build(); |
| }); |
| } |
| } |
| |
| class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| final IrFunction function; |
| final FunctionElement functionElement; |
| final ResolvedAst resolvedAst; |
| final Compiler compiler; |
| final CodegenRegistry registry; |
| |
| JavaScriptBackend get backend => compiler.backend; |
| |
| LocalsHandler localsHandler; |
| SourceInformationBuilder sourceInformationBuilder; |
| KernelAstAdapter astAdapter; |
| |
| KernelSsaBuilder( |
| this.function, |
| this.functionElement, |
| this.resolvedAst, |
| this.compiler, |
| this.registry, |
| SourceInformationStrategy sourceInformationFactory, |
| KernelVisitor visitor) { |
| graph.element = functionElement; |
| // 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.astAdapter = |
| new KernelAstAdapter(compiler.backend, resolvedAst, visitor.nodeToAst); |
| } |
| |
| HGraph build() { |
| // TODO(het): no reason to do this here... |
| HInstruction.idCounter = 0; |
| if (function.kind == ir.ProcedureKind.Method) { |
| buildMethod(function, functionElement); |
| } else { |
| compiler.reporter.internalError( |
| functionElement, |
| "Unable to convert this kind of Kernel " |
| "procedure to SSA: ${function.kind}"); |
| } |
| assert(graph.isValid()); |
| return graph; |
| } |
| |
| /// Builds a SSA graph for [method]. |
| void buildMethod(IrFunction method, FunctionElement functionElement) { |
| openFunction(method, functionElement); |
| method.node.body.accept(this); |
| closeFunction(); |
| } |
| |
| void openFunction(IrFunction method, FunctionElement functionElement) { |
| HBasicBlock block = graph.addNewBlock(); |
| open(graph.entry); |
| // TODO(het): Register parameters with a locals handler |
| localsHandler.startFunction(functionElement, resolvedAst.node); |
| close(new HGoto()).addSuccessor(block); |
| |
| open(block); |
| } |
| |
| void closeFunction() { |
| if (!isAborted()) closeAndGotoExit(new HGoto()); |
| graph.finalize(); |
| } |
| |
| @override |
| void visitBlock(ir.Block block) { |
| assert(!isAborted()); |
| for (ir.Statement statement in block.statements) { |
| statement.accept(this); |
| if (!isReachable) { |
| // The block has been aborted by a return or a throw. |
| if (stack.isNotEmpty) { |
| compiler.reporter.internalError( |
| NO_LOCATION_SPANNABLE, 'Non-empty instruction stack.'); |
| } |
| return; |
| } |
| } |
| assert(!current.isClosed()); |
| if (stack.isNotEmpty) { |
| compiler.reporter |
| .internalError(NO_LOCATION_SPANNABLE, 'Non-empty instruction stack'); |
| } |
| } |
| |
| @override |
| void visitReturnStatement(ir.ReturnStatement returnStatement) { |
| HInstruction value; |
| if (returnStatement.expression == null) { |
| value = graph.addConstantNull(compiler); |
| } else { |
| returnStatement.expression.accept(this); |
| value = pop(); |
| // TODO(het): Check or trust the type of value |
| } |
| // TODO(het): Add source information |
| // TODO(het): Set a return value instead of closing the function when we |
| // support inlining. |
| closeAndGotoExit(new HReturn(value, null)); |
| } |
| |
| @override |
| void visitIntLiteral(ir.IntLiteral intLiteral) { |
| stack.add(graph.addConstantInt(intLiteral.value, compiler)); |
| } |
| |
| @override |
| visitDoubleLiteral(ir.DoubleLiteral doubleLiteral) { |
| stack.add(graph.addConstantDouble(doubleLiteral.value, compiler)); |
| } |
| |
| @override |
| visitBoolLiteral(ir.BoolLiteral boolLiteral) { |
| stack.add(graph.addConstantBool(boolLiteral.value, compiler)); |
| } |
| |
| @override |
| visitStringLiteral(ir.StringLiteral stringLiteral) { |
| stack.add(graph.addConstantString( |
| new DartString.literal(stringLiteral.value), compiler)); |
| } |
| |
| @override |
| visitSymbolLiteral(ir.SymbolLiteral symbolLiteral) { |
| stack.add( |
| graph.addConstant(astAdapter.getConstantFor(symbolLiteral), compiler)); |
| registry?.registerConstSymbol(symbolLiteral.value); |
| } |
| |
| @override |
| visitNullLiteral(ir.NullLiteral nullLiteral) { |
| stack.add(graph.addConstantNull(compiler)); |
| } |
| } |