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)); |
} |