| 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..3eb696af225dc25b6d65c3249b15e748d6f9dd35 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,150 @@ 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) {
|
| + var staticTarget = staticGet.target;
|
| + Element element = astAdapter.getElement(staticTarget).declaration;
|
| + if (staticTarget is ir.Procedure &&
|
| + staticTarget.kind == ir.ProcedureKind.Getter) {
|
| + // Invoke the getter
|
| + _pushStaticInvocation(
|
| + target, const <HInstruction>[], astAdapter.returnTypeOf(target));
|
| + } else {
|
| + push(new HStatic(element, astAdapter.inferredTypeOf(staticTarget)));
|
| + }
|
| + }
|
| +
|
| + @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 +383,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 +406,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 +417,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 +428,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;
|
| + }
|
| +
|
| + static ir.Class _containingClass(ir.TreeNode node) {
|
| + 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));
|
| }
|
|
|