kernel -> ssa: support static invocations and variable gets

R=sigmund@google.com

Review URL: https://codereview.chromium.org/2290893002 .
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 2dc4895..83f22ab 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -4899,7 +4899,7 @@
       instruction = new HInvokeStatic(element.declaration, arguments, typeMask,
           targetCanThrow: targetCanThrow)
         ..sourceInformation = sourceInformation;
-      if (!currentInlinedInstantiations.isEmpty) {
+      if (currentInlinedInstantiations.isNotEmpty) {
         instruction.instantiatedTypes =
             new List<DartType>.from(currentInlinedInstantiations);
       }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 8879413..9c91c0f 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -15,6 +15,7 @@
 import '../kernel/kernel_visitor.dart';
 import '../resolution/tree_elements.dart';
 import '../tree/dartstring.dart';
+import '../types/masks.dart';
 
 import 'graph_builder.dart';
 import 'kernel_ast_adapter.dart';
@@ -50,7 +51,8 @@
           backend.compiler,
           work.registry,
           sourceInformationFactory,
-          visitor);
+          visitor,
+          kernel);
       return builder.build();
     });
   }
@@ -76,7 +78,8 @@
       this.compiler,
       this.registry,
       SourceInformationStrategy sourceInformationFactory,
-      KernelVisitor visitor) {
+      KernelVisitor visitor,
+      Kernel kernel) {
     graph.element = functionElement;
     // TODO(het): Should sourceInformationBuilder be in GraphBuilder?
     this.sourceInformationBuilder =
@@ -85,8 +88,8 @@
         sourceInformationBuilder.buildVariableDeclaration();
     this.localsHandler =
         new LocalsHandler(this, functionElement, null, compiler);
-    this.astAdapter =
-        new KernelAstAdapter(compiler.backend, resolvedAst, visitor.nodeToAst);
+    this.astAdapter = new KernelAstAdapter(compiler.backend, resolvedAst,
+        visitor.nodeToAst, visitor.nodeToElement, kernel.functions);
   }
 
   HGraph build() {
@@ -186,8 +189,8 @@
 
   @override
   visitSymbolLiteral(ir.SymbolLiteral symbolLiteral) {
-    stack.add(
-        graph.addConstant(astAdapter.getConstantFor(symbolLiteral), compiler));
+    stack.add(graph.addConstant(
+        astAdapter.getConstantForSymbol(symbolLiteral), compiler));
     registry?.registerConstSymbol(symbolLiteral.value);
   }
 
@@ -195,4 +198,41 @@
   visitNullLiteral(ir.NullLiteral nullLiteral) {
     stack.add(graph.addConstantNull(compiler));
   }
+
+  @override
+  visitVariableGet(ir.VariableGet variableGet) {
+    LocalElement local = astAdapter.getElement(variableGet.variable);
+    stack.add(localsHandler.readLocal(local));
+  }
+
+  @override
+  visitStaticInvocation(ir.StaticInvocation invocation) {
+    List<HInstruction> inputs = <HInstruction>[];
+
+    for (ir.Expression argument in invocation.arguments.positional) {
+      argument.accept(this);
+      inputs.add(pop());
+    }
+    for (ir.NamedExpression argument in invocation.arguments.named) {
+      argument.value.accept(this);
+      inputs.add(pop());
+    }
+
+    ir.Procedure target = invocation.target;
+    bool targetCanThrow = astAdapter.getCanThrow(target);
+    TypeMask typeMask = astAdapter.returnTypeOf(target);
+
+    HInstruction instruction = new HInvokeStatic(
+        astAdapter.getElement(target).declaration, inputs, typeMask,
+        targetCanThrow: targetCanThrow);
+    instruction.sideEffects = astAdapter.getSideEffects(target);
+
+    push(instruction);
+  }
+
+  @override
+  visitExpressionStatement(ir.ExpressionStatement exprStatement) {
+    exprStatement.expression.accept(this);
+    pop();
+  }
 }
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index f5d271f..2076899 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -9,23 +9,53 @@
 import '../elements/elements.dart';
 import '../js_backend/js_backend.dart';
 import '../tree/tree.dart' as ast;
+import '../types/masks.dart';
+import '../universe/side_effects.dart';
+
+import 'types.dart';
 
 /// A helper class that abstracts all accesses of the AST from Kernel nodes.
 ///
 /// The goal is to remove all need for the AST from the Kernel SSA builder.
 class KernelAstAdapter {
-  final JavaScriptBackend backend;
-  final ResolvedAst resolvedAst;
-  final Map<ir.Node, ast.Node> nodeToAst;
+  final JavaScriptBackend _backend;
+  final ResolvedAst _resolvedAst;
+  final Map<ir.Node, ast.Node> _nodeToAst;
+  final Map<ir.Node, Element> _nodeToElement;
 
-  KernelAstAdapter(this.backend, this.resolvedAst, this.nodeToAst);
+  KernelAstAdapter(this._backend, this._resolvedAst, this._nodeToAst,
+      this._nodeToElement, Map<FunctionElement, ir.Member> functions) {
+    for (FunctionElement functionElement in functions.keys) {
+      _nodeToElement[functions[functionElement]] = functionElement;
+    }
+  }
 
-  ConstantValue getConstantFor(ir.Node node) {
-    ast.Node astNode = nodeToAst[node];
-    ConstantValue constantValue = backend.constants
-        .getConstantValueForNode(astNode, resolvedAst.elements);
+  ConstantValue getConstantForSymbol(ir.SymbolLiteral node) {
+    ast.Node astNode = _nodeToAst[node];
+    ConstantValue constantValue = _backend.constants
+        .getConstantValueForNode(astNode, _resolvedAst.elements);
     assert(invariant(astNode, constantValue != null,
         message: 'No constant computed for $node'));
     return constantValue;
   }
+
+  Element getElement(ir.Node node) {
+    Element result = _nodeToElement[node];
+    assert(result != null);
+    return result;
+  }
+
+  bool getCanThrow(ir.Procedure procedure) {
+    FunctionElement function = getElement(procedure);
+    return !_backend.compiler.world.getCannotThrow(function);
+  }
+
+  TypeMask returnTypeOf(ir.Procedure node) {
+    return TypeMaskFactory.inferredReturnTypeForElement(
+        getElement(node), _backend.compiler);
+  }
+
+  SideEffects getSideEffects(ir.Node node) {
+    return _backend.compiler.world.getSideEffectsOfElement(getElement(node));
+  }
 }
diff --git a/tests/compiler/dart2js/kernel/helper.dart b/tests/compiler/dart2js/kernel/helper.dart
index 37dfe15..30512d8 100644
--- a/tests/compiler/dart2js/kernel/helper.dart
+++ b/tests/compiler/dart2js/kernel/helper.dart
@@ -36,5 +36,5 @@
 Future check(String code, {String entry: 'main'}) async {
   var original = await compile(code, entry: entry, useKernel: false);
   var kernel = await compile(code, entry: entry, useKernel: true);
-  expect(original, kernel);
+  expect(kernel, original);
 }
diff --git a/tests/compiler/dart2js/kernel/simple_function_test.dart b/tests/compiler/dart2js/kernel/simple_function_test.dart
index c252716..5b1985d 100644
--- a/tests/compiler/dart2js/kernel/simple_function_test.dart
+++ b/tests/compiler/dart2js/kernel/simple_function_test.dart
@@ -5,27 +5,39 @@
 main() {
   group('compile function that returns a value', () {
     test('constant int', () {
-      return check("main() { return 1; }");
+      return check('main() { return 1; }');
     });
 
     test('constant double', () {
-      return check("main() { return 1.0; }");
+      return check('main() { return 1.0; }');
     });
 
     test('constant string', () {
-      return check("main() { return 'hello'; }");
+      return check('main() { return "hello"; }');
     });
 
     test('constant bool', () {
-      return check("main() { return true; }");
+      return check('main() { return true; }');
     });
 
     test('constant symbol', () {
-      return check("main() { return #hello; }");
+      return check('main() { return #hello; }');
     });
 
     test('null', () {
-      return check("main() { return null; }");
+      return check('main() { return null; }');
     });
   });
+
+  test('compile function that returns its argument', () {
+    String code = '''
+      foo(x) {
+        return x;
+      }
+
+      main() {
+        foo(1);
+      }''';
+    return check(code, entry: 'foo');
+  });
 }