// Copyright (c) 2012, 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 'dart:collection';

import 'package:js_runtime/shared/embedded_names.dart';

import '../closure.dart';
import '../common.dart';
import '../common/codegen.dart' show CodegenRegistry;
import '../common/names.dart' show Identifiers, Selectors;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart';
import '../constants/constant_system.dart';
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../deferred_load.dart' show OutputUnit;
import '../diagnostics/messages.dart' show Message, MessageTemplate;
import '../dump_info.dart' show InfoReporter;
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../elements/jumps.dart';
import '../elements/modelx.dart' show ConstructorBodyElementX;
import '../elements/names.dart';
import '../elements/operators.dart';
import '../elements/resolution_types.dart';
import '../elements/types.dart';
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../js_backend/element_strategy.dart' show ElementCodegenWorkItem;
import '../js_backend/runtime_types.dart';
import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
import '../native/native.dart' as native;
import '../resolution/deferred_load.dart' show AstDeferredLoadTask;
import '../resolution/semantic_visitor.dart';
import '../resolution/tree_elements.dart' show TreeElements;
import '../tree/tree.dart' as ast;
import '../types/types.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
import '../universe/use.dart'
    show ConstantUse, ConstrainedDynamicUse, StaticUse;
import '../util/util.dart';
import '../world.dart' show ClosedWorld;

import 'graph_builder.dart';
import 'jump_handler.dart';
import 'locals_handler.dart';
import 'loop_handler.dart';
import 'nodes.dart';
import 'optimize.dart';
import 'ssa.dart';
import 'ssa_branch_builder.dart';
import 'type_builder.dart';
import 'types.dart';

abstract class SsaAstBuilderBase extends SsaBuilderFieldMixin
    implements SsaBuilder {
  final CompilerTask task;
  final JavaScriptBackend backend;

  SsaAstBuilderBase(this.task, this.backend);

  ConstantValue getFieldInitialConstantValue(FieldElement field) {
    ConstantExpression constant = field.constant;
    if (constant != null) {
      ConstantValue initialValue = backend.constants.getConstantValue(constant);
      if (initialValue == null) {
        assert(
            field.isInstanceMember ||
                constant.isImplicit ||
                constant.isPotential,
            failedAt(
                field,
                "Constant expression without value: "
                "${constant.toStructuredText()}."));
      }
      return initialValue;
    }
    return null;
  }
}

class SsaAstBuilder extends SsaAstBuilderBase {
  final CodeEmitterTask emitter;
  final SourceInformationStrategy sourceInformationFactory;

  SsaAstBuilder(CompilerTask task, JavaScriptBackend backend,
      this.sourceInformationFactory)
      : emitter = backend.emitter,
        super(task, backend);

  DiagnosticReporter get reporter => backend.reporter;

  HGraph build(covariant ElementCodegenWorkItem work, ClosedWorld closedWorld) {
    return task.measure(() {
      if (handleConstantField(work.element, work.registry, closedWorld)) {
        // No code is generated for `work.element`.
        return null;
      }
      MemberElement element = work.element.implementation;
      return reporter.withCurrentElement(element, () {
        SsaAstGraphBuilder builder = new SsaAstGraphBuilder(
            work.element.implementation,
            work.resolvedAst,
            work.registry,
            backend,
            closedWorld,
            emitter.nativeEmitter,
            sourceInformationFactory);
        HGraph graph = builder.build();

        // Default arguments are handled elsewhere, but we must ensure
        // that the default values are computed during codegen.
        if (!identical(element.kind, ElementKind.FIELD)) {
          MethodElement function = element;
          FunctionSignature signature = function.functionSignature;
          signature.forEachOptionalParameter((_parameter) {
            ParameterElement parameter = _parameter;
            // This ensures the default value will be computed.
            ConstantValue constant =
                backend.constants.getConstantValue(parameter.constant);
            work.registry.registerConstantUse(new ConstantUse.init(constant));
          });
        }
        if (backend.tracer.isEnabled) {
          String name;
          if (element.isClassMember) {
            String className = element.enclosingClass.name;
            String memberName = element.name;
            name = "$className.$memberName";
            if (element.isGenerativeConstructorBody) {
              name = "$name (body)";
            }
          } else {
            name = "${element.name}";
          }
          backend.tracer.traceCompilation(name);
          backend.tracer.traceGraph('builder', graph);
        }
        return graph;
      });
    });
  }
}

/**
 * This class builds SSA nodes for functions represented in AST.
 */
class SsaAstGraphBuilder extends ast.Visitor
    with
        BaseImplementationOfCompoundsMixin,
        BaseImplementationOfSetIfNullsMixin,
        BaseImplementationOfSuperIndexSetIfNullMixin,
        SemanticSendResolvedMixin,
        NewBulkMixin,
        ErrorBulkMixin,
        GraphBuilder
    implements SemanticSendVisitor {
  /// The element for which this SSA builder is being used.
  final MemberElement target;
  final ClosedWorld closedWorld;

  ResolvedAst resolvedAst;

  /// Used to report information about inlining (which occurs while building the
  /// SSA graph), when dump-info is enabled.
  final InfoReporter infoReporter;

  /// Registry used to enqueue work during codegen, may be null to avoid
  /// enqueing any work.
  // TODO(sigmund,johnniwinther): get rid of registry entirely. We should be
  // able to return the impact as a result after building and avoid enqueing
  // things here. Later the codegen task can decide whether to enqueue
  // something. In the past this didn't matter as much because the SSA graph was
  // used only for codegen, but currently we want to experiment using it for
  // code-analysis too.
  final CodegenRegistry registry;

  /// Results from the global type-inference analysis corresponding to the
  /// current element being visited.
  ///
  /// Invariant: this property is updated together with [resolvedAst].
  GlobalTypeInferenceElementResult elementInferenceResults;

  final JavaScriptBackend backend;

  Compiler get compiler => backend.compiler;

  AstDeferredLoadTask get deferredLoadTask => super.deferredLoadTask;

  final ConstantSystem constantSystem;
  final RuntimeTypesSubstitutions rtiSubstitutions;

  SourceInformationBuilder sourceInformationBuilder;

  bool inLazyInitializerExpression = false;

  // TODO(sigmund): make all comments /// instead of /* */
  /* This field is used by the native handler. */
  final NativeEmitter nativeEmitter;

  /**
   * True if we are visiting the expression of a throw statement; we assume this
   * is a slow path.
   */
  bool inExpressionOfThrow = false;

  /**
   * This stack contains declaration elements of the functions being built
   * or inlined by this builder.
   */
  final List<MemberElement> sourceElementStack = <MemberElement>[];

  HInstruction rethrowableException;

  /// Returns `true` if the current element is an `async` function.
  bool get isBuildingAsyncFunction {
    Element element = sourceElement;
    return (element is FunctionElement &&
        element.asyncMarker == AsyncMarker.ASYNC);
  }

  /// Handles the building of loops.
  LoopHandler<ast.Node> loopHandler;

  /// Handles type check building.
  TypeBuilder typeBuilder;

  // TODO(sigmund): make most args optional
  SsaAstGraphBuilder(
      this.target,
      this.resolvedAst,
      this.registry,
      JavaScriptBackend backend,
      this.closedWorld,
      this.nativeEmitter,
      SourceInformationStrategy sourceInformationFactory)
      : this.infoReporter = backend.compiler.dumpInfoTask,
        this.backend = backend,
        this.constantSystem = backend.constantSystem,
        this.rtiSubstitutions = backend.rtiSubstitutions {
    assert(target.isImplementation);
    elementInferenceResults = _resultOf(target.declaration);
    assert(elementInferenceResults != null);
    graph.element = target;
    sourceElementStack.add(target.declaration);
    sourceInformationBuilder =
        sourceInformationFactory.createBuilderForContext(target);
    graph.sourceInformation =
        sourceInformationBuilder.buildVariableDeclaration();
    localsHandler = new LocalsHandler(
        this,
        target,
        target.memberContext,
        target.contextClass?.thisType,
        closedWorld.nativeData,
        closedWorld.interceptorData);
    loopHandler = new SsaLoopHandler(this);
    typeBuilder = new AstTypeBuilder(this);
  }

  MemberElement get targetElement => target;

  /// Reference to resolved elements in [target]'s AST.
  TreeElements get elements => resolvedAst.elements;

  @override
  SemanticSendVisitor get sendVisitor => this;

  @override
  void visitNode(ast.Node node) {
    internalError(node, "Unhandled node: $node");
  }

  @override
  void apply(ast.Node node, [_]) {
    node.accept(this);
  }

  /// Returns the current source element.
  ///
  /// The returned element is a declaration element.
  // TODO(johnniwinther): Check that all usages of sourceElement agree on
  // implementation/declaration distinction.
  @override
  MemberElement get sourceElement => sourceElementStack.last;

  /// Helper to retrieve global inference results for [element] with special
  /// care for `ConstructorBodyElement`s which don't exist at the time the
  /// global analysis run.
  ///
  /// Note: this helper is used selectively. When we know that we are in a
  /// context were we don't expect to see a constructor body element, we
  /// directly fetch the data from the global inference results.
  GlobalTypeInferenceElementResult _resultOf(MemberElement element) {
    assert(element.isDeclaration);
    return globalInferenceResults.resultOfMember(
        element is ConstructorBodyElementX ? element.constructor : element);
  }

  /// Build the graph for [target].
  HGraph build() {
    assert(target.isImplementation, failedAt(target));
    HInstruction.idCounter = 0;
    // TODO(sigmund): remove `result` and return graph directly, need to ensure
    // that it can never be null (see result in buildFactory for instance).
    var result;
    if (target.isGenerativeConstructor) {
      result = buildFactory(resolvedAst);
    } else if (target.isGenerativeConstructorBody ||
        target.isFactoryConstructor ||
        target.isFunction ||
        target.isGetter ||
        target.isSetter) {
      result = buildMethod(target);
    } else if (target.isField) {
      if (target.isInstanceMember) {
        assert(options.enableTypeAssertions);
        result = buildCheckedSetter(target);
      } else {
        result = buildLazyInitializer(target);
      }
    } else {
      reporter.internalError(target, 'Unexpected element kind $target.');
    }
    assert(result.isValid());
    return result;
  }

  void addWithPosition(HInstruction instruction, ast.Node node) {
    add(attachPosition(instruction, node));
  }

  /**
   * Returns a complete argument list for a call of [function].
   */
  List<HInstruction> completeSendArgumentsList(
      FunctionElement function,
      Selector selector,
      List<HInstruction> providedArguments,
      ast.Node currentNode) {
    assert(function.isImplementation, failedAt(function));
    assert(providedArguments != null);

    bool isInstanceMember = function.isInstanceMember;
    // For static calls, [providedArguments] is complete, default arguments
    // have been included if necessary, see [makeStaticArgumentList].
    if (!isInstanceMember ||
        currentNode == null || // In erroneous code, currentNode can be null.
        providedArgumentsKnownToBeComplete(currentNode) ||
        function.isGenerativeConstructorBody ||
        selector.isGetter) {
      // For these cases, the provided argument list is known to be complete.
      return providedArguments;
    } else {
      return completeDynamicSendArgumentsList(
          selector, function, providedArguments);
    }
  }

  /**
   * Returns a complete argument list for a dynamic call of [function]. The
   * initial argument list [providedArguments], created by
   * [addDynamicSendArgumentsToList], does not include values for default
   * arguments used in the call. The reason is that the target function (which
   * defines the defaults) is not known.
   *
   * However, inlining can only be performed when the target function can be
   * resolved statically. The defaults can therefore be included at this point.
   *
   * The [providedArguments] list contains first all positional arguments, then
   * the provided named arguments (the named arguments that are defined in the
   * [selector]) in a specific order (see [addDynamicSendArgumentsToList]).
   */
  List<HInstruction> completeDynamicSendArgumentsList(Selector selector,
      MethodElement function, List<HInstruction> providedArguments) {
    assert(selector.applies(function));
    FunctionSignature signature = function.functionSignature;
    List<HInstruction> compiledArguments = new List<HInstruction>(
        signature.parameterCount + 1); // Plus one for receiver.

    compiledArguments[0] = providedArguments[0]; // Receiver.
    int index = 1;
    for (; index <= signature.requiredParameterCount; index++) {
      compiledArguments[index] = providedArguments[index];
    }
    if (!signature.optionalParametersAreNamed) {
      signature.forEachOptionalParameter((element) {
        if (index < providedArguments.length) {
          compiledArguments[index] = providedArguments[index];
        } else {
          compiledArguments[index] =
              handleConstantForOptionalParameter(element);
        }
        index++;
      });
    } else {
      /* Example:
       *   void foo(a, {b, d, c})
       *   foo(0, d = 1, b = 2)
       *
       * providedArguments = [0, 2, 1]
       * selectorArgumentNames = [b, d]
       * signature.orderedOptionalParameters = [b, c, d]
       *
       * For each parameter name in the signature, if the argument name matches
       * we use the next provided argument, otherwise we get the default.
       */
      List<String> selectorArgumentNames =
          selector.callStructure.getOrderedNamedArguments();
      int namedArgumentIndex = 0;
      int firstProvidedNamedArgument = index;
      signature.orderedOptionalParameters.forEach((element) {
        if (namedArgumentIndex < selectorArgumentNames.length &&
            element.name == selectorArgumentNames[namedArgumentIndex]) {
          // The named argument was provided in the function invocation.
          compiledArguments[index] = providedArguments[
              firstProvidedNamedArgument + namedArgumentIndex++];
        } else {
          compiledArguments[index] =
              handleConstantForOptionalParameter(element);
        }
        index++;
      });
    }
    return compiledArguments;
  }

  /**
   * Try to inline [element] within the correct context of the builder. The
   * insertion point is the state of the builder.
   */
  bool tryInlineMethod(MethodElement element, Selector selector, TypeMask mask,
      List<HInstruction> providedArguments, ast.Node currentNode,
      {ResolutionInterfaceType instanceType}) {
    if (nativeData.isJsInteropMember(element) &&
        !element.isFactoryConstructor) {
      // We only inline factory JavaScript interop constructors.
      return false;
    }

    // Ensure that [element] is an implementation element.
    element = element.implementation;

    if (compiler.elementHasCompileTimeError(element)) return false;

    MethodElement function = element;
    MethodElement declaration = function.declaration;
    ResolvedAst functionResolvedAst = function.resolvedAst;
    bool insideLoop = loopDepth > 0 || graph.calledInLoop;

    // Bail out early if the inlining decision is in the cache and we can't
    // inline (no need to check the hard constraints).
    bool cachedCanBeInlined =
        inlineCache.canInline(declaration, insideLoop: insideLoop);
    if (cachedCanBeInlined == false) return false;

    bool meetsHardConstraints() {
      if (options.disableInlining) return false;

      assert(
          selector != null ||
              Elements.isStaticOrTopLevel(function) ||
              function.isGenerativeConstructorBody,
          failedAt(currentNode ?? function,
              "Missing selector for inlining of $function."));
      if (selector != null) {
        if (!selector.applies(function)) return false;
        if (mask != null && !mask.canHit(function, selector, closedWorld)) {
          return false;
        }
      }

      if (nativeData.isJsInteropMember(function)) return false;

      // Don't inline operator== methods if the parameter can be null.
      if (function.name == '==') {
        if (function.enclosingClass != commonElements.objectClass &&
            providedArguments[1].canBeNull()) {
          return false;
        }
      }

      // Generative constructors of native classes should not be called directly
      // and have an extra argument that causes problems with inlining.
      if (function.isGenerativeConstructor &&
          nativeData.isNativeOrExtendsNative(function.enclosingClass)) {
        return false;
      }

      // A generative constructor body is not seen by global analysis,
      // so we should not query for its type.
      if (!function.isGenerativeConstructorBody) {
        if (globalInferenceResults.resultOfMember(declaration).throwsAlways) {
          isReachable = false;
          return false;
        }
      }

      return true;
    }

    bool doesNotContainCode() {
      // A function with size 1 does not contain any code.
      return InlineWeeder.canBeInlined(functionResolvedAst, 1,
          enableUserAssertions: options.enableUserAssertions);
    }

    bool reductiveHeuristic() {
      // The call is on a path which is executed rarely, so inline only if it
      // does not make the program larger.
      if (isCalledOnce(declaration)) {
        return InlineWeeder.canBeInlined(functionResolvedAst, null,
            enableUserAssertions: options.enableUserAssertions);
      }
      // TODO(sra): Measure if inlining would 'reduce' the size.  One desirable
      // case we miss by doing nothing is inlining very simple constructors
      // where all fields are initialized with values from the arguments at this
      // call site.  The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but
      // that usually means the factory constructor is left unused and not
      // emitted.
      // We at least inline bodies that are empty (and thus have a size of 1).
      return doesNotContainCode();
    }

    bool heuristicSayGoodToGo() {
      // Don't inline recursively
      if (inliningStack.any((entry) => entry.function == function)) {
        return false;
      }

      if (function.isSynthesized) return true;

      // Don't inline across deferred import to prevent leaking code. The only
      // exception is an empty function (which does not contain code).
      bool hasOnlyNonDeferredImportPaths = backend.outputUnitData
          .hasOnlyNonDeferredImportPaths(compiler.currentElement, function);

      if (!hasOnlyNonDeferredImportPaths) {
        return doesNotContainCode();
      }

      // Do not inline code that is rarely executed unless it reduces size.
      if (inExpressionOfThrow || inLazyInitializerExpression) {
        return reductiveHeuristic();
      }

      if (cachedCanBeInlined == true) {
        // We may have forced the inlining of some methods. Therefore check
        // if we can inline this method regardless of size.
        assert(InlineWeeder.canBeInlined(functionResolvedAst, null,
            allowLoops: true,
            enableUserAssertions: options.enableUserAssertions));
        return true;
      }

      int numParameters = function.functionSignature.parameterCount;
      int maxInliningNodes;
      if (insideLoop) {
        maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP +
            InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters;
      } else {
        maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP +
            InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters;
      }

      // If a method is called only once, and all the methods in the
      // inlining stack are called only once as well, we know we will
      // save on output size by inlining this method.
      if (isCalledOnce(declaration)) {
        maxInliningNodes = null;
      }
      bool canInline = InlineWeeder.canBeInlined(
          functionResolvedAst, maxInliningNodes,
          enableUserAssertions: options.enableUserAssertions);
      if (canInline) {
        inlineCache.markAsInlinable(declaration, insideLoop: insideLoop);
      } else {
        inlineCache.markAsNonInlinable(declaration, insideLoop: insideLoop);
      }
      return canInline;
    }

    void doInlining() {
      registry
          .registerStaticUse(new StaticUse.inlining(declaration, instanceType));

      // Add an explicit null check on the receiver before doing the
      // inlining. We use [element] to get the same name in the
      // NoSuchMethodError message as if we had called it.
      if (function.isInstanceMember &&
          !function.isGenerativeConstructorBody &&
          (mask == null || mask.isNullable)) {
        addWithPosition(
            new HFieldGet(null, providedArguments[0], commonMasks.dynamicType,
                isAssignable: false),
            currentNode);
      }
      List<HInstruction> compiledArguments = completeSendArgumentsList(
          function, selector, providedArguments, currentNode);
      enterInlinedMethod(
          function, functionResolvedAst, compiledArguments, instanceType);
      inlinedFrom(functionResolvedAst, () {
        if (!isReachable) {
          emitReturn(graph.addConstantNull(closedWorld), null);
        } else {
          doInline(functionResolvedAst);
        }
      });
      leaveInlinedMethod();
    }

    if (meetsHardConstraints() && heuristicSayGoodToGo()) {
      doInlining();
      MemberElement inlinedFrom = inliningStack.isEmpty
          ? target.declaration
          : inliningStack.last.function.declaration;
      infoReporter?.reportInlined(declaration, inlinedFrom);
      return true;
    }

    return false;
  }

  bool get allInlinedFunctionsCalledOnce {
    return inliningStack.isEmpty || inliningStack.last.allFunctionsCalledOnce;
  }

  bool isFunctionCalledOnce(MethodElement element) {
    // ConstructorBodyElements are not in the type inference graph.
    if (element is ConstructorBodyEntity) return false;
    return globalInferenceResults.resultOfMember(element).isCalledOnce;
  }

  bool isCalledOnce(MethodElement element) {
    assert(element.isDeclaration);
    return allInlinedFunctionsCalledOnce && isFunctionCalledOnce(element);
  }

  inlinedFrom(ResolvedAst resolvedAst, f()) {
    MemberElement element = resolvedAst.element;
    assert(element is FunctionElement || element is VariableElement);
    return reporter.withCurrentElement(element.implementation, () {
      // The [sourceElementStack] contains declaration elements.
      SourceInformationBuilder oldSourceInformationBuilder =
          sourceInformationBuilder;
      sourceInformationBuilder = sourceInformationBuilder.forContext(element);
      sourceElementStack.add(element);
      var result = f();
      sourceInformationBuilder = oldSourceInformationBuilder;
      sourceElementStack.removeLast();
      return result;
    });
  }

  /**
   * Return null so it is simple to remove the optional parameters completely
   * from interop methods to match JavaScript semantics for omitted arguments.
   */
  HInstruction handleConstantForOptionalParameterJsInterop(Element parameter) =>
      null;

  HInstruction handleConstantForOptionalParameter(ParameterElement parameter) {
    ConstantValue constantValue =
        constants.getConstantValue(parameter.constant);
    assert(constantValue != null,
        failedAt(parameter, 'No constant computed for $parameter'));
    return graph.addConstant(constantValue, closedWorld);
  }

  ClassElement get currentNonClosureClass {
    ClassElement cls = sourceElement.enclosingClass;
    if (cls != null && cls.isClosure) {
      dynamic closureClass = cls;
      // ignore: UNDEFINED_GETTER
      return closureClass.methodElement.enclosingClass;
    } else {
      return cls;
    }
  }

  /// A stack of [ResolutionDartType]s that have been seen during inlining of
  /// factory constructors.  These types are preserved in [HInvokeStatic]s and
  /// [HCreate]s inside the inline code and registered during code generation
  /// for these nodes.
  // TODO(karlklose): consider removing this and keeping the (substituted) types
  // of the type variables in an environment (like the [LocalsHandler]).
  final List<ResolutionDartType> currentInlinedInstantiations =
      <ResolutionDartType>[];

  final List<AstInliningState> inliningStack = <AstInliningState>[];

  Local returnLocal;
  ResolutionDartType returnType;

  ConstantValue getConstantForNode(ast.Node node) {
    ConstantValue constantValue =
        constants.getConstantValueForNode(node, elements);
    assert(constantValue != null,
        failedAt(node, 'No constant computed for $node'));
    return constantValue;
  }

  HInstruction addConstant(ast.Node node) {
    return graph.addConstant(getConstantForNode(node), closedWorld);
  }

  /**
   * Documentation wanted -- johnniwinther
   *
   * Invariant: [functionElement] must be an implementation element.
   */
  HGraph buildMethod(MethodElement functionElement) {
    assert(functionElement.isImplementation, failedAt(functionElement));
    MethodElement declaration = functionElement.declaration;
    graph.calledInLoop = closedWorld.isCalledInLoop(declaration);
    ast.FunctionExpression function = resolvedAst.node;
    assert(function != null);
    assert(elements.getFunctionDefinition(function) != null);
    openFunction(functionElement, function);
    String name = functionElement.name;
    if (nativeData.isJsInteropMember(functionElement)) {
      push(invokeJsInteropFunction(functionElement, parameters.values.toList(),
          sourceInformationBuilder.buildGeneric(function)));
      var value = pop();
      closeAndGotoExit(new HReturn(
          value, sourceInformationBuilder.buildReturn(functionElement.node)));
      return closeFunction();
    }
    assert(!function.modifiers.isExternal, failedAt(functionElement));

    // If [functionElement] is `operator==` we explicitly add a null check at
    // the beginning of the method. This is to avoid having call sites do the
    // null check.
    if (name == '==') {
      if (!commonElements.operatorEqHandlesNullArgument(functionElement)) {
        handleIf(
            node: function,
            visitCondition: () {
              HParameterValue parameter = parameters.values.first;
              push(new HIdentity(parameter, graph.addConstantNull(closedWorld),
                  null, commonMasks.boolType));
            },
            visitThen: () {
              closeAndGotoExit(new HReturn(
                  graph.addConstantBool(false, closedWorld),
                  sourceInformationBuilder
                      .buildImplicitReturn(functionElement)));
            },
            visitElse: null,
            sourceInformation: sourceInformationBuilder.buildIf(function.body));
      }
    }
    if (const bool.fromEnvironment('unreachable-throw')) {
      var emptyParameters =
          parameters.values.where((p) => p.instructionType.isEmpty);
      if (emptyParameters.length > 0) {
        addComment('${emptyParameters} inferred as [empty]');
        pushInvokeStatic(
            function.body, commonElements.assertUnreachableMethod, []);
        pop();
        return closeFunction();
      }
    }
    function.body.accept(this);
    return closeFunction();
  }

  /// Adds a JavaScript comment to the output. The comment will be omitted in
  /// minified mode.  Each line in [text] is preceded with `//` and indented.
  /// Use sparingly. In order for the comment to be retained it is modeled as
  /// having side effects which will inhibit code motion.
  // TODO(sra): Figure out how to keep comment anchored without effects.
  void addComment(String text) {
    add(new HForeignCode(js.js.statementTemplateYielding(new js.Comment(text)),
        commonMasks.dynamicType, <HInstruction>[],
        isStatement: true));
  }

  HGraph buildCheckedSetter(FieldElement field) {
    ResolvedAst resolvedAst = field.resolvedAst;
    openFunction(field, resolvedAst.node);
    HInstruction thisInstruction = localsHandler.readThis(
        sourceInformation: sourceInformationBuilder.buildDeclaration(field));
    // Use dynamic type because the type computed by the inferrer is
    // narrowed to the type annotation.
    HInstruction parameter =
        new HParameterValue(field, commonMasks.dynamicType);
    // Add the parameter as the last instruction of the entry block.
    // If the method is intercepted, we want the actual receiver
    // to be the first parameter.
    graph.entry.addBefore(graph.entry.last, parameter);
    HInstruction value =
        typeBuilder.potentiallyCheckOrTrustType(parameter, field.type);
    add(new HFieldSet(field, thisInstruction, value));
    return closeFunction();
  }

  HGraph buildLazyInitializer(FieldElement variable) {
    assert(resolvedAst.element == variable,
        failedAt(variable, "Unexpected variable $variable for $resolvedAst."));
    inLazyInitializerExpression = true;
    ast.VariableDefinitions node = resolvedAst.node;
    ast.Node initializer = resolvedAst.body;
    assert(
        initializer != null,
        failedAt(
            variable, "Non-constant variable $variable has no initializer."));
    openFunction(variable, node);
    visit(initializer);
    HInstruction value = pop();
    value = typeBuilder.potentiallyCheckOrTrustType(value, variable.type);
    // In the case of multiple declarations (and some definitions) on the same
    // line, the source pointer needs to point to the right initialized
    // variable. So find the specific initialized variable we are referring to.
    ast.Node sourceInfoNode = initializer;
    for (var definition in node.definitions) {
      if (definition is ast.SendSet &&
          definition.selector.asIdentifier().source == variable.name) {
        sourceInfoNode = definition.assignmentOperator;
        break;
      }
    }

    closeAndGotoExit(new HReturn(
        value, sourceInformationBuilder.buildReturn(sourceInfoNode)));
    return closeFunction();
  }

  /**
   * This method sets up the local state of the builder for inlining [function].
   * The arguments of the function are inserted into the [localsHandler].
   *
   * When inlining a function, [:return:] statements are not emitted as
   * [HReturn] instructions. Instead, the value of a synthetic element is
   * updated in the [localsHandler]. This function creates such an element and
   * stores it in the [returnLocal] field.
   */
  void setupStateForInlining(
      MethodElement function, List<HInstruction> compiledArguments,
      {ResolutionInterfaceType instanceType}) {
    ResolvedAst resolvedAst = function.resolvedAst;
    assert(resolvedAst != null);
    localsHandler = new LocalsHandler(
        this,
        function,
        function.memberContext,
        instanceType ?? function.contextClass?.thisType,
        nativeData,
        interceptorData);
    localsHandler.scopeInfo = closureDataLookup.getScopeInfo(function);
    returnLocal =
        new SyntheticLocal("result", function, function.memberContext);
    localsHandler.updateLocal(returnLocal, graph.addConstantNull(closedWorld));

    inTryStatement = false; // TODO(lry): why? Document.

    int argumentIndex = 0;
    if (function.isInstanceMember) {
      localsHandler.updateLocal(localsHandler.scopeInfo.thisLocal,
          compiledArguments[argumentIndex++]);
    }

    FunctionSignature signature = function.functionSignature;
    signature.orderedForEachParameter((_parameter) {
      ParameterElement parameter = _parameter;
      HInstruction argument = compiledArguments[argumentIndex++];
      localsHandler.updateLocal(parameter, argument);
    });

    ClassElement enclosing = function.enclosingClass;
    if ((function.isConstructor || function.isGenerativeConstructorBody) &&
        rtiNeed.classNeedsTypeArguments(enclosing)) {
      enclosing.typeVariables.forEach((_typeVariable) {
        ResolutionTypeVariableType typeVariable = _typeVariable;
        HInstruction argument = compiledArguments[argumentIndex++];
        localsHandler.updateLocal(
            localsHandler.getTypeVariableAsLocal(typeVariable), argument);
      });
    }
    assert(argumentIndex == compiledArguments.length);

    returnType = signature.type.returnType;
    stack = <HInstruction>[];

    insertTraceCall(function);
    insertCoverageCall(function);
  }

  void restoreState(AstInliningState state) {
    localsHandler = state.oldLocalsHandler;
    returnLocal = state.oldReturnLocal;
    inTryStatement = state.inTryStatement;
    resolvedAst = state.oldResolvedAst;
    elementInferenceResults = state.oldElementInferenceResults;
    returnType = state.oldReturnType;
    assert(stack.isEmpty);
    stack = state.oldStack;
  }

  /**
   * Run this builder on the body of the [function] to be inlined.
   */
  void visitInlinedFunction(ResolvedAst resolvedAst) {
    MethodElement function = resolvedAst.element.implementation;
    typeBuilder.potentiallyCheckInlinedParameterTypes(function);

    if (resolvedAst.element.isGenerativeConstructor) {
      buildFactory(resolvedAst);
    } else {
      ast.FunctionExpression functionNode = resolvedAst.node;
      functionNode.body.accept(this);
    }
  }

  addInlinedInstantiation(ResolutionDartType type) {
    if (type != null) {
      currentInlinedInstantiations.add(type);
    }
  }

  removeInlinedInstantiation(ResolutionDartType type) {
    if (type != null) {
      currentInlinedInstantiations.removeLast();
    }
  }

  bool providedArgumentsKnownToBeComplete(ast.Node currentNode) {
    /* When inlining the iterator methods generated for a [:for-in:] loop, the
     * [currentNode] is the [ForIn] tree. The compiler-generated iterator
     * invocations are known to have fully specified argument lists, no default
     * arguments are used. See invocations of [pushInvokeDynamic] in
     * [visitForIn].
     */
    return currentNode.asForIn() != null;
  }

  /**
   * Documentation wanted -- johnniwinther
   *
   * Invariant: [constructors] must contain only implementation elements.
   */
  void inlineSuperOrRedirect(
      ResolvedAst constructorResolvedAst,
      List<HInstruction> compiledArguments,
      List<ResolvedAst> constructorResolvedAsts,
      Map<FieldElement, HInstruction> fieldValues,
      FunctionElement caller) {
    ConstructorElement callee = constructorResolvedAst.element.implementation;

    reporter.withCurrentElement(callee, () {
      Set<ClassElement> includedClasses = new Set<ClassElement>();
      constructorResolvedAsts.add(constructorResolvedAst);
      ClassElement currentClass = caller.enclosingClass;

      /// Include locals for type variable used in [member].
      void includeTypeVariables(MemberElement member) {
        ClassElement enclosingClass = member.enclosingClass;
        if (!includedClasses.add(enclosingClass)) return;

        if (rtiNeed.classNeedsTypeArguments(enclosingClass)) {
          // If [enclosingClass] needs RTI, we have to give a value to its
          // type parameters.
          // For a super constructor call, the type is the supertype of
          // [currentClass]. For a redirecting constructor, the type is
          // the current type. [InterfaceType.asInstanceOf] takes care
          // of both.
          ResolutionInterfaceType type =
              currentClass.thisType.asInstanceOf(enclosingClass);
          type = localsHandler.substInContext(type);
          List<ResolutionDartType> arguments = type.typeArguments;
          List<ResolutionDartType> typeVariables = enclosingClass.typeVariables;
          if (!type.isRaw) {
            assert(arguments.length == typeVariables.length);
            Iterator<ResolutionDartType> variables = typeVariables.iterator;
            type.typeArguments.forEach((ResolutionDartType argument) {
              variables.moveNext();
              ResolutionTypeVariableType typeVariable = variables.current;
              localsHandler.updateLocal(
                  localsHandler.getTypeVariableAsLocal(typeVariable),
                  typeBuilder.analyzeTypeArgument(argument, sourceElement));
            });
          } else {
            // If the supertype is a raw type, we need to set to null the
            // type variables.
            for (ResolutionTypeVariableType variable in typeVariables) {
              localsHandler.updateLocal(
                  localsHandler.getTypeVariableAsLocal(variable),
                  graph.addConstantNull(closedWorld));
            }
          }
        }
      }

      includeTypeVariables(callee);

      // For redirecting constructors, the fields will be initialized later
      // by the effective target.
      if (!callee.isRedirectingGenerative) {
        callee.enclosingClass.implementation.forEachInstanceField(
            (ClassElement enclosingClass, FieldElement member) {
          includeTypeVariables(member);
        });
        inlinedFrom(constructorResolvedAst, () {
          buildFieldInitializers(
              callee.enclosingClass.implementation, fieldValues);
        });
      }

      int index = 0;
      FunctionSignature params = callee.functionSignature;
      params.orderedForEachParameter((_parameter) {
        ParameterElement parameter = _parameter;
        HInstruction argument = compiledArguments[index++];
        // Because we are inlining the initializer, we must update
        // what was given as parameter. This will be used in case
        // there is a parameter check expression in the initializer.
        parameters[parameter] = argument;
        localsHandler.updateLocal(parameter, argument);
        // Don't forget to update the field, if the parameter is of the
        // form [:this.x:].
        if (parameter.isInitializingFormal) {
          InitializingFormalElement fieldParameterElement = parameter;
          fieldValues[fieldParameterElement.fieldElement] = argument;
        }
      });

      // Build the initializers in the context of the new constructor.
      ResolvedAst oldResolvedAst = resolvedAst;
      resolvedAst = callee.resolvedAst;
      final oldElementInferenceResults = elementInferenceResults;
      elementInferenceResults = globalInferenceResults.resultOfMember(callee);
      ScopeInfo oldScopeInfo = localsHandler.scopeInfo;
      ScopeInfo newScopeInfo = closureDataLookup.getScopeInfo(callee);
      localsHandler.scopeInfo = newScopeInfo;
      if (resolvedAst.kind == ResolvedAstKind.PARSED) {
        localsHandler.enterScope(closureDataLookup.getCapturedScope(callee),
            sourceInformationBuilder.buildDeclaration(callee),
            forGenerativeConstructorBody: callee.isGenerativeConstructorBody);
      }
      buildInitializers(callee, constructorResolvedAsts, fieldValues);
      localsHandler.scopeInfo = oldScopeInfo;
      resolvedAst = oldResolvedAst;
      elementInferenceResults = oldElementInferenceResults;
    });
  }

  void buildInitializers(
      ConstructorElement constructor,
      List<ResolvedAst> constructorResolvedAsts,
      Map<FieldElement, HInstruction> fieldValues) {
    assert(
        resolvedAst.element == constructor.declaration,
        failedAt(constructor,
            "Expected ResolvedAst for $constructor, found $resolvedAst"));
    if (resolvedAst.kind == ResolvedAstKind.PARSED) {
      buildParsedInitializers(
          constructor, constructorResolvedAsts, fieldValues);
    } else {
      buildSynthesizedConstructorInitializers(
          constructor, constructorResolvedAsts, fieldValues);
    }
  }

  void buildSynthesizedConstructorInitializers(
      ConstructorElement constructor,
      List<ResolvedAst> constructorResolvedAsts,
      Map<FieldElement, HInstruction> fieldValues) {
    assert(
        constructor.isSynthesized,
        failedAt(
            constructor, "Unexpected unsynthesized constructor: $constructor"));
    List<HInstruction> arguments = <HInstruction>[];
    HInstruction compileArgument(ParameterElement parameter) {
      return localsHandler.readLocal(parameter);
    }

    ConstructorElement target = constructor.definingConstructor.implementation;
    bool match = !target.isMalformed &&
        Elements.addForwardingElementArgumentsToList<HInstruction>(
            constructor,
            arguments,
            target,
            compileArgument,
            handleConstantForOptionalParameter);
    if (!match) {
      if (compiler.elementHasCompileTimeError(constructor)) {
        return;
      }
      // If this fails, the selector we constructed for the call to a
      // forwarding constructor in a mixin application did not match the
      // constructor (which, for example, may happen when the libraries are
      // not compatible for private names, see issue 20394).
      reporter.internalError(
          constructor, 'forwarding constructor call does not match');
    }
    inlineSuperOrRedirect(target.resolvedAst, arguments,
        constructorResolvedAsts, fieldValues, constructor);
  }

  /**
   * Run through the initializers and inline all field initializers. Recursively
   * inlines super initializers.
   *
   * The constructors of the inlined initializers is added to [constructors]
   * with sub constructors having a lower index than super constructors.
   *
   * Invariant: The [constructor] and elements in [constructors] must all be
   * implementation elements.
   */
  void buildParsedInitializers(
      ConstructorElement constructor,
      List<ResolvedAst> constructorResolvedAsts,
      Map<FieldElement, HInstruction> fieldValues) {
    assert(
        resolvedAst.element == constructor.declaration, failedAt(constructor));
    assert(constructor.isImplementation, failedAt(constructor));
    assert(
        !constructor.isSynthesized,
        failedAt(
            constructor, "Unexpected synthesized constructor: $constructor"));
    ast.FunctionExpression functionNode = resolvedAst.node;

    bool foundSuperOrRedirect = false;
    if (functionNode.initializers != null) {
      Link<ast.Node> initializers = functionNode.initializers.nodes;
      for (Link<ast.Node> link = initializers;
          !link.isEmpty;
          link = link.tail) {
        assert(link.head is ast.Send);
        if (link.head is! ast.SendSet) {
          // A super initializer or constructor redirection.
          foundSuperOrRedirect = true;
          ast.Send call = link.head;
          assert(ast.Initializers.isSuperConstructorCall(call) ||
              ast.Initializers.isConstructorRedirect(call));
          ConstructorElement target = elements[call];
          CallStructure callStructure =
              elements.getSelector(call).callStructure;
          Link<ast.Node> arguments = call.arguments;
          List<HInstruction> compiledArguments;
          inlinedFrom(resolvedAst, () {
            compiledArguments =
                makeStaticArgumentList(callStructure, arguments, target);
          });
          inlineSuperOrRedirect(target.resolvedAst, compiledArguments,
              constructorResolvedAsts, fieldValues, constructor);
        } else {
          // A field initializer.
          ast.SendSet init = link.head;
          Link<ast.Node> arguments = init.arguments;
          assert(!arguments.isEmpty && arguments.tail.isEmpty);
          inlinedFrom(resolvedAst, () {
            visit(arguments.head);
          });
          fieldValues[elements[init]] = pop();
        }
      }
    }

    if (!foundSuperOrRedirect) {
      // No super initializer found. Try to find the default constructor if
      // the class is not Object.
      ClassElement enclosingClass = constructor.enclosingClass;
      ClassElement superClass = enclosingClass.superclass;
      if (!enclosingClass.isObject) {
        assert(superClass != null);
        assert(superClass.isResolved);
        // TODO(johnniwinther): Should we find injected constructors as well?
        FunctionElement target = superClass.lookupDefaultConstructor();
        if (target == null) {
          reporter.internalError(
              superClass, "No default constructor available.");
        }
        List<HInstruction> arguments = Elements.makeArgumentsList<HInstruction>(
            CallStructure.NO_ARGS,
            const Link<ast.Node>(),
            target.implementation,
            null,
            handleConstantForOptionalParameter);
        inlineSuperOrRedirect(target.resolvedAst, arguments,
            constructorResolvedAsts, fieldValues, constructor);
      }
    }
  }

  /**
   * Run through the fields of [cls] and add their potential
   * initializers.
   *
   * Invariant: [classElement] must be an implementation element.
   */
  void buildFieldInitializers(
      ClassElement classElement, Map<Element, HInstruction> fieldValues) {
    assert(classElement.isImplementation, failedAt(classElement));
    classElement.forEachInstanceField(
        (ClassElement enclosingClass, FieldElement member) {
      if (compiler.elementHasCompileTimeError(member)) return;
      reporter.withCurrentElement(member, () {
        ResolvedAst fieldResolvedAst = member.resolvedAst;
        ast.Expression initializer = fieldResolvedAst.body;
        if (initializer == null) {
          // Unassigned fields of native classes are not initialized to
          // prevent overwriting pre-initialized native properties.
          if (!nativeData.isNativeOrExtendsNative(classElement)) {
            fieldValues[member] = graph.addConstantNull(closedWorld);
          }
        } else {
          ast.Node right = initializer;
          ResolvedAst savedResolvedAst = resolvedAst;
          resolvedAst = fieldResolvedAst;
          final oldElementInferenceResults = elementInferenceResults;
          elementInferenceResults =
              globalInferenceResults.resultOfMember(member);
          inlinedFrom(fieldResolvedAst, () => right.accept(this));
          resolvedAst = savedResolvedAst;
          elementInferenceResults = oldElementInferenceResults;
          fieldValues[member] = pop();
        }
      });
    });
  }

  /**
   * Build the factory function corresponding to the constructor
   * [functionElement]:
   *  - Initialize fields with the values of the field initializers of the
   *    current constructor and super constructors or constructors redirected
   *    to, starting from the current constructor.
   *  - Call the constructor bodies, starting from the constructor(s) in the
   *    super class(es).
   */
  HGraph buildFactory(ResolvedAst resolvedAst) {
    ConstructorElement functionElement = resolvedAst.element;
    functionElement = functionElement.implementation;
    ClassElement classElement = functionElement.enclosingClass.implementation;
    bool isNativeUpgradeFactory =
        nativeData.isNativeOrExtendsNative(classElement) &&
            !nativeData.isJsInteropClass(classElement);
    ast.FunctionExpression function;
    if (resolvedAst.kind == ResolvedAstKind.PARSED) {
      function = resolvedAst.node;
    }

    // Note that constructors (like any other static function) do not need
    // to deal with optional arguments. It is the callers job to provide all
    // arguments as if they were positional.

    if (inliningStack.isEmpty) {
      // The initializer list could contain closures.
      openFunction(functionElement, function);
    }

    Map<FieldElement, HInstruction> fieldValues =
        new Map<FieldElement, HInstruction>();

    // Compile the possible initialization code for local fields and
    // super fields, unless this is a redirecting constructor, in which case
    // the effective target will initialize these.
    if (!functionElement.isRedirectingGenerative) {
      buildFieldInitializers(classElement, fieldValues);
    }

    // Compile field-parameters such as [:this.x:].
    FunctionSignature params = functionElement.functionSignature;
    params.orderedForEachParameter((_parameter) {
      ParameterElement parameter = _parameter;
      if (parameter.isInitializingFormal) {
        // If the [element] is a field-parameter then
        // initialize the field element with its value.
        InitializingFormalElement fieldParameter = parameter;
        HInstruction parameterValue = localsHandler.readLocal(fieldParameter);
        fieldValues[fieldParameter.fieldElement] = parameterValue;
      }
    });

    // Analyze the constructor and all referenced constructors and collect
    // initializers and constructor bodies.
    List<ResolvedAst> constructorResolvedAsts = <ResolvedAst>[resolvedAst];
    buildInitializers(functionElement, constructorResolvedAsts, fieldValues);

    // Call the JavaScript constructor with the fields as argument.
    List<HInstruction> constructorArguments = <HInstruction>[];
    List<FieldEntity> fields = <FieldEntity>[];

    classElement.forEachInstanceField(
        (ClassElement enclosingClass, FieldElement member) {
      HInstruction value = fieldValues[member];
      if (value == null) {
        // Uninitialized native fields are pre-initialized by the native
        // implementation.
        assert(isNativeUpgradeFactory || reporter.hasReportedError,
            failedAt(member));
      } else {
        fields.add(member);
        ResolutionDartType type = localsHandler.substInContext(member.type);
        constructorArguments
            .add(typeBuilder.potentiallyCheckOrTrustType(value, type));
      }
    }, includeSuperAndInjectedMembers: true);

    ResolutionInterfaceType type = classElement.thisType;
    TypeMask ssaType =
        new TypeMask.nonNullExact(classElement.declaration, closedWorld);
    List<DartType> instantiatedTypes;
    addInlinedInstantiation(type);
    if (!currentInlinedInstantiations.isEmpty) {
      instantiatedTypes =
          new List<ResolutionInterfaceType>.from(currentInlinedInstantiations);
    }

    HInstruction newObject;
    if (!isNativeUpgradeFactory) {
      // Create the runtime type information, if needed.
      bool hasRtiInput = false;
      if (rtiNeed.classNeedsTypeArguments(classElement.declaration)) {
        // Read the values of the type arguments and create a
        // HTypeInfoExpression to set on the newly create object.
        hasRtiInput = true;
        List<HInstruction> typeArguments = <HInstruction>[];
        classElement.typeVariables.forEach((_typeVariable) {
          ResolutionTypeVariableType typeVariable = _typeVariable;
          HInstruction argument = localsHandler
              .readLocal(localsHandler.getTypeVariableAsLocal(typeVariable));
          typeArguments.add(argument);
        });

        HInstruction typeInfo = new HTypeInfoExpression(
            TypeInfoExpressionKind.INSTANCE,
            classElement.thisType,
            typeArguments,
            commonMasks.dynamicType);
        add(typeInfo);
        constructorArguments.add(typeInfo);
      }

      newObject = new HCreate(
          classElement,
          constructorArguments,
          ssaType,
          function != null
              ? sourceInformationBuilder.buildCreate(function)
              : sourceInformationBuilder.buildDeclaration(functionElement),
          instantiatedTypes: instantiatedTypes,
          hasRtiInput: hasRtiInput);
      add(newObject);
    } else {
      // Bulk assign to the initialized fields.
      newObject = graph.explicitReceiverParameter;
      // Null guard ensures an error if we are being called from an explicit
      // 'new' of the constructor instead of via an upgrade. It is optimized out
      // if there are field initializers.
      add(new HFieldGet(null, newObject, commonMasks.dynamicType,
          isAssignable: false));
      for (int i = 0; i < fields.length; i++) {
        add(new HFieldSet(fields[i], newObject, constructorArguments[i]));
      }
    }
    removeInlinedInstantiation(type);

    // Generate calls to the constructor bodies.
    HInstruction interceptor = null;
    for (int index = constructorResolvedAsts.length - 1; index >= 0; index--) {
      ResolvedAst constructorResolvedAst = constructorResolvedAsts[index];
      ConstructorElement constructor =
          constructorResolvedAst.element.implementation;
      ConstructorBodyElement body =
          ConstructorBodyElementX.createFromResolvedAst(constructorResolvedAst);
      if (body == null) continue;

      List bodyCallInputs = <HInstruction>[];
      if (isNativeUpgradeFactory) {
        if (interceptor == null) {
          ConstantValue constant = new InterceptorConstantValue(classElement);
          interceptor = graph.addConstant(constant, closedWorld);
        }
        bodyCallInputs.add(interceptor);
      }
      bodyCallInputs.add(newObject);

      FunctionSignature functionSignature = body.functionSignature;
      // Provide the parameters to the generative constructor body.
      functionSignature.orderedForEachParameter((_parameter) {
        ParameterElement parameter = _parameter;
        // If [parameter] is boxed, it will be a field in the box passed as the
        // last parameter. So no need to directly pass it.
        if (!localsHandler.isBoxed(parameter)) {
          bodyCallInputs.add(localsHandler.readLocal(parameter));
        }
      });

      // If there are locals that escape (ie mutated in closures), we
      // pass the box to the constructor.
      // The box must be passed before any type variable.
      CapturedScope scopeData = closureDataLookup.getCapturedScope(constructor);
      if (scopeData.requiresContextBox) {
        bodyCallInputs.add(localsHandler.readLocal(scopeData.context));
      }

      // Type variables arguments must come after the box (if there is one).
      ClassElement currentClass = constructor.enclosingClass;
      if (rtiNeed.classNeedsTypeArguments(currentClass)) {
        // If [currentClass] needs RTI, we add the type variables as
        // parameters of the generative constructor body.
        currentClass.typeVariables.forEach((_argument) {
          ResolutionTypeVariableType argument = _argument;
          // TODO(johnniwinther): Substitute [argument] with
          // `localsHandler.substInContext(argument)`.
          bodyCallInputs.add(localsHandler
              .readLocal(localsHandler.getTypeVariableAsLocal(argument)));
        });
      }

      if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining.
          tryInlineMethod(body, null, null, bodyCallInputs, function)) {
        pop();
      } else {
        ConstructorBodyElement declaration = body.declaration;
        HInvokeConstructorBody invoke = new HInvokeConstructorBody(
            declaration,
            bodyCallInputs,
            commonMasks.nonNullType,
            sourceInformationBuilder.buildDeclaration(constructor));
        invoke.sideEffects = closedWorld.getSideEffectsOfElement(constructor);
        add(invoke);
      }
    }
    if (inliningStack.isEmpty) {
      closeAndGotoExit(new HReturn(newObject,
          sourceInformationBuilder.buildImplicitReturn(functionElement)));
      return closeFunction();
    } else {
      localsHandler.updateLocal(returnLocal, newObject);
      return null;
    }
  }

  /**
   * Documentation wanted -- johnniwinther
   *
   * Invariant: [functionElement] must be the implementation element.
   */
  void openFunction(MemberElement element, ast.Node node) {
    assert(element.isImplementation, failedAt(element));
    HBasicBlock block = graph.addNewBlock();
    open(graph.entry);

    Map<Local, TypeMask> parameters = <Local, TypeMask>{};
    if (element is MethodElement) {
      element.functionSignature.orderedForEachParameter((_parameter) {
        ParameterElement parameter = _parameter;
        parameters[parameter] = TypeMaskFactory.inferredTypeForParameter(
            parameter, globalInferenceResults);
      });
    }

    localsHandler.startFunction(
        element,
        closureDataLookup.getScopeInfo(element),
        closureDataLookup.getCapturedScope(element),
        parameters,
        sourceInformationBuilder.buildDeclaration(element),
        isGenerativeConstructorBody: element.isGenerativeConstructorBody);
    close(new HGoto()).addSuccessor(block);

    open(block);

    // Add the type parameters of the class as parameters of this method.  This
    // must be done before adding the normal parameters, because their types
    // may contain references to type variables.
    ClassElement cls = element.enclosingClass;
    if ((element.isConstructor || element.isGenerativeConstructorBody) &&
        rtiNeed.classNeedsTypeArguments(cls)) {
      cls.typeVariables.forEach((_typeVariable) {
        ResolutionTypeVariableType typeVariable = _typeVariable;
        HParameterValue param =
            addParameter(typeVariable.element, commonMasks.nonNullType);
        localsHandler.directLocals[
            localsHandler.getTypeVariableAsLocal(typeVariable)] = param;
      });
    }

    if (element is MethodElement) {
      MethodElement functionElement = element;
      FunctionSignature signature = functionElement.functionSignature;

      // Put the type checks in the first successor of the entry,
      // because that is where the type guards will also be inserted.
      // This way we ensure that a type guard will dominate the type
      // check.
      signature.forEachParameter((_parameterElement) {
        ParameterElement parameterElement = _parameterElement;
        if (element.isGenerativeConstructorBody) {
          if (closureDataLookup
              .getCapturedScope(element)
              .isBoxed(parameterElement)) {
            // The parameter will be a field in the box passed as the
            // last parameter. So no need to have it.
            return;
          }
        }
        HInstruction newParameter =
            localsHandler.directLocals[parameterElement];
        if (!element.isConstructor ||
            !(element as ConstructorElement).isRedirectingFactory) {
          // Redirection factories must not check their argument types.
          // Example:
          //
          //     class A {
          //       A(String foo) = A.b;
          //       A.b(int foo) { print(foo); }
          //     }
          //     main() {
          //       new A(499);    // valid even in checked mode.
          //       new A("foo");  // invalid in checked mode.
          //
          // Only the final target is allowed to check for the argument types.
          newParameter = typeBuilder.potentiallyCheckOrTrustType(
              newParameter, parameterElement.type);
        }
        localsHandler.directLocals[parameterElement] = newParameter;
      });

      returnType = signature.type.returnType;
    } else {
      // Otherwise it is a lazy initializer which does not have parameters.
      assert(element is VariableElement);
    }

    insertTraceCall(element);
    insertCoverageCall(element);
  }

  insertTraceCall(Element element) {
    if (JavaScriptBackend.TRACE_METHOD == 'console') {
      if (element == commonElements.traceHelper) return;
      n(e) => e == null ? '' : e.name;
      String name = "${n(element.library)}:${n(element.enclosingClass)}."
          "${n(element)}";
      HConstant nameConstant = addConstantString(name);
      add(new HInvokeStatic(
          commonElements.traceHelper,
          <HInstruction>[nameConstant],
          commonMasks.dynamicType,
          const <DartType>[]));
    }
  }

  insertCoverageCall(Element element) {
    if (JavaScriptBackend.TRACE_METHOD == 'post') {
      if (element == commonElements.traceHelper) return;
      // TODO(sigmund): create a better uuid for elements.
      HConstant idConstant =
          graph.addConstantInt(element.hashCode, closedWorld);
      HConstant nameConstant = addConstantString(element.name);
      add(new HInvokeStatic(
          commonElements.traceHelper,
          <HInstruction>[idConstant, nameConstant],
          commonMasks.dynamicType,
          const <DartType>[]));
    }
  }

  void assertIsSubtype(ast.Node node, ResolutionDartType subtype,
      ResolutionDartType supertype, String message) {
    HInstruction subtypeInstruction = typeBuilder.analyzeTypeArgument(
        localsHandler.substInContext(subtype), sourceElement);
    HInstruction supertypeInstruction = typeBuilder.analyzeTypeArgument(
        localsHandler.substInContext(supertype), sourceElement);
    HInstruction messageInstruction =
        graph.addConstantString(message, closedWorld);
    MethodElement element = commonElements.assertIsSubtype;
    var inputs = <HInstruction>[
      subtypeInstruction,
      supertypeInstruction,
      messageInstruction
    ];
    HInstruction assertIsSubtype = new HInvokeStatic(element, inputs,
        subtypeInstruction.instructionType, const <DartType>[]);
    registry?.registerTypeVariableBoundsSubtypeCheck(subtype, supertype);
    add(assertIsSubtype);
  }

  HGraph closeFunction() {
    // TODO(kasperl): Make this goto an implicit return.
    if (!isAborted()) closeAndGotoExit(new HGoto());
    graph.finalize();
    return graph;
  }

  void pushWithPosition(HInstruction instruction, ast.Node node) {
    push(attachPosition(instruction, node));
  }

  /// Pops the most recent instruction from the stack and 'boolifies' it.
  ///
  /// Boolification is checking if the value is '=== true'.
  @override
  HInstruction popBoolified() {
    HInstruction value = pop();
    if (typeBuilder.checkOrTrustTypes) {
      ResolutionInterfaceType boolType = commonElements.boolType;
      return typeBuilder.potentiallyCheckOrTrustType(value, boolType,
          kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK);
    }
    HInstruction result = new HBoolify(value, commonMasks.boolType)
      ..sourceInformation = value.sourceInformation;
    add(result);
    return result;
  }

  HInstruction attachPosition(HInstruction target, ast.Node node) {
    if (node != null) {
      target.sourceInformation = sourceInformationBuilder.buildGeneric(node);
    }
    return target;
  }

  void visit(ast.Node node) {
    if (node != null) node.accept(this);
  }

  /// Visit [node] and pop the resulting [HInstruction].
  HInstruction visitAndPop(ast.Node node) {
    node.accept(this);
    return pop();
  }

  visitAssert(ast.Assert node) {
    if (!options.enableUserAssertions) return;

    if (!node.hasMessage) {
      // Generate:
      //
      //     assertHelper(condition);
      //
      visit(node.condition);
      pushInvokeStatic(node, commonElements.assertHelper, [pop()]);
      pop();
      return;
    }
    // Assert has message. Generate:
    //
    //     if (assertTest(condition)) assertThrow(message);
    //
    void buildCondition() {
      visit(node.condition);
      pushInvokeStatic(node, commonElements.assertTest, [pop()]);
    }

    void fail() {
      visit(node.message);
      pushInvokeStatic(node, commonElements.assertThrow, [pop()]);
      pop();
    }

    handleIf(node: node, visitCondition: buildCondition, visitThen: fail);
  }

  visitBlock(ast.Block node) {
    assert(!isAborted());
    if (!isReachable) return; // This can only happen when inlining.
    for (Link<ast.Node> link = node.statements.nodes;
        !link.isEmpty;
        link = link.tail) {
      visit(link.head);
      if (!isReachable) {
        // The block has been aborted by a return or a throw.
        if (!stack.isEmpty) {
          reporter.internalError(node, 'Non-empty instruction stack.');
        }
        return;
      }
    }
    assert(!current.isClosed());
    if (!stack.isEmpty) {
      reporter.internalError(node, 'Non-empty instruction stack.');
    }
  }

  visitClassNode(ast.ClassNode node) {
    reporter.internalError(
        node, 'SsaBuilder.visitClassNode should not be called.');
  }

  visitThrowExpression(ast.Expression expression) {
    bool old = inExpressionOfThrow;
    try {
      inExpressionOfThrow = true;
      visit(expression);
    } finally {
      inExpressionOfThrow = old;
    }
  }

  visitExpressionStatement(ast.ExpressionStatement node) {
    if (!isReachable) return;
    ast.Throw throwExpression = node.expression.asThrow();
    if (throwExpression != null && inliningStack.isEmpty) {
      visitThrowExpression(throwExpression.expression);
      handleInTryStatement();
      closeAndGotoExit(
          new HThrow(pop(), sourceInformationBuilder.buildThrow(node)));
    } else {
      visit(node.expression);
      pop();
    }
  }

  visitFor(ast.For node) {
    assert(isReachable);
    assert(node.body != null);
    void buildInitializer() {
      ast.Node initializer = node.initializer;
      if (initializer == null) return;
      visit(initializer);
      if (initializer.asExpression() != null) {
        pop();
      }
    }

    HInstruction buildCondition() {
      if (node.condition == null) {
        return graph.addConstantBool(true, closedWorld);
      }
      visit(node.condition);
      return popBoolified();
    }

    void buildUpdate() {
      for (ast.Expression expression in node.update) {
        visit(expression);
        assert(!isAborted());
        // The result of the update instruction isn't used, and can just
        // be dropped.
        pop();
      }
    }

    void buildBody() {
      visit(node.body);
    }

    loopHandler.handleLoop(
        node,
        closureDataLookup.getCapturedLoopScope(node),
        elements.getTargetDefinition(node),
        buildInitializer,
        buildCondition,
        buildUpdate,
        buildBody,
        sourceInformationBuilder.buildLoop(node));
  }

  visitWhile(ast.While node) {
    assert(isReachable);
    HInstruction buildCondition() {
      visit(node.condition);
      return popBoolified();
    }

    loopHandler.handleLoop(node, closureDataLookup.getCapturedLoopScope(node),
        elements.getTargetDefinition(node), () {}, buildCondition, () {}, () {
      visit(node.body);
    }, sourceInformationBuilder.buildLoop(node));
  }

  visitDoWhile(ast.DoWhile node) {
    assert(isReachable);
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildLoop(node);
    LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
    var loopClosureInfo = closureDataLookup.getCapturedLoopScope(node);
    localsHandler.startLoop(loopClosureInfo, sourceInformation);
    loopDepth++;
    JumpTarget target = elements.getTargetDefinition(node);
    JumpHandler jumpHandler = loopHandler.beginLoopHeader(node, target);
    HLoopInformation loopInfo = current.loopInformation;
    HBasicBlock loopEntryBlock = current;
    HBasicBlock bodyEntryBlock = current;
    bool hasContinues = target != null && target.isContinueTarget;
    if (hasContinues) {
      // Add extra block to hang labels on.
      // It doesn't currently work if they are on the same block as the
      // HLoopInfo. The handling of HLabeledBlockInformation will visit a
      // SubGraph that starts at the same block again, so the HLoopInfo is
      // either handled twice, or it's handled after the labeled block info,
      // both of which generate the wrong code.
      // Using a separate block is just a simple workaround.
      bodyEntryBlock = openNewBlock();
    }
    localsHandler.enterLoopBody(loopClosureInfo, sourceInformation);
    visit(node.body);

    // If there are no continues we could avoid the creation of the condition
    // block. This could also lead to a block having multiple entries and exits.
    HBasicBlock bodyExitBlock;
    bool isAbortingBody = false;
    if (current != null) {
      bodyExitBlock = close(new HGoto());
    } else {
      isAbortingBody = true;
      bodyExitBlock = lastOpenedBlock;
    }

    SubExpression conditionExpression;
    bool loopIsDegenerate = isAbortingBody && !hasContinues;
    if (!loopIsDegenerate) {
      HBasicBlock conditionBlock = addNewBlock();

      List<LocalsHandler> continueHandlers = <LocalsHandler>[];
      jumpHandler
          .forEachContinue((HContinue instruction, LocalsHandler locals) {
        instruction.block.addSuccessor(conditionBlock);
        continueHandlers.add(locals);
      });

      if (!isAbortingBody) {
        bodyExitBlock.addSuccessor(conditionBlock);
      }

      if (!continueHandlers.isEmpty) {
        if (!isAbortingBody) continueHandlers.add(localsHandler);
        localsHandler =
            savedLocals.mergeMultiple(continueHandlers, conditionBlock);
        SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
        List<LabelDefinition> labels = jumpHandler.labels;
        HSubGraphBlockInformation bodyInfo =
            new HSubGraphBlockInformation(bodyGraph);
        HLabeledBlockInformation info;
        if (!labels.isEmpty) {
          info =
              new HLabeledBlockInformation(bodyInfo, labels, isContinue: true);
        } else {
          info = new HLabeledBlockInformation.implicit(bodyInfo, target,
              isContinue: true);
        }
        bodyEntryBlock.setBlockFlow(info, conditionBlock);
      }
      open(conditionBlock);

      visit(node.condition);
      assert(!isAborted());
      HInstruction conditionInstruction = popBoolified();
      HBasicBlock conditionEndBlock = close(
          new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP));

      HBasicBlock avoidCriticalEdge = addNewBlock();
      conditionEndBlock.addSuccessor(avoidCriticalEdge);
      open(avoidCriticalEdge);
      close(new HGoto());
      avoidCriticalEdge.addSuccessor(loopEntryBlock); // The back-edge.

      conditionExpression =
          new SubExpression(conditionBlock, conditionEndBlock);

      // Avoid a critical edge from the condition to the loop-exit body.
      HBasicBlock conditionExitBlock = addNewBlock();
      open(conditionExitBlock);
      close(new HGoto());
      conditionEndBlock.addSuccessor(conditionExitBlock);

      loopHandler.endLoop(
          loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler);

      loopEntryBlock.postProcessLoopHeader();
      SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock);
      HLoopBlockInformation loopBlockInfo = new HLoopBlockInformation(
          HLoopBlockInformation.DO_WHILE_LOOP,
          null,
          wrapExpressionGraph(conditionExpression),
          wrapStatementGraph(bodyGraph),
          null,
          loopEntryBlock.loopInformation.target,
          loopEntryBlock.loopInformation.labels,
          sourceInformation);
      loopEntryBlock.setBlockFlow(loopBlockInfo, current);
      loopInfo.loopBlockInformation = loopBlockInfo;
    } else {
      // Since the loop has no back edge, we remove the loop information on the
      // header.
      loopEntryBlock.loopInformation = null;

      if (jumpHandler.hasAnyBreak()) {
        // Null branchBlock because the body of the do-while loop always aborts,
        // so we never get to the condition.
        loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler);

        // Since the body of the loop has a break, we attach a synthesized label
        // to the body.
        SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
        JumpTarget target = elements.getTargetDefinition(node);
        LabelDefinition label =
            target.addLabel(null, 'loop', isBreakTarget: true);
        HLabeledBlockInformation info = new HLabeledBlockInformation(
            new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]);
        loopEntryBlock.setBlockFlow(info, current);
        jumpHandler.forEachBreak((HBreak breakInstruction, _) {
          HBasicBlock block = breakInstruction.block;
          block.addAtExit(new HBreak.toLabel(label, sourceInformation));
          block.remove(breakInstruction);
        });
      }
    }
    jumpHandler.close();
    loopDepth--;
  }

  visitFunctionExpression(ast.FunctionExpression node) {
    ClosureRepresentationInfo closureInfo =
        closureDataLookup.getClosureInfo(node);
    ClassEntity closureClassEntity = closureInfo.closureClassEntity;

    List<HInstruction> capturedVariables = <HInstruction>[];
    compiler.codegenWorldBuilder.forEachInstanceField(closureClassEntity,
        (_, FieldEntity field) {
      capturedVariables
          .add(localsHandler.readLocal(closureInfo.getLocalForField(field)));
    });

    TypeMask type = new TypeMask.nonNullExact(closureClassEntity, closedWorld);
    push(new HCreate(closureClassEntity, capturedVariables, type,
        sourceInformationBuilder.buildCreate(node),
        callMethod: closureInfo.callMethod));
  }

  visitFunctionDeclaration(ast.FunctionDeclaration node) {
    assert(isReachable);
    visit(node.function);
    LocalFunctionElement localFunction =
        elements.getFunctionDefinition(node.function);
    localsHandler.updateLocal(localFunction, pop());
  }

  @override
  void visitThisGet(ast.Identifier node, [_]) {
    stack.add(localsHandler.readThis(
        sourceInformation: sourceInformationBuilder.buildGet(node)));
  }

  visitIdentifier(ast.Identifier node) {
    if (node.isThis()) {
      visitThisGet(node);
    } else {
      reporter.internalError(
          node, "SsaFromAstMixin.visitIdentifier on non-this.");
    }
  }

  void handleIf(
      {ast.Node node,
      void visitCondition(),
      void visitThen(),
      void visitElse(),
      SourceInformation sourceInformation}) {
    SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node);
    branchBuilder.handleIf(visitCondition, visitThen, visitElse,
        sourceInformation: sourceInformation);
  }

  visitIf(ast.If node) {
    assert(isReachable);
    handleIf(
        node: node,
        visitCondition: () => visit(node.condition),
        visitThen: () => visit(node.thenPart),
        visitElse: node.elsePart != null ? () => visit(node.elsePart) : null,
        sourceInformation: sourceInformationBuilder.buildIf(node));
  }

  @override
  void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) {
    SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
    brancher.handleIfNull(() => visit(left), () => visit(right));
  }

  /// Optimizes logical binary where the left is also a logical binary.
  ///
  /// This method transforms the operator by optimizing the case where [left] is
  /// a logical "and" or logical "or". Then it uses [branchBuilder] to build the
  /// graph for the optimized expression.
  ///
  /// For example, `(x && y) && z` is transformed into `x && (y && z)`:
  ///
  ///     t0 = boolify(x);
  ///     if (t0) {
  ///       t1 = boolify(y);
  ///       if (t1) {
  ///         t2 = boolify(z);
  ///       }
  ///       t3 = phi(t2, false);
  ///     }
  ///     result = phi(t3, false);
  void handleLogicalBinaryWithLeftNode(ast.Node left, void visitRight(),
      SsaBranchBuilder branchBuilder, SourceInformation sourceInformation,
      {bool isAnd}) {
    ast.Send send = left.asSend();
    if (send != null && (isAnd ? send.isLogicalAnd : send.isLogicalOr)) {
      ast.Node newLeft = send.receiver;
      Link<ast.Node> link = send.argumentsNode.nodes;
      assert(link.tail.isEmpty);
      ast.Node middle = link.head;
      handleLogicalBinaryWithLeftNode(
          newLeft,
          () => handleLogicalBinaryWithLeftNode(middle, visitRight,
              branchBuilder, sourceInformationBuilder.buildBinary(middle),
              isAnd: isAnd),
          branchBuilder,
          sourceInformation,
          isAnd: isAnd);
    } else {
      branchBuilder.handleLogicalBinary(
          () => visit(left), visitRight, sourceInformation,
          isAnd: isAnd);
    }
  }

  @override
  void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) {
    SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node);
    handleLogicalBinaryWithLeftNode(left, () => visit(right), branchBuilder,
        sourceInformationBuilder.buildBinary(node),
        isAnd: true);
  }

  @override
  void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) {
    SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node);
    handleLogicalBinaryWithLeftNode(left, () => visit(right), branchBuilder,
        sourceInformationBuilder.buildBinary(node),
        isAnd: false);
  }

  @override
  void visitNot(ast.Send node, ast.Node expression, _) {
    assert(node.argumentsNode is ast.Prefix);
    visit(expression);
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildGeneric(node);
    push(new HNot(popBoolified(), commonMasks.boolType)
      ..sourceInformation = sourceInformation);
  }

  @override
  void visitUnary(
      ast.Send node, UnaryOperator operator, ast.Node expression, _) {
    assert(node.argumentsNode is ast.Prefix);
    HInstruction operand = visitAndPop(expression);

    // See if we can constant-fold right away. This avoids rewrites later on.
    if (operand is HConstant) {
      UnaryOperation operation = constantSystem.lookupUnary(operator);
      HConstant constant = operand;
      ConstantValue folded = operation.fold(constant.constant);
      if (folded != null) {
        stack.add(graph.addConstant(folded, closedWorld));
        return;
      }
    }

    pushInvokeDynamic(node, elements.getSelector(node),
        elementInferenceResults.typeOfSend(node), [operand],
        sourceInformation: sourceInformationBuilder.buildGeneric(node));
  }

  @override
  void visitBinary(ast.Send node, ast.Node left, BinaryOperator operator,
      ast.Node right, _) {
    handleBinary(node, left, right);
  }

  @override
  void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) {
    generateDynamicSend(node);
  }

  @override
  void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) {
    handleBinary(node, left, right);
  }

  @override
  void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) {
    handleBinary(node, left, right);
    pushWithPosition(
        new HNot(popBoolified(), commonMasks.boolType), node.selector);
  }

  void handleBinary(ast.Send node, ast.Node left, ast.Node right) {
    visitBinarySend(
        visitAndPop(left),
        visitAndPop(right),
        elements.getSelector(node),
        elementInferenceResults.typeOfSend(node),
        node,
        sourceInformation:
            sourceInformationBuilder.buildGeneric(node.selector));
  }

  /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and
  /// remove use of [location] for source information.
  void visitBinarySend(HInstruction left, HInstruction right, Selector selector,
      TypeMask mask, ast.Send send,
      {SourceInformation sourceInformation}) {
    pushInvokeDynamic(send, selector, mask, [left, right],
        sourceInformation: sourceInformation);
  }

  HInstruction generateInstanceSendReceiver(ast.Send send) {
    assert(Elements.isInstanceSend(send, elements));
    if (send.receiver == null) {
      return localsHandler.readThis(
          sourceInformation: sourceInformationBuilder.buildGet(send));
    }
    visit(send.receiver);
    return pop();
  }

  String noSuchMethodTargetSymbolString(Element error, [String prefix]) {
    String result = error.name;
    if (prefix == "set") return "$result=";
    return result;
  }

  /**
   * Returns a set of interceptor classes that contain the given
   * [selector].
   */
  void generateInstanceGetterWithCompiledReceiver(
      ast.Send send, Selector selector, TypeMask mask, HInstruction receiver) {
    assert(Elements.isInstanceSend(send, elements));
    assert(selector.isGetter);
    pushInvokeDynamic(send, selector, mask, [receiver],
        sourceInformation: sourceInformationBuilder.buildGet(send));
  }

  /// Inserts a call to checkDeferredIsLoaded for a deferred [import].
  /// If [import] is [null], do nothing.
  void generateIsDeferredLoadedCheckIfNeeded(
      ImportElement import, ast.Node location) {
    if (import == null) return;
    String loadId = deferredLoadTask.getImportDeferName(location, import);
    HInstruction loadIdConstant = addConstantString(loadId);
    String uri = import.uri.toString();
    HInstruction uriConstant = addConstantString(uri);
    MethodElement helper = commonElements.checkDeferredIsLoaded;
    pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]);
    pop();
  }

  /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that
  /// resolves to a deferred library.
  void generateIsDeferredLoadedCheckOfSend(ast.Send node) {
    generateIsDeferredLoadedCheckIfNeeded(
        deferredLoadTask.deferredImportElement(node, elements), node);
  }

  void handleInvalidStaticGet(ast.Send node, Element element) {
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildGet(node);
    generateThrowNoSuchMethod(
        node, noSuchMethodTargetSymbolString(element, 'get'),
        argumentNodes: const Link<ast.Node>(),
        sourceInformation: sourceInformation);
  }

  /// Generate read access of an unresolved static or top level entity.
  void generateStaticUnresolvedGet(ast.Send node, Element element) {
    if (element is ErroneousElement) {
      // An erroneous element indicates an unresolved static getter.
      handleInvalidStaticGet(node, element);
    } else {
      // This happens when [element] has parse errors.
      assert(element == null || element.isMalformed, failedAt(node));
      // TODO(ahe): Do something like the above, that is, emit a runtime
      // error.
      stack.add(graph.addConstantNull(closedWorld));
    }
  }

  /// Read a static or top level [field] of constant value.
  void generateStaticConstGet(ast.Send node, FieldElement field,
      ConstantExpression constant, SourceInformation sourceInformation) {
    ConstantValue value = constants.getConstantValue(constant);
    HConstant instruction;
    // Constants that are referred via a deferred prefix should be referred
    // by reference.
    ImportElement deferredImport =
        deferredLoadTask.deferredImportElement(node, elements);
    if (deferredImport != null) {
      OutputUnit unit =
          compiler.backend.outputUnitData.outputUnitForMember(field);
      instruction = graph.addDeferredConstant(
          value, unit, sourceInformation, compiler, closedWorld);
    } else {
      instruction = graph.addConstant(value, closedWorld,
          sourceInformation: sourceInformation);
    }
    stack.add(instruction);
    // The inferrer may have found a better type than the constant
    // handler in the case of lists, because the constant handler
    // does not look at elements in the list.
    TypeMask type =
        TypeMaskFactory.inferredTypeForMember(field, globalInferenceResults);
    if (!type.containsAll(closedWorld) && !instruction.isConstantNull()) {
      // TODO(13429): The inferrer should know that an element
      // cannot be null.
      instruction.instructionType = type.nonNullable();
    }
  }

  @override
  void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) {
    generateIsDeferredLoadedCheckIfNeeded(prefix.deferredImport, node);
  }

  /// Read a static or top level [field].
  void generateStaticFieldGet(ast.Send node, FieldElement field) {
    ConstantExpression constant = field.constant;
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildGet(node.selector);
    if (constant != null) {
      if (!field.isAssignable) {
        // A static final or const. Get its constant value and inline it if
        // the value can be compiled eagerly.
        generateStaticConstGet(node, field, constant, sourceInformation);
      } else {
        // TODO(5346): Try to avoid the need for calling [declaration] before
        // creating an [HStatic].
        HInstruction instruction = new HStatic(
            field,
            TypeMaskFactory.inferredTypeForMember(
                field, globalInferenceResults),
            sourceInformation);
        push(instruction);
      }
    } else {
      HInstruction instruction = new HLazyStatic(
          field,
          TypeMaskFactory.inferredTypeForMember(field, globalInferenceResults),
          sourceInformation);
      push(instruction);
    }
  }

  /// Generate a getter invocation of the static or top level [getter].
  void generateStaticGetterGet(ast.Send node, MethodElement getter) {
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildGet(node.selector);
    if (getter.isDeferredLoaderGetter) {
      generateDeferredLoaderGet(node, getter, sourceInformation);
    } else {
      pushInvokeStatic(node, getter, <HInstruction>[],
          sourceInformation: sourceInformation);
    }
  }

  /// Generate a dynamic getter invocation.
  void generateDynamicGet(ast.Send node) {
    HInstruction receiver = generateInstanceSendReceiver(node);
    generateInstanceGetterWithCompiledReceiver(node, elements.getSelector(node),
        elementInferenceResults.typeOfSend(node), receiver);
  }

  /// Generate a closurization of the static or top level [method].
  void generateStaticFunctionGet(ast.Send node, MethodElement method) {
    assert(method.isDeclaration);
    // TODO(5346): Try to avoid the need for calling [declaration] before
    // creating an [HStatic].
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildGet(node.selector);
    push(new HStatic(method, commonMasks.nonNullType, sourceInformation));
  }

  /// Read a local variable, function or parameter.
  void buildLocalGet(LocalElement local, SourceInformation sourceInformation) {
    stack.add(
        localsHandler.readLocal(local, sourceInformation: sourceInformation));
  }

  void handleLocalGet(ast.Send node, LocalElement local) {
    buildLocalGet(local, sourceInformationBuilder.buildGet(node));
  }

  @override
  void visitDynamicPropertyGet(ast.Send node, ast.Node receiver, Name name, _) {
    generateDynamicGet(node);
  }

  @override
  void visitIfNotNullDynamicPropertyGet(
      ast.Send node, ast.Node receiver, Name name, _) {
    // exp?.x compiled as:
    //   t1 = exp;
    //   result = t1 == null ? t1 : t1.x;
    // This is equivalent to t1 == null ? null : t1.x, but in the current form
    // we will be able to later compress it as:
    //   t1 || t1.x
    HInstruction expression;
    SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
    brancher.handleConditional(
        () {
          expression = visitAndPop(receiver);
          pushCheckNull(expression);
        },
        () => stack.add(expression),
        () {
          generateInstanceGetterWithCompiledReceiver(
              node,
              elements.getSelector(node),
              elementInferenceResults.typeOfSend(node),
              expression);
        });
  }

  @override
  void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) {
    handleLocalGet(node, variable);
  }

  @override
  void visitParameterGet(ast.Send node, ParameterElement parameter, _) {
    handleLocalGet(node, parameter);
  }

  @override
  void visitLocalFunctionGet(ast.Send node, LocalFunctionElement function, _) {
    handleLocalGet(node, function);
  }

  @override
  void visitStaticFieldGet(ast.Send node, FieldElement field, _) {
    generateStaticFieldGet(node, field);
  }

  @override
  void visitStaticFunctionGet(ast.Send node, MethodElement function, _) {
    generateStaticFunctionGet(node, function);
  }

  @override
  void visitStaticGetterGet(ast.Send node, FunctionElement getter, _) {
    generateStaticGetterGet(node, getter);
  }

  @override
  void visitThisPropertyGet(ast.Send node, Name name, _) {
    generateDynamicGet(node);
  }

  @override
  void visitTopLevelFieldGet(ast.Send node, FieldElement field, _) {
    generateStaticFieldGet(node, field);
  }

  @override
  void visitTopLevelFunctionGet(ast.Send node, MethodElement function, _) {
    generateStaticFunctionGet(node, function);
  }

  @override
  void visitTopLevelGetterGet(ast.Send node, FunctionElement getter, _) {
    generateStaticGetterGet(node, getter);
  }

  void generateInstanceSetterWithCompiledReceiver(
      ast.Send send, HInstruction receiver, HInstruction value,
      {Selector selector, TypeMask mask, ast.Node location}) {
    assert(
        send == null || Elements.isInstanceSend(send, elements),
        failedAt(
            send ?? location,
            "Unexpected instance setter"
            "${send != null ? " element: ${elements[send]}" : ""}"));
    if (selector == null) {
      assert(send != null);
      selector = elements.getSelector(send);
      mask ??= elementInferenceResults.typeOfSend(send);
    }
    if (location == null) {
      assert(send != null);
      location = send;
    }
    assert(selector.isSetter);
    pushInvokeDynamic(location, selector, mask, [receiver, value],
        sourceInformation: sourceInformationBuilder.buildAssignment(location));
    pop();
    stack.add(value);
  }

  void generateNoSuchSetter(
      ast.Node location, Element element, HInstruction value) {
    List<HInstruction> arguments =
        value == null ? const <HInstruction>[] : <HInstruction>[value];
    // An erroneous element indicates an unresolved static setter.
    generateThrowNoSuchMethod(
        location, noSuchMethodTargetSymbolString(element, 'set'),
        argumentValues: arguments);
  }

  void generateNonInstanceSetter(
      ast.SendSet send, Element element, HInstruction value,
      {ast.Node location}) {
    if (location == null) {
      assert(send != null);
      location = send;
    }
    assert(send == null || !Elements.isInstanceSend(send, elements),
        failedAt(location, "Unexpected non instance setter: $element."));
    if (Elements.isStaticOrTopLevelField(element)) {
      if (element.isSetter) {
        pushInvokeStatic(location, element, <HInstruction>[value]);
        pop();
      } else {
        FieldElement field = element;
        value = typeBuilder.potentiallyCheckOrTrustType(value, field.type);
        addWithPosition(new HStaticStore(field, value), location);
      }
      stack.add(value);
    } else if (Elements.isError(element)) {
      generateNoSuchSetter(location, element, send == null ? null : value);
    } else if (Elements.isMalformed(element)) {
      // TODO(ahe): Do something like [generateWrongArgumentCountError].
      stack.add(graph.addConstantNull(closedWorld));
    } else {
      stack.add(value);
      LocalElement local = element;
      // If the value does not already have a name, give it here.
      if (value.sourceElement == null) {
        value.sourceElement = local;
      }
      HInstruction checkedOrTrusted =
          typeBuilder.potentiallyCheckOrTrustType(value, local.type);
      if (!identical(checkedOrTrusted, value)) {
        pop();
        stack.add(checkedOrTrusted);
      }

      localsHandler.updateLocal(local, checkedOrTrusted,
          sourceInformation:
              sourceInformationBuilder.buildAssignment(location));
    }
  }

  HInstruction invokeInterceptor(HInstruction receiver) {
    HInterceptor interceptor =
        new HInterceptor(receiver, commonMasks.nonNullType);
    add(interceptor);
    return interceptor;
  }

  @override
  void visitAs(ast.Send node, ast.Node expression, ResolutionDartType type, _) {
    HInstruction expressionInstruction = visitAndPop(expression);
    if (type.isMalformed) {
      if (type is MalformedType) {
        ErroneousElement element = type.element;
        generateTypeError(node, element.message);
      } else {
        assert(type is MethodTypeVariableType);
        stack.add(expressionInstruction);
      }
    } else {
      HInstruction converted = typeBuilder.buildTypeConversion(
          expressionInstruction,
          localsHandler.substInContext(type),
          HTypeConversion.CAST_TYPE_CHECK,
          sourceInformation: sourceInformationBuilder.buildAs(node));
      if (converted != expressionInstruction) add(converted);
      stack.add(converted);
    }
  }

  @override
  void visitIs(ast.Send node, ast.Node expression, ResolutionDartType type, _) {
    HInstruction expressionInstruction = visitAndPop(expression);
    push(buildIsNode(node, type, expressionInstruction,
        sourceInformationBuilder.buildIs(node)));
  }

  @override
  void visitIsNot(
      ast.Send node, ast.Node expression, ResolutionDartType type, _) {
    HInstruction expressionInstruction = visitAndPop(expression);
    HInstruction instruction = buildIsNode(node, type, expressionInstruction,
        sourceInformationBuilder.buildIs(node));
    add(instruction);
    push(new HNot(instruction, commonMasks.boolType));
  }

  HInstruction buildIsNode(ast.Node node, ResolutionDartType type,
      HInstruction expression, SourceInformation sourceInformation) {
    type = localsHandler.substInContext(type).unaliased;
    if (type.isMalformed) {
      String message;
      if (type is MethodTypeVariableType) {
        message = "Method type variables are not reified, "
            "so they cannot be tested with an `is` expression.";
      } else {
        assert(type is MalformedType);
        ErroneousElement element = type.element;
        message = element.message;
      }
      generateTypeError(node, message);
      HInstruction call = pop();
      return new HIs.compound(
          type, expression, call, commonMasks.boolType, sourceInformation);
    } else if (type.isFunctionType) {
      HInstruction representation =
          typeBuilder.analyzeTypeArgument(type, sourceElement);
      List<HInstruction> inputs = <HInstruction>[
        expression,
        representation,
      ];
      pushInvokeStatic(node, commonElements.functionTypeTest, inputs,
          typeMask: commonMasks.boolType, sourceInformation: sourceInformation);
      HInstruction call = pop();
      return new HIs.compound(
          type, expression, call, commonMasks.boolType, sourceInformation);
    } else if (type.isTypeVariable) {
      ResolutionTypeVariableType typeVariable = type;
      HInstruction runtimeType =
          typeBuilder.addTypeVariableReference(typeVariable, sourceElement);
      MethodElement helper = commonElements.checkSubtypeOfRuntimeType;
      List<HInstruction> inputs = <HInstruction>[expression, runtimeType];
      pushInvokeStatic(null, helper, inputs,
          typeMask: commonMasks.boolType, sourceInformation: sourceInformation);
      HInstruction call = pop();
      return new HIs.variable(
          type, expression, call, commonMasks.boolType, sourceInformation);
    } else if (RuntimeTypesSubstitutions.hasTypeArguments(type)) {
      ClassElement element = type.element;
      MethodElement helper = commonElements.checkSubtype;
      HInstruction representations =
          typeBuilder.buildTypeArgumentRepresentations(type, sourceElement);
      add(representations);
      js.Name operator = namer.operatorIs(element);
      HInstruction isFieldName = addConstantStringFromName(operator);
      HInstruction asFieldName = closedWorld.hasAnyStrictSubtype(element)
          ? addConstantStringFromName(namer.substitutionName(element))
          : graph.addConstantNull(closedWorld);
      List<HInstruction> inputs = <HInstruction>[
        expression,
        isFieldName,
        representations,
        asFieldName
      ];
      pushInvokeStatic(node, helper, inputs,
          typeMask: commonMasks.boolType, sourceInformation: sourceInformation);
      HInstruction call = pop();
      return new HIs.compound(
          type, expression, call, commonMasks.boolType, sourceInformation);
    } else {
      if (backend.hasDirectCheckFor(closedWorld.commonElements, type)) {
        return new HIs.direct(
            type, expression, commonMasks.boolType, sourceInformation);
      }
      // The interceptor is not always needed.  It is removed by optimization
      // when the receiver type or tested type permit.
      return new HIs.raw(type, expression, invokeInterceptor(expression),
          commonMasks.boolType, sourceInformation);
    }
  }

  void addDynamicSendArgumentsToList(ast.Send node, List<HInstruction> list) {
    CallStructure callStructure = elements.getSelector(node).callStructure;
    if (callStructure.namedArgumentCount == 0) {
      addGenericSendArgumentsToList(node.arguments, list);
    } else {
      // Visit positional arguments and add them to the list.
      Link<ast.Node> arguments = node.arguments;
      int positionalArgumentCount = callStructure.positionalArgumentCount;
      for (int i = 0;
          i < positionalArgumentCount;
          arguments = arguments.tail, i++) {
        visit(arguments.head);
        list.add(pop());
      }

      // Visit named arguments and add them into a temporary map.
      Map<String, HInstruction> instructions = new Map<String, HInstruction>();
      List<String> namedArguments = callStructure.namedArguments;
      int nameIndex = 0;
      for (; !arguments.isEmpty; arguments = arguments.tail) {
        visit(arguments.head);
        instructions[namedArguments[nameIndex++]] = pop();
      }

      // Iterate through the named arguments to add them to the list
      // of instructions, in an order that can be shared with
      // selectors with the same named arguments.
      List<String> orderedNames = callStructure.getOrderedNamedArguments();
      for (String name in orderedNames) {
        list.add(instructions[name]);
      }
    }
  }

  /**
   * Returns a list with the evaluated [arguments] in the normalized order.
   *
   * Precondition: `this.applies(element, world)`.
   * Invariant: [element] must be an implementation element.
   */
  List<HInstruction> makeStaticArgumentList(CallStructure callStructure,
      Link<ast.Node> arguments, MethodElement element) {
    assert(element.isDeclaration, failedAt(element));

    HInstruction compileArgument(ast.Node argument) {
      visit(argument);
      return pop();
    }

    return Elements.makeArgumentsList<HInstruction>(
        callStructure,
        arguments,
        element.implementation,
        compileArgument,
        nativeData.isJsInteropMember(element)
            ? handleConstantForOptionalParameterJsInterop
            : handleConstantForOptionalParameter);
  }

  void addGenericSendArgumentsToList(
      Link<ast.Node> link, List<HInstruction> list) {
    for (; !link.isEmpty; link = link.tail) {
      visit(link.head);
      list.add(pop());
    }
  }

  /// Generate a dynamic method, getter or setter invocation.
  void generateDynamicSend(ast.Send node) {
    HInstruction receiver = generateInstanceSendReceiver(node);
    _generateDynamicSend(node, receiver);
  }

  void _generateDynamicSend(ast.Send node, HInstruction receiver) {
    Selector selector = elements.getSelector(node);
    TypeMask mask = elementInferenceResults.typeOfSend(node);
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildCall(node, node.selector);

    List<HInstruction> inputs = <HInstruction>[];
    inputs.add(receiver);
    addDynamicSendArgumentsToList(node, inputs);

    pushInvokeDynamic(node, selector, mask, inputs,
        sourceInformation: sourceInformation);
    if (selector.isSetter || selector.isIndexSet) {
      pop();
      stack.add(inputs.last);
    }
  }

  @override
  visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver,
      ast.NodeList arguments, Selector selector, _) {
    generateDynamicSend(node);
  }

  @override
  visitIfNotNullDynamicPropertyInvoke(ast.Send node, ast.Node receiver,
      ast.NodeList arguments, Selector selector, _) {
    /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()`
    HInstruction receiver;
    SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
    brancher.handleConditional(() {
      receiver = generateInstanceSendReceiver(node);
      pushCheckNull(receiver);
    }, () => stack.add(receiver), () => _generateDynamicSend(node, receiver));
  }

  @override
  visitThisPropertyInvoke(
      ast.Send node, ast.NodeList arguments, Selector selector, _) {
    generateDynamicSend(node);
  }

  @override
  visitExpressionInvoke(ast.Send node, ast.Node expression,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateCallInvoke(node, visitAndPop(expression),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  visitThisInvoke(
      ast.Send node, ast.NodeList arguments, CallStructure callStructure, _) {
    generateCallInvoke(
        node,
        localsHandler.readThis(
            sourceInformation: sourceInformationBuilder.buildGet(node)),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  visitParameterInvoke(ast.Send node, ParameterElement parameter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateCallInvoke(node, localsHandler.readLocal(parameter),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  visitLocalVariableInvoke(ast.Send node, LocalVariableElement variable,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateCallInvoke(node, localsHandler.readLocal(variable),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  visitLocalFunctionInvoke(ast.Send node, LocalFunctionElement function,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateCallInvoke(node, localsHandler.readLocal(function),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  visitLocalFunctionIncompatibleInvoke(
      ast.Send node,
      LocalFunctionElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    generateCallInvoke(node, localsHandler.readLocal(function),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  void handleForeignJs(ast.Send node) {
    Link<ast.Node> link = node.arguments;
    // Don't visit the first argument, which is the type, and the second
    // argument, which is the foreign code.
    if (link.isEmpty || link.tail.isEmpty) {
      // We should not get here because the call should be compiled to NSM.
      reporter.internalError(
          node.argumentsNode, 'At least two arguments expected.');
    }
    native.NativeBehavior nativeBehavior = elements.getNativeData(node);
    assert(
        nativeBehavior != null, failedAt(node, "No NativeBehavior for $node"));

    List<HInstruction> inputs = <HInstruction>[];
    addGenericSendArgumentsToList(link.tail.tail, inputs);

    if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) {
      reporter.reportErrorMessage(node, MessageKind.GENERIC, {
        'text': 'Mismatch between number of placeholders'
            ' and number of arguments.'
      });
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) {
      reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE);
    }

    TypeMask ssaType =
        TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);

    DartType typeArgument;
    ast.NodeList typeArgumentsNode = node.typeArgumentsNode;
    if (typeArgumentsNode != null) {
      if (typeArgumentsNode.slowLength() == 1) {
        ast.Node typeNode = typeArgumentsNode.single;
        typeArgument = elements.getType(typeNode);
      } else {
        reporter.reportErrorMessage(typeArgumentsNode, MessageKind.GENERIC,
            {'text': 'JS takes one type argument'});
      }
    }

    SourceInformation sourceInformation =
        sourceInformationBuilder.buildCall(node, node.argumentsNode);
    push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs,
        isStatement: !nativeBehavior.codeTemplate.isExpression,
        effects: nativeBehavior.sideEffects,
        nativeBehavior: nativeBehavior)
      ..sourceInformation = sourceInformation);

    HInstruction code = stack.last;
    TypeMask trustedMask = typeBuilder.trustTypeMask(typeArgument);

    if (trustedMask != null) {
      // We only allow the type argument to narrow `dynamic`, which probably
      // comes from an unspecified return type in the NativeBehavior.
      if (code.instructionType.containsAll(closedWorld)) {
        // Overwrite the type with the narrower type.
        code.instructionType = trustedMask;
      } else if (trustedMask.containsMask(code.instructionType, closedWorld)) {
        // It is acceptable for the type parameter to be broader than the
        // specified type.
      } else {
        reporter.reportErrorMessage(typeArgumentsNode, MessageKind.GENERIC, {
          'text': 'Type argument too narrow for specified behavior type '
              '(${trustedMask} does not allow '
              'all values in ${code.instructionType})'
        });
      }
    }
  }

  void handleJsStringConcat(ast.Send node) {
    List<HInstruction> inputs = <HInstruction>[];
    addGenericSendArgumentsToList(node.arguments, inputs);
    if (inputs.length != 2) {
      reporter.internalError(node.argumentsNode, 'Two arguments expected.');
    }
    push(new HStringConcat(inputs[0], inputs[1], commonMasks.stringType));
  }

  void handleForeignJsCurrentIsolateContext(ast.Send node) {
    if (!node.arguments.isEmpty) {
      reporter.internalError(
          node, 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.');
    }

    if (!backendUsage.isIsolateInUse) {
      // If the isolate library is not used, we just generate code
      // to fetch the static state.
      String name = namer.staticStateHolder;
      push(new HForeignCode(
          js.js.parseForeignJS(name), commonMasks.dynamicType, <HInstruction>[],
          nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
    } else {
      // Call a helper method from the isolate library. The isolate
      // library uses its own isolate structure, that encapsulates
      // Leg's isolate.
      MethodElement element = commonElements.currentIsolate;
      if (element == null) {
        reporter.internalError(node, 'Isolate library and compiler mismatch.');
      }
      pushInvokeStatic(null, element, [], typeMask: commonMasks.dynamicType);
    }
  }

  void handleForeignJsGetFlag(ast.Send node) {
    List<ast.Node> arguments = node.arguments.toList();
    ast.Node argument;
    switch (arguments.length) {
      case 0:
        reporter.reportErrorMessage(node, MessageKind.GENERIC,
            {'text': 'Error: Expected one argument to JS_GET_FLAG.'});
        return;
      case 1:
        argument = arguments[0];
        break;
      default:
        for (int i = 1; i < arguments.length; i++) {
          reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC,
              {'text': 'Error: Extra argument to JS_GET_FLAG.'});
        }
        return;
    }
    ast.LiteralString string = argument.asLiteralString();
    if (string == null) {
      reporter.reportErrorMessage(argument, MessageKind.GENERIC,
          {'text': 'Error: Expected a literal string.'});
    }
    String name = string.dartString.slowToString();
    bool value = getFlagValue(name);
    if (value == null) {
      reporter.reportErrorMessage(node, MessageKind.GENERIC,
          {'text': 'Error: Unknown internal flag "$name".'});
    } else {
      stack.add(graph.addConstantBool(value, closedWorld));
    }
  }

  void handleForeignJsGetName(ast.Send node) {
    List<ast.Node> arguments = node.arguments.toList();
    ast.Node argument;
    switch (arguments.length) {
      case 0:
        reporter.reportErrorMessage(node, MessageKind.GENERIC,
            {'text': 'Error: Expected one argument to JS_GET_NAME.'});
        return;
      case 1:
        argument = arguments[0];
        break;
      default:
        for (int i = 1; i < arguments.length; i++) {
          reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC,
              {'text': 'Error: Extra argument to JS_GET_NAME.'});
        }
        return;
    }
    Element element = elements[argument];
    if (element == null ||
        element is! EnumConstantElement ||
        element.enclosingClass != commonElements.jsGetNameEnum) {
      reporter.reportErrorMessage(argument, MessageKind.GENERIC,
          {'text': 'Error: Expected a JsGetName enum value.'});
    }
    EnumConstantElement enumConstant = element;
    int index = enumConstant.index;
    stack.add(addConstantStringFromName(
        namer.getNameForJsGetName(argument, JsGetName.values[index])));
  }

  void handleForeignJsBuiltin(ast.Send node) {
    List<ast.Node> arguments = node.arguments.toList();
    ast.Node argument;
    if (arguments.length < 2) {
      reporter.reportErrorMessage(node, MessageKind.GENERIC,
          {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'});
    }

    Element builtinElement = elements[arguments[1]];
    if (builtinElement == null ||
        (builtinElement is! EnumConstantElement) ||
        builtinElement.enclosingClass != commonElements.jsBuiltinEnum) {
      reporter.reportErrorMessage(argument, MessageKind.GENERIC,
          {'text': 'Error: Expected a JsBuiltin enum value.'});
    }
    EnumConstantElement enumConstant = builtinElement;
    int index = enumConstant.index;

    js.Template template = emitter.builtinTemplateFor(JsBuiltin.values[index]);

    List<HInstruction> compiledArguments = <HInstruction>[];
    for (int i = 2; i < arguments.length; i++) {
      visit(arguments[i]);
      compiledArguments.add(pop());
    }

    native.NativeBehavior nativeBehavior = elements.getNativeData(node);
    assert(
        nativeBehavior != null, failedAt(node, "No NativeBehavior for $node"));

    TypeMask ssaType =
        TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);

    push(new HForeignCode(template, ssaType, compiledArguments,
        nativeBehavior: nativeBehavior));
  }

  void handleForeignJsEmbeddedGlobal(ast.Send node) {
    List<ast.Node> arguments = node.arguments.toList();
    ast.Node globalNameNode;
    switch (arguments.length) {
      case 0:
      case 1:
        reporter.reportErrorMessage(node, MessageKind.GENERIC,
            {'text': 'Error: Expected two arguments to JS_EMBEDDED_GLOBAL.'});
        return;
      case 2:
        // The type has been extracted earlier. We are only interested in the
        // name in this function.
        globalNameNode = arguments[1];
        break;
      default:
        for (int i = 2; i < arguments.length; i++) {
          reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC,
              {'text': 'Error: Extra argument to JS_EMBEDDED_GLOBAL.'});
        }
        return;
    }
    visit(globalNameNode);
    HInstruction globalNameHNode = pop();
    if (!globalNameHNode.isConstantString()) {
      reporter.reportErrorMessage(arguments[1], MessageKind.GENERIC, {
        'text': 'Error: Expected String as second argument '
            'to JS_EMBEDDED_GLOBAL.'
      });
      return;
    }
    HConstant hConstant = globalNameHNode;
    StringConstantValue constant = hConstant.constant;
    String globalName = constant.stringValue;
    js.Template expr = js.js.expressionTemplateYielding(
        emitter.generateEmbeddedGlobalAccess(globalName));
    native.NativeBehavior nativeBehavior = elements.getNativeData(node);
    assert(
        nativeBehavior != null, failedAt(node, "No NativeBehavior for $node"));
    TypeMask ssaType =
        TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
    push(new HForeignCode(expr, ssaType, const [],
        nativeBehavior: nativeBehavior));
  }

  void handleJsInterceptorConstant(ast.Send node) {
    // Single argument must be a TypeConstant which is converted into a
    // InterceptorConstant.
    if (!node.arguments.isEmpty && node.arguments.tail.isEmpty) {
      ast.Node argument = node.arguments.head;
      visit(argument);
      HInstruction argumentInstruction = pop();
      if (argumentInstruction is HConstant) {
        ConstantValue argumentConstant = argumentInstruction.constant;
        if (argumentConstant is TypeConstantValue &&
            argumentConstant.representedType is ResolutionInterfaceType) {
          ResolutionInterfaceType type = argumentConstant.representedType;
          ConstantValue constant = new InterceptorConstantValue(type.element);
          HInstruction instruction = graph.addConstant(constant, closedWorld);
          stack.add(instruction);
          return;
        }
      }
    }
    reporter.reportErrorMessage(
        node, MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
    stack.add(graph.addConstantNull(closedWorld));
  }

  void handleForeignJsCallInIsolate(ast.Send node) {
    Link<ast.Node> link = node.arguments;
    if (!backendUsage.isIsolateInUse) {
      // If the isolate library is not used, we just invoke the
      // closure.
      visit(link.tail.head);
      push(new HInvokeClosure(new Selector.callClosure(0),
          <HInstruction>[pop()], commonMasks.dynamicType, const <DartType>[]));
    } else {
      // Call a helper method from the isolate library.
      MethodElement element = commonElements.callInIsolate;
      if (element == null) {
        reporter.internalError(node, 'Isolate library and compiler mismatch.');
      }
      List<HInstruction> inputs = <HInstruction>[];
      addGenericSendArgumentsToList(link, inputs);
      pushInvokeStatic(node, element, inputs,
          typeMask: commonMasks.dynamicType);
    }
  }

  FunctionSignature handleForeignRawFunctionRef(ast.Send node, String name) {
    if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) {
      reporter.internalError(
          node.argumentsNode, '"$name" requires exactly one argument.');
    }
    ast.Node closure = node.arguments.head;
    Element element = elements[closure];
    if (!Elements.isStaticOrTopLevelFunction(element)) {
      reporter.internalError(
          closure, '"$name" requires a static or top-level method.');
    }
    MethodElement function = element;
    // TODO(johnniwinther): Try to eliminate the need to distinguish declaration
    // and implementation signatures. Currently it is need because the
    // signatures have different elements for parameters.
    FunctionElement implementation = function.implementation;
    FunctionSignature params = implementation.functionSignature;
    if (params.optionalParameterCount != 0) {
      reporter.internalError(
          closure, '"$name" does not handle closure with optional parameters.');
    }

    push(new HForeignCode(
        js.js
            .expressionTemplateYielding(emitter.staticFunctionAccess(function)),
        commonMasks.dynamicType,
        <HInstruction>[],
        nativeBehavior: native.NativeBehavior.PURE,
        foreignFunction: function));
    return params;
  }

  void handleForeignDartClosureToJs(ast.Send node, String name) {
    // TODO(ahe): This implements DART_CLOSURE_TO_JS and should probably take
    // care to wrap the closure in another closure that saves the current
    // isolate.
    handleForeignRawFunctionRef(node, name);
  }

  void handleForeignJsSetStaticState(ast.Send node) {
    if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) {
      reporter.internalError(
          node.argumentsNode, 'Exactly one argument required.');
    }
    visit(node.arguments.head);
    String isolateName = namer.staticStateHolder;
    SideEffects sideEffects = new SideEffects.empty();
    sideEffects.setAllSideEffects();
    push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
        commonMasks.dynamicType, <HInstruction>[pop()],
        nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
        effects: sideEffects));
  }

  void handleForeignJsGetStaticState(ast.Send node) {
    if (!node.arguments.isEmpty) {
      reporter.internalError(node.argumentsNode, 'Too many arguments.');
    }
    push(new HForeignCode(js.js.parseForeignJS(namer.staticStateHolder),
        commonMasks.dynamicType, <HInstruction>[],
        nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
  }

  void handleForeignSend(ast.Send node, FunctionElement element) {
    String name = element.name;
    if (name == JavaScriptBackend.JS) {
      handleForeignJs(node);
    } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
      handleForeignJsCurrentIsolateContext(node);
    } else if (name == 'JS_CALL_IN_ISOLATE') {
      handleForeignJsCallInIsolate(node);
    } else if (name == 'DART_CLOSURE_TO_JS') {
      handleForeignDartClosureToJs(node, 'DART_CLOSURE_TO_JS');
    } else if (name == 'RAW_DART_FUNCTION_REF') {
      handleForeignRawFunctionRef(node, 'RAW_DART_FUNCTION_REF');
    } else if (name == 'JS_SET_STATIC_STATE') {
      handleForeignJsSetStaticState(node);
    } else if (name == 'JS_GET_STATIC_STATE') {
      handleForeignJsGetStaticState(node);
    } else if (name == 'JS_GET_NAME') {
      handleForeignJsGetName(node);
    } else if (name == JavaScriptBackend.JS_EMBEDDED_GLOBAL) {
      handleForeignJsEmbeddedGlobal(node);
    } else if (name == JavaScriptBackend.JS_BUILTIN) {
      handleForeignJsBuiltin(node);
    } else if (name == 'JS_GET_FLAG') {
      handleForeignJsGetFlag(node);
    } else if (name == 'JS_EFFECT') {
      stack.add(graph.addConstantNull(closedWorld));
    } else if (name == JavaScriptBackend.JS_INTERCEPTOR_CONSTANT) {
      handleJsInterceptorConstant(node);
    } else if (name == 'JS_STRING_CONCAT') {
      handleJsStringConcat(node);
    } else {
      reporter.internalError(node, "Unknown foreign: ${element}");
    }
  }

  generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader,
      SourceInformation sourceInformation) {
    // Until now we only handle these as getters.
    if (!deferredLoader.isDeferredLoaderGetter) {
      failedAt(node);
    }
    FunctionEntity loadFunction = commonElements.loadLibraryWrapper;
    PrefixElement prefixElement = deferredLoader.enclosingElement;
    String loadId =
        deferredLoadTask.getImportDeferName(node, prefixElement.deferredImport);
    var inputs = [graph.addConstantString(loadId, closedWorld)];
    push(new HInvokeStatic(
        loadFunction, inputs, commonMasks.nonNullType, const <DartType>[],
        targetCanThrow: false)
      ..sourceInformation = sourceInformation);
  }

  generateSuperNoSuchMethodSend(
      ast.Send node, Selector selector, List<HInstruction> arguments) {
    String name = selector.name;

    ClassElement cls = currentNonClosureClass;
    MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
    if (!Selectors.noSuchMethod_.signatureApplies(element)) {
      ClassElement objectClass = commonElements.objectClass;
      element = objectClass.lookupMember(Identifiers.noSuchMethod_);
    }
    if (backendUsage.isInvokeOnUsed && !element.enclosingClass.isObject) {
      // Register the call as dynamic if [noSuchMethod] on the super
      // class is _not_ the default implementation from [Object], in
      // case the [noSuchMethod] implementation calls
      // [JSInvocationMirror._invokeOn].
      // TODO(johnniwinther): Register this more precisely.
      registry
          ?.registerDynamicUse(new ConstrainedDynamicUse(selector, null, null));
    }
    String publicName = name;
    if (selector.isSetter) publicName += '=';

    ConstantValue nameConstant = constantSystem.createString(publicName);

    js.Name internalName = namer.invocationName(selector);

    MethodElement createInvocationMirror =
        commonElements.createInvocationMirror;
    var argumentsInstruction = buildLiteralList(arguments);
    add(argumentsInstruction);

    var argumentNames = new List<HInstruction>();
    for (String argumentName in selector.namedArguments) {
      ConstantValue argumentNameConstant =
          constantSystem.createString(argumentName);
      argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld));
    }
    var argumentNamesInstruction = buildLiteralList(argumentNames);
    add(argumentNamesInstruction);

    ConstantValue kindConstant =
        constantSystem.createInt(selector.invocationMirrorKind);

    pushInvokeStatic(
        null,
        createInvocationMirror,
        [
          graph.addConstant(nameConstant, closedWorld),
          graph.addConstantStringFromName(internalName, closedWorld),
          graph.addConstant(kindConstant, closedWorld),
          argumentsInstruction,
          argumentNamesInstruction
        ],
        typeMask: commonMasks.dynamicType);

    var inputs = <HInstruction>[pop()];
    push(buildInvokeSuper(Selectors.noSuchMethod_, element, inputs,
        sourceInformationBuilder.buildGeneric(node)));
  }

  /// Generate a call to a super method or constructor.
  void generateSuperInvoke(ast.Send node, MethodElement method,
      SourceInformation sourceInformation) {
    // TODO(5347): Try to avoid the need for calling [implementation] before
    // calling [makeStaticArgumentList].
    Selector selector = elements.getSelector(node);
    MethodElement implementation = method.implementation;
    assert(selector.applies(implementation),
        failedAt(node, "$selector does not apply to ${implementation}"));
    List<HInstruction> inputs =
        makeStaticArgumentList(selector.callStructure, node.arguments, method);
    push(buildInvokeSuper(selector, method, inputs, sourceInformation));
  }

  /// Access the value from the super [element].
  void handleSuperGet(ast.Send node, Element element) {
    Selector selector = elements.getSelector(node);
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildGet(node.selector);
    push(buildInvokeSuper(
        selector, element, const <HInstruction>[], sourceInformation));
  }

  /// Invoke .call on the value retrieved from the super [element].
  void handleSuperCallInvoke(ast.Send node, Element element) {
    Selector selector = elements.getSelector(node);
    HInstruction target = buildInvokeSuper(
        selector,
        element,
        const <HInstruction>[],
        sourceInformationBuilder.buildGet(node.selector));
    add(target);
    generateCallInvoke(
        node,
        target,
        sourceInformationBuilder.buildCall(
            node.argumentsNode, node.argumentsNode));
  }

  /// Invoke super [method].
  void handleSuperMethodInvoke(ast.Send node, MethodElement method) {
    generateSuperInvoke(node, method,
        sourceInformationBuilder.buildCall(node.selector, node.selector));
  }

  /// Access an unresolved super property.
  void handleUnresolvedSuperInvoke(ast.Send node) {
    Selector selector = elements.getSelector(node);
    List<HInstruction> arguments = <HInstruction>[];
    if (!node.isPropertyAccess) {
      addGenericSendArgumentsToList(node.arguments, arguments);
    }
    generateSuperNoSuchMethodSend(node, selector, arguments);
  }

  @override
  void visitUnresolvedSuperIndex(
      ast.Send node, Element element, ast.Node index, _) {
    handleUnresolvedSuperInvoke(node);
  }

  @override
  void visitUnresolvedSuperUnary(
      ast.Send node, UnaryOperator operator, Element element, _) {
    handleUnresolvedSuperInvoke(node);
  }

  @override
  void visitUnresolvedSuperBinary(ast.Send node, Element element,
      BinaryOperator operator, ast.Node argument, _) {
    handleUnresolvedSuperInvoke(node);
  }

  @override
  void visitUnresolvedSuperGet(ast.Send node, Element element, _) {
    handleUnresolvedSuperInvoke(node);
  }

  @override
  void visitUnresolvedSuperSet(
      ast.Send node, Element element, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperSetterGet(ast.Send node, MethodElement setter, _) {
    handleUnresolvedSuperInvoke(node);
  }

  @override
  void visitUnresolvedSuperInvoke(
      ast.Send node, Element element, ast.Node argument, Selector selector, _) {
    handleUnresolvedSuperInvoke(node);
  }

  @override
  void visitSuperFieldGet(ast.Send node, FieldElement field, _) {
    handleSuperGet(node, field);
  }

  @override
  void visitSuperGetterGet(ast.Send node, MethodElement method, _) {
    handleSuperGet(node, method);
  }

  @override
  void visitSuperMethodGet(ast.Send node, MethodElement method, _) {
    handleSuperGet(node, method);
  }

  @override
  void visitSuperFieldInvoke(ast.Send node, FieldElement field,
      ast.NodeList arguments, CallStructure callStructure, _) {
    handleSuperCallInvoke(node, field);
  }

  @override
  void visitSuperGetterInvoke(ast.Send node, MethodElement getter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    handleSuperCallInvoke(node, getter);
  }

  @override
  void visitSuperMethodInvoke(ast.Send node, MethodElement method,
      ast.NodeList arguments, CallStructure callStructure, _) {
    handleSuperMethodInvoke(node, method);
  }

  @override
  void visitSuperIndex(ast.Send node, MethodElement method, ast.Node index, _) {
    handleSuperMethodInvoke(node, method);
  }

  @override
  void visitSuperEquals(
      ast.Send node, MethodElement method, ast.Node argument, _) {
    handleSuperMethodInvoke(node, method);
  }

  @override
  void visitSuperBinary(ast.Send node, MethodElement method,
      BinaryOperator operator, ast.Node argument, _) {
    handleSuperMethodInvoke(node, method);
  }

  @override
  void visitSuperNotEquals(
      ast.Send node, MethodElement method, ast.Node argument, _) {
    handleSuperMethodInvoke(node, method);
    pushWithPosition(
        new HNot(popBoolified(), commonMasks.boolType), node.selector);
  }

  @override
  void visitSuperUnary(
      ast.Send node, UnaryOperator operator, MethodElement method, _) {
    handleSuperMethodInvoke(node, method);
  }

  @override
  void visitSuperMethodIncompatibleInvoke(ast.Send node, MethodElement method,
      ast.NodeList arguments, CallStructure callStructure, _) {
    handleInvalidSuperInvoke(node, arguments);
  }

  @override
  void visitSuperSetterInvoke(ast.Send node, SetterElement setter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    handleInvalidSuperInvoke(node, arguments);
  }

  void handleInvalidSuperInvoke(ast.Send node, ast.NodeList arguments) {
    Selector selector = elements.getSelector(node);
    List<HInstruction> inputs = <HInstruction>[];
    addGenericSendArgumentsToList(arguments.nodes, inputs);
    generateSuperNoSuchMethodSend(node, selector, inputs);
  }

  bool needsSubstitutionForTypeVariableAccess(ClassElement cls) {
    if (closedWorld.isUsedAsMixin(cls)) return true;

    return closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) {
      return !rtiSubstitutions.isTrivialSubstitution(subclass, cls);
    });
  }

  HInstruction handleListConstructor(ResolutionInterfaceType type,
      HInstruction newObject, SourceInformation sourceInformation) {
    if (!rtiNeed.classNeedsTypeArguments(type.element) || type.treatAsRaw) {
      return newObject;
    }
    List<HInstruction> inputs = <HInstruction>[];
    type = localsHandler.substInContext(type);
    type.typeArguments.forEach((ResolutionDartType argument) {
      inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement,
          sourceInformation: sourceInformation));
    });
    // TODO(15489): Register at codegen.
    registry?.registerInstantiation(type);
    return callSetRuntimeTypeInfoWithTypeArguments(
        type, inputs, newObject, sourceInformation);
  }

  HInstruction callSetRuntimeTypeInfo(HInstruction typeInfo,
      HInstruction newObject, SourceInformation sourceInformation) {
    // Set the runtime type information on the object.
    MethodElement typeInfoSetterElement = commonElements.setRuntimeTypeInfo;
    pushInvokeStatic(
        null, typeInfoSetterElement, <HInstruction>[newObject, typeInfo],
        typeMask: commonMasks.dynamicType,
        sourceInformation: sourceInformation);

    // The new object will now be referenced through the
    // `setRuntimeTypeInfo` call. We therefore set the type of that
    // instruction to be of the object's type.
    assert(
        stack.last is HInvokeStatic || stack.last == newObject,
        failedAt(
            CURRENT_ELEMENT_SPANNABLE,
            "Unexpected `stack.last`: Found ${stack.last}, "
            "expected ${newObject} or an HInvokeStatic. "
            "State: typeInfo=$typeInfo, stack=$stack."));
    stack.last.instructionType = newObject.instructionType;
    return pop();
  }

  void handleNewSend(ast.NewExpression node) {
    ast.Send send = node.send;
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildNew(send);

    generateIsDeferredLoadedCheckOfSend(send);

    ConstructorElement constructor = elements[send];
    bool isFixedList = false;
    bool isFixedListConstructorCall = Elements.isFixedListConstructorCall(
        constructor, send, closedWorld.commonElements);
    bool isGrowableListConstructorCall = Elements.isGrowableListConstructorCall(
        constructor, send, closedWorld.commonElements);

    TypeMask computeType(element) {
      ConstructorElement originalElement = elements[send];
      if (isFixedListConstructorCall ||
          Elements.isFilledListConstructorCall(
              originalElement, send, closedWorld.commonElements)) {
        isFixedList = true;
        TypeMask inferred = _inferredTypeOfNewList(send);
        return inferred.containsAll(closedWorld)
            ? commonMasks.fixedArrayType
            : inferred;
      } else if (isGrowableListConstructorCall) {
        TypeMask inferred = _inferredTypeOfNewList(send);
        return inferred.containsAll(closedWorld)
            ? commonMasks.extendableArrayType
            : inferred;
      } else if (Elements.isConstructorOfTypedArraySubclass(
          originalElement, closedWorld)) {
        isFixedList = true;
        TypeMask inferred = _inferredTypeOfNewList(send);
        ClassElement cls = element.enclosingClass;
        assert(nativeData.isNativeClass(cls));
        return inferred.containsAll(closedWorld)
            ? new TypeMask.nonNullExact(cls, closedWorld)
            : inferred;
      } else if (element.isGenerativeConstructor) {
        ClassElement cls = element.enclosingClass;
        if (cls.isAbstract) {
          // An error will be thrown.
          return new TypeMask.nonNullEmpty();
        } else {
          return new TypeMask.nonNullExact(cls, closedWorld);
        }
      } else {
        return TypeMaskFactory.inferredReturnTypeForElement(
            originalElement, globalInferenceResults);
      }
    }

    CallStructure callStructure = elements.getSelector(send).callStructure;
    ConstructorElement constructorDeclaration = constructor;
    ConstructorElement constructorImplementation = constructor.implementation;
    constructor = constructorImplementation.effectiveTarget;

    final bool isSymbolConstructor =
        closedWorld.commonElements.isSymbolConstructor(constructorDeclaration);
    final bool isJSArrayTypedConstructor = constructorDeclaration ==
        closedWorld.commonElements.jsArrayTypedConstructor;

    if (isSymbolConstructor) {
      constructor = commonElements.symbolValidatedConstructor;
      assert(constructor != null,
          failedAt(send, 'Constructor Symbol.validated is missing'));
      callStructure =
          commonElements.symbolValidatedConstructorSelector.callStructure;
      assert(callStructure != null,
          failedAt(send, 'Constructor Symbol.validated is missing'));
    }

    bool isRedirected = constructorDeclaration.isRedirectingFactory;
    if (!constructorDeclaration.isCyclicRedirection) {
      // Insert a check for every deferred redirection on the path to the
      // final target.
      ConstructorElement target = constructorDeclaration;
      while (target.isRedirectingFactory) {
        if (constructorDeclaration.redirectionDeferredPrefix != null) {
          generateIsDeferredLoadedCheckIfNeeded(
              target.redirectionDeferredPrefix.deferredImport, node);
        }
        target = target.immediateRedirectionTarget;
      }
    }
    ResolutionInterfaceType type = elements.getType(node);
    ResolutionDartType expectedType =
        constructorDeclaration.computeEffectiveTargetType(type);
    expectedType = localsHandler.substInContext(expectedType);

    if (compiler.elementHasCompileTimeError(constructor) ||
        compiler.elementHasCompileTimeError(constructor.enclosingClass)) {
      // TODO(ahe): Do something like [generateWrongArgumentCountError].
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    if (checkTypeVariableBounds(node, type)) return;

    // Abstract class instantiation error takes precedence over argument
    // mismatch.
    ClassElement cls = constructor.enclosingClass;
    if (cls.isAbstract && constructor.isGenerativeConstructor) {
      // However, we need to ensure that all arguments are evaluated before we
      // throw the ACIE exception.
      send.arguments.forEach((arg) {
        visit(arg);
        pop();
      });
      generateAbstractClassInstantiationError(send, cls.name);
      return;
    }

    // TODO(5347): Try to avoid the need for calling [implementation] before
    // calling [makeStaticArgumentList].
    constructorImplementation = constructor.implementation;
    if (constructorImplementation.isMalformed ||
        !callStructure
            .signatureApplies(constructorImplementation.parameterStructure)) {
      generateWrongArgumentCountError(send, constructor, send.arguments);
      return;
    }

    List<HInstruction> inputs = <HInstruction>[];
    if (constructor.isGenerativeConstructor &&
        nativeData.isNativeOrExtendsNative(constructor.enclosingClass) &&
        !nativeData.isJsInteropMember(constructor)) {
      // Native class generative constructors take a pre-constructed object.
      inputs.add(graph.addConstantNull(closedWorld));
    }
    inputs.addAll(makeStaticArgumentList(
        callStructure, send.arguments, constructorImplementation.declaration));

    TypeMask elementType = computeType(constructor);
    if (isFixedListConstructorCall) {
      if (!inputs[0].isNumber(closedWorld)) {
        HTypeConversion conversion = new HTypeConversion(
            null,
            HTypeConversion.ARGUMENT_TYPE_CHECK,
            commonMasks.numType,
            inputs[0],
            sourceInformation);
        add(conversion);
        inputs[0] = conversion;
      }
      js.Template code = js.js.parseForeignJS('new Array(#)');
      var behavior = new native.NativeBehavior();
      behavior.typesInstantiated.add(expectedType);
      behavior.typesReturned.add(expectedType);
      // The allocation can throw only if the given length is a double or
      // outside the unsigned 32 bit range.
      // TODO(sra): Array allocation should be an instruction so that canThrow
      // can depend on a length type discovered in optimization.
      bool canThrow = true;
      if (inputs[0].isInteger(closedWorld) && inputs[0] is HConstant) {
        dynamic constant = inputs[0];
        IntConstantValue intConstant = constant.constant;
        int value = intConstant.intValue;
        if (0 <= value && value < 0x100000000) canThrow = false;
      }
      HForeignCode foreign = new HForeignCode(code, elementType, inputs,
          nativeBehavior: behavior,
          throwBehavior: canThrow
              ? native.NativeThrowBehavior.MAY
              : native.NativeThrowBehavior.NEVER);
      push(foreign);
      if (globalInferenceResults.isFixedArrayCheckedForGrowable(send)) {
        js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array');
        // We set the instruction as [canThrow] to avoid it being dead code.
        // We need a finer grained side effect.
        add(new HForeignCode(code, commonMasks.nullType, [stack.last],
            throwBehavior: native.NativeThrowBehavior.MAY));
      }
    } else if (isGrowableListConstructorCall) {
      push(buildLiteralList(<HInstruction>[]));
      stack.last.instructionType = elementType;
    } else if (constructor.isExternal &&
        constructor.isFromEnvironmentConstructor) {
      generateUnsupportedError(
          node,
          '${cls.name}.${constructor.name} '
          'can only be used as a const constructor');
    } else {
      potentiallyAddTypeArguments(inputs, cls, expectedType);
      addInlinedInstantiation(expectedType);
      pushInvokeStatic(node, constructor.declaration, inputs,
          typeMask: elementType,
          instanceType: expectedType,
          sourceInformation: sourceInformation);
      removeInlinedInstantiation(expectedType);
    }
    HInstruction newInstance = stack.last;
    if (isFixedList) {
      // Overwrite the element type, in case the allocation site has
      // been inlined.
      newInstance.instructionType = elementType;
      graph.allocatedFixedLists?.add(newInstance);
    }

    // The List constructor forwards to a Dart static method that does
    // not know about the type argument. Therefore we special case
    // this constructor to have the setRuntimeTypeInfo called where
    // the 'new' is done.
    if (rtiNeed.classNeedsTypeArguments(commonElements.listClass) &&
        (isFixedListConstructorCall ||
            isGrowableListConstructorCall ||
            isJSArrayTypedConstructor)) {
      newInstance = handleListConstructor(type, pop(), sourceInformation);
      stack.add(newInstance);
    }

    // Finally, if we called a redirecting factory constructor, check the type.
    if (isRedirected) {
      HInstruction checked =
          typeBuilder.potentiallyCheckOrTrustType(newInstance, type);
      if (checked != newInstance) {
        pop();
        stack.add(checked);
      }
    }
  }

  void potentiallyAddTypeArguments(List<HInstruction> inputs, ClassElement cls,
      ResolutionInterfaceType expectedType,
      {SourceInformation sourceInformation}) {
    if (!rtiNeed.classNeedsTypeArguments(cls)) return;
    assert(cls.typeVariables.length == expectedType.typeArguments.length);
    expectedType.typeArguments.forEach((ResolutionDartType argument) {
      inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement,
          sourceInformation: sourceInformation));
    });
  }

  /// In checked mode checks the [type] of [node] to be well-bounded. The method
  /// returns [:true:] if an error can be statically determined.
  bool checkTypeVariableBounds(
      ast.NewExpression node, ResolutionInterfaceType type) {
    if (!options.enableTypeAssertions) return false;

    Map<ResolutionDartType, Set<ResolutionDartType>> seenChecksMap =
        new Map<ResolutionDartType, Set<ResolutionDartType>>();
    bool definitelyFails = false;

    void addTypeVariableBoundCheck(
        InterfaceType _instance,
        DartType _typeArgument,
        TypeVariableType _typeVariable,
        DartType _bound) {
      if (definitelyFails) return;
      ResolutionInterfaceType instance = _instance;
      ResolutionDartType typeArgument = _typeArgument;
      ResolutionTypeVariableType typeVariable = _typeVariable;
      ResolutionDartType bound = _bound;

      int subtypeRelation = types.computeSubtypeRelation(typeArgument, bound);
      if (subtypeRelation == DartTypes.IS_SUBTYPE) return;

      String message = "Can't create an instance of malbounded type '$type': "
          "'${typeArgument}' is not a subtype of bound '${bound}' for "
          "type variable '${typeVariable}' of type "
          "${type == instance
              ? "'${type.element.thisType}'"
              : "'${instance.element.thisType}' on the supertype "
                "'${instance}' of '${type}'"
            }.";
      if (subtypeRelation == DartTypes.NOT_SUBTYPE) {
        generateTypeError(node, message);
        definitelyFails = true;
        return;
      } else if (subtypeRelation == DartTypes.MAYBE_SUBTYPE) {
        Set<ResolutionDartType> seenChecks = seenChecksMap.putIfAbsent(
            typeArgument, () => new Set<ResolutionDartType>());
        if (!seenChecks.contains(bound)) {
          seenChecks.add(bound);
          assertIsSubtype(node, typeArgument, bound, message);
        }
      }
    }

    types.checkTypeVariableBounds(type, addTypeVariableBoundCheck);
    if (definitelyFails) {
      return true;
    }
    for (ResolutionInterfaceType supertype in type.element.allSupertypes) {
      ResolutionInterfaceType instance = type.asInstanceOf(supertype.element);
      types.checkTypeVariableBounds(instance, addTypeVariableBoundCheck);
      if (definitelyFails) {
        return true;
      }
    }
    return false;
  }

  visitStaticSend(ast.Send node) {
    internalError(node, "Unexpected visitStaticSend");
  }

  /// Generate an invocation to the static or top level [function].
  void generateStaticFunctionInvoke(
      ast.Send node, MethodElement function, CallStructure callStructure) {
    List<HInstruction> inputs =
        makeStaticArgumentList(callStructure, node.arguments, function);
    pushInvokeStatic(node, function, inputs,
        sourceInformation:
            sourceInformationBuilder.buildCall(node.selector, node.selector));
  }

  /// Generate an invocation to a static or top level function with the wrong
  /// number of arguments.
  void generateStaticFunctionIncompatibleInvoke(
      ast.Send node, Element element) {
    generateWrongArgumentCountError(node, element, node.arguments);
  }

  @override
  void visitStaticFieldInvoke(ast.Send node, FieldElement field,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateStaticFieldGet(node, field);
    generateCallInvoke(
        node,
        pop(),
        sourceInformationBuilder.buildCall(
            node.argumentsNode, node.argumentsNode));
  }

  @override
  void visitStaticFunctionInvoke(ast.Send node, MethodElement function,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateStaticFunctionInvoke(node, function, callStructure);
  }

  @override
  void visitStaticFunctionIncompatibleInvoke(
      ast.Send node,
      MethodElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    generateStaticFunctionIncompatibleInvoke(node, function);
  }

  @override
  void visitStaticGetterInvoke(ast.Send node, FunctionElement getter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateStaticGetterGet(node, getter);
    generateCallInvoke(node, pop(),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  void visitTopLevelFieldInvoke(ast.Send node, FieldElement field,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateStaticFieldGet(node, field);
    generateCallInvoke(node, pop(),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  void visitTopLevelFunctionInvoke(ast.Send node, MethodElement function,
      ast.NodeList arguments, CallStructure callStructure, _) {
    if (closedWorld.commonElements.isForeign(function)) {
      handleForeignSend(node, function);
    } else {
      generateStaticFunctionInvoke(node, function, callStructure);
    }
  }

  @override
  void visitTopLevelFunctionIncompatibleInvoke(
      ast.Send node,
      MethodElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    generateStaticFunctionIncompatibleInvoke(node, function);
  }

  @override
  void visitTopLevelGetterInvoke(ast.Send node, FunctionElement getter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateStaticGetterGet(node, getter);
    generateCallInvoke(node, pop(),
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  @override
  void visitTopLevelSetterGet(ast.Send node, MethodElement setter, _) {
    handleInvalidStaticGet(node, setter);
  }

  @override
  void visitStaticSetterGet(ast.Send node, MethodElement setter, _) {
    handleInvalidStaticGet(node, setter);
  }

  @override
  void visitUnresolvedGet(ast.Send node, Element element, _) {
    generateStaticUnresolvedGet(node, element);
  }

  void handleInvalidStaticInvoke(ast.Send node, Element element) {
    generateThrowNoSuchMethod(node, noSuchMethodTargetSymbolString(element),
        argumentNodes: node.arguments);
  }

  @override
  void visitStaticSetterInvoke(ast.Send node, MethodElement setter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    handleInvalidStaticInvoke(node, setter);
  }

  @override
  void visitTopLevelSetterInvoke(ast.Send node, MethodElement setter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    handleInvalidStaticInvoke(node, setter);
  }

  @override
  void visitUnresolvedInvoke(ast.Send node, Element element,
      ast.NodeList arguments, Selector selector, _) {
    if (element is ErroneousElement) {
      // An erroneous element indicates that the function could not be
      // resolved (a warning has been issued).
      handleInvalidStaticInvoke(node, element);
    } else {
      // TODO(ahe): Do something like [generateWrongArgumentCountError].
      stack.add(graph.addConstantNull(closedWorld));
    }
    return;
  }

  HConstant addConstantString(String string) {
    return graph.addConstantString(string, closedWorld);
  }

  HConstant addConstantStringFromName(js.Name name) {
    return graph.addConstantStringFromName(name, closedWorld);
  }

  visitClassTypeLiteralGet(ast.Send node, ConstantExpression constant, _) {
    generateConstantTypeLiteral(node);
  }

  visitClassTypeLiteralInvoke(ast.Send node, ConstantExpression constant,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateConstantTypeLiteral(node);
    generateTypeLiteralCall(node);
  }

  visitTypedefTypeLiteralGet(ast.Send node, ConstantExpression constant, _) {
    generateConstantTypeLiteral(node);
  }

  visitTypedefTypeLiteralInvoke(ast.Send node, ConstantExpression constant,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateConstantTypeLiteral(node);
    generateTypeLiteralCall(node);
  }

  visitTypeVariableTypeLiteralGet(
      ast.Send node, TypeVariableElement element, _) {
    generateTypeVariableLiteral(node, element.type);
  }

  visitTypeVariableTypeLiteralInvoke(ast.Send node, TypeVariableElement element,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateTypeVariableLiteral(node, element.type);
    generateTypeLiteralCall(node);
  }

  visitDynamicTypeLiteralGet(ast.Send node, ConstantExpression constant, _) {
    generateConstantTypeLiteral(node);
  }

  visitDynamicTypeLiteralInvoke(ast.Send node, ConstantExpression constant,
      ast.NodeList arguments, CallStructure callStructure, _) {
    generateConstantTypeLiteral(node);
    generateTypeLiteralCall(node);
  }

  /// Generate the constant value for a constant type literal.
  void generateConstantTypeLiteral(ast.Send node) {
    // TODO(karlklose): add type representation
    if (node.isCall) {
      // The node itself is not a constant but we register the selector (the
      // identifier that refers to the class/typedef) as a constant.
      stack.add(addConstant(node.selector));
    } else {
      stack.add(addConstant(node));
    }
  }

  /// Generate the literal for [typeVariable] in the current context.
  void generateTypeVariableLiteral(
      ast.Send node, ResolutionTypeVariableType typeVariable) {
    // GENERIC_METHODS: This provides thin support for method type variables
    // by treating them as malformed when evaluated as a literal. For full
    // support of generic methods this must be revised.
    if (typeVariable is MethodTypeVariableType) {
      generateTypeError(node, "Method type variables are not reified");
    } else {
      ResolutionDartType type = localsHandler.substInContext(typeVariable);
      HInstruction value = typeBuilder.analyzeTypeArgument(type, sourceElement,
          sourceInformation: sourceInformationBuilder.buildGet(node));
      pushInvokeStatic(node, commonElements.runtimeTypeToString, [value],
          typeMask: commonMasks.stringType);
      pushInvokeStatic(node, commonElements.createRuntimeType, [pop()]);
    }
  }

  /// Generate a call to a type literal.
  void generateTypeLiteralCall(ast.Send node) {
    // This send is of the form 'e(...)', where e is resolved to a type
    // reference. We create a regular closure call on the result of the type
    // reference instead of creating a NoSuchMethodError to avoid pulling it
    // in if it is not used (e.g., in a try/catch).
    HInstruction target = pop();
    generateCallInvoke(node, target,
        sourceInformationBuilder.buildCall(node, node.argumentsNode));
  }

  /// Generate a '.call' invocation on [target].
  void generateCallInvoke(
      ast.Send node, HInstruction target, SourceInformation sourceInformation) {
    Selector selector = elements.getSelector(node);
    List<HInstruction> inputs = <HInstruction>[target];
    addDynamicSendArgumentsToList(node, inputs);
    push(new HInvokeClosure(new Selector.callClosureFrom(selector), inputs,
        commonMasks.dynamicType, const <DartType>[])
      ..sourceInformation = sourceInformation);
  }

  visitGetterSend(ast.Send node) {
    internalError(node, "Unexpected visitGetterSend");
  }

  // TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
  internalError(Spannable node, String reason) {
    reporter.internalError(node, reason);
  }

  void generateError(ast.Node node, String message, Element helper) {
    HInstruction errorMessage = addConstantString(message);
    pushInvokeStatic(node, helper, [errorMessage]);
  }

  void generateRuntimeError(ast.Node node, String message) {
    MethodElement helper = commonElements.throwRuntimeError;
    generateError(node, message, helper);
  }

  void generateUnsupportedError(ast.Node node, String message) {
    MethodElement helper = commonElements.throwUnsupportedError;
    generateError(node, message, helper);
  }

  void generateTypeError(ast.Node node, String message) {
    MethodElement helper = commonElements.throwTypeError;
    generateError(node, message, helper);
  }

  void generateAbstractClassInstantiationError(ast.Node node, String message) {
    MethodElement helper = commonElements.throwAbstractClassInstantiationError;
    generateError(node, message, helper);
  }

  void generateThrowNoSuchMethod(ast.Node diagnosticNode, String methodName,
      {Link<ast.Node> argumentNodes,
      List<HInstruction> argumentValues,
      List<String> existingArguments,
      SourceInformation sourceInformation}) {
    MethodElement helper = commonElements.throwNoSuchMethod;
    ConstantValue receiverConstant = constantSystem.createString('');
    HInstruction receiver = graph.addConstant(receiverConstant, closedWorld);
    ConstantValue nameConstant = constantSystem.createString(methodName);
    HInstruction name = graph.addConstant(nameConstant, closedWorld);
    if (argumentValues == null) {
      argumentValues = <HInstruction>[];
      argumentNodes.forEach((argumentNode) {
        visit(argumentNode);
        HInstruction value = pop();
        argumentValues.add(value);
      });
    }
    HInstruction arguments = buildLiteralList(argumentValues);
    add(arguments);
    HInstruction existingNamesList;
    if (existingArguments != null) {
      List<HInstruction> existingNames = <HInstruction>[];
      for (String name in existingArguments) {
        HInstruction nameConstant = graph.addConstantString(name, closedWorld);
        existingNames.add(nameConstant);
      }
      existingNamesList = buildLiteralList(existingNames);
      add(existingNamesList);
    } else {
      existingNamesList = graph.addConstantNull(closedWorld);
    }
    pushInvokeStatic(
        diagnosticNode, helper, [receiver, name, arguments, existingNamesList],
        sourceInformation: sourceInformation);
  }

  /**
   * Generate code to throw a [NoSuchMethodError] exception for calling a
   * method with a wrong number of arguments or mismatching named optional
   * arguments.
   */
  void generateWrongArgumentCountError(ast.Node diagnosticNode,
      FunctionElement function, Link<ast.Node> argumentNodes) {
    List<String> existingArguments = <String>[];
    FunctionSignature signature = function.functionSignature;
    signature.forEachParameter((Element parameter) {
      existingArguments.add(parameter.name);
    });
    generateThrowNoSuchMethod(diagnosticNode, function.name,
        argumentNodes: argumentNodes, existingArguments: existingArguments);
  }

  @override
  void bulkHandleNode(ast.Node node, String message, _) {
    internalError(node, "Unexpected bulk handled node: $node");
  }

  @override
  void bulkHandleNew(ast.NewExpression node, [_]) {
    Element element = elements[node.send];
    if (!Elements.isMalformed(element)) {
      ConstructorElement function = element;
      element = function.effectiveTarget;
    }
    final bool isSymbolConstructor =
        element == commonElements.symbolConstructorTarget;
    if (Elements.isError(element)) {
      ErroneousElement error = element;
      if (error.messageKind == MessageKind.CANNOT_FIND_CONSTRUCTOR ||
          error.messageKind == MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR) {
        generateThrowNoSuchMethod(
            node.send, noSuchMethodTargetSymbolString(error, 'constructor'),
            argumentNodes: node.send.arguments);
      } else {
        MessageTemplate template = MessageTemplate.TEMPLATES[error.messageKind];
        Message message = template.message(error.messageArguments);
        generateRuntimeError(node.send, message.toString());
      }
    } else if (Elements.isMalformed(element)) {
      // TODO(ahe): Do something like [generateWrongArgumentCountError].
      stack.add(graph.addConstantNull(closedWorld));
    } else if (node.isConst) {
      stack.add(addConstant(node));
      if (isSymbolConstructor) {
        ConstructedConstantValue symbol = getConstantForNode(node);
        StringConstantValue stringConstant = symbol.fields.values.single;
        String nameString = stringConstant.stringValue;
        registry?.registerConstSymbol(nameString);
      }
    } else {
      handleNewSend(node);
    }
  }

  @override
  void errorNonConstantConstructorInvoke(
      ast.NewExpression node,
      Element element,
      ResolutionDartType type,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    bulkHandleNew(node);
  }

  void pushInvokeDynamic(ast.Node node, Selector selector, TypeMask mask,
      List<HInstruction> arguments,
      {SourceInformation sourceInformation}) {
    // We prefer to not inline certain operations on indexables,
    // because the constant folder will handle them better and turn
    // them into simpler instructions that allow further
    // optimizations.
    bool isOptimizableOperationOnIndexable(Selector selector, Element element) {
      bool isLength = selector.isGetter && selector.name == "length";
      if (isLength || selector.isIndex) {
        return closedWorld.isSubtypeOf(
            element.enclosingClass, commonElements.jsIndexableClass);
      } else if (selector.isIndexSet) {
        return closedWorld.isSubtypeOf(
            element.enclosingClass, commonElements.jsMutableIndexableClass);
      } else {
        return false;
      }
    }

    bool isOptimizableOperation(Selector selector, Element element) {
      ClassElement cls = element.enclosingClass;
      if (isOptimizableOperationOnIndexable(selector, element)) return true;
      if (!interceptorData.interceptedClasses.contains(cls)) return false;
      if (selector.isOperator) return true;
      if (selector.isSetter) return true;
      if (selector.isIndex) return true;
      if (selector.isIndexSet) return true;
      if (element == commonElements.jsArrayAdd ||
          element == commonElements.jsArrayRemoveLast ||
          element == commonElements.jsStringSplit) {
        return true;
      }
      return false;
    }

    MemberElement element = closedWorld.locateSingleElement(selector, mask);
    if (element != null &&
        !element.isField &&
        !(element.isGetter && selector.isCall) &&
        !(element.isFunction && selector.isGetter) &&
        !isOptimizableOperation(selector, element)) {
      if (tryInlineMethod(element, selector, mask, arguments, node)) {
        return;
      }
    }

    HInstruction receiver = arguments[0];
    List<HInstruction> inputs = <HInstruction>[];
    bool isIntercepted = interceptorData.isInterceptedSelector(selector);
    if (isIntercepted) {
      inputs.add(invokeInterceptor(receiver));
    }
    inputs.addAll(arguments);
    TypeMask type = TypeMaskFactory.inferredTypeForSelector(
        selector, mask, globalInferenceResults);
    if (selector.isGetter) {
      push(new HInvokeDynamicGetter(selector, mask, null, inputs, isIntercepted,
          type, sourceInformation));
    } else if (selector.isSetter) {
      push(new HInvokeDynamicSetter(selector, mask, null, inputs, isIntercepted,
          type, sourceInformation));
    } else {
      push(new HInvokeDynamicMethod(
          selector, mask, inputs, type, const <DartType>[], sourceInformation,
          isIntercepted: isIntercepted));
    }
  }

  HForeignCode invokeJsInteropFunction(MethodElement element,
      List<HInstruction> arguments, SourceInformation sourceInformation) {
    assert(nativeData.isJsInteropMember(element));
    nativeEmitter.nativeMethods.add(element);

    if (element.isFactoryConstructor &&
        nativeData.isAnonymousJsInteropClass(element.contextClass)) {
      // Factory constructor that is syntactic sugar for creating a JavaScript
      // object literal.
      ConstructorElement constructor = element;
      FunctionSignature params = constructor.functionSignature;
      int i = 0;
      int positions = 0;
      var filteredArguments = <HInstruction>[];
      var parameterNameMap = new Map<String, js.Expression>();
      params.orderedForEachParameter((_parameter) {
        ParameterElement parameter = _parameter;
        // TODO(jacobr): consider throwing if parameter names do not match
        // names of properties in the class.
        assert(parameter.isNamed);
        HInstruction argument = arguments[i];
        if (argument != null) {
          filteredArguments.add(argument);
          var jsName = nativeData.computeUnescapedJSInteropName(parameter.name);
          parameterNameMap[jsName] = new js.InterpolatedExpression(positions++);
        }
        i++;
      });
      var codeTemplate =
          new js.Template(null, js.objectLiteral(parameterNameMap));

      var nativeBehavior = new native.NativeBehavior()
        ..codeTemplate = codeTemplate;
      if (options.trustJSInteropTypeAnnotations) {
        nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType);
      }
      return new HForeignCode(
          codeTemplate, commonMasks.dynamicType, filteredArguments,
          nativeBehavior: nativeBehavior)
        ..sourceInformation = sourceInformation;
    }
    var target = new HForeignCode(
        js.js.parseForeignJS("${nativeData.getFixedBackendMethodPath(element)}."
            "${nativeData.getFixedBackendName(element)}"),
        commonMasks.dynamicType,
        <HInstruction>[]);
    add(target);
    // Strip off trailing arguments that were not specified.
    // we could assert that the trailing arguments are all null.
    // TODO(jacobr): rewrite named arguments to an object literal matching
    // the factory constructor case.
    arguments = arguments.where((arg) => arg != null).toList();
    var inputs = <HInstruction>[target]..addAll(arguments);

    var nativeBehavior = new native.NativeBehavior()
      ..sideEffects.setAllSideEffects();

    ResolutionDartType type = element.isConstructor
        ? element.enclosingClass.thisType
        : element.type.returnType;
    // Native behavior effects here are similar to native/behavior.dart.
    // The return type is dynamic if we don't trust js-interop type
    // declarations.
    nativeBehavior.typesReturned.add(options.trustJSInteropTypeAnnotations
        ? type
        : const ResolutionDynamicType());

    // The allocation effects include the declared type if it is native (which
    // includes js interop types).
    if (type is ResolutionInterfaceType &&
        nativeData.isNativeClass(type.element)) {
      nativeBehavior.typesInstantiated.add(type);
    }

    // It also includes any other JS interop type if we don't trust the
    // annotation or if is declared too broad.
    if (!options.trustJSInteropTypeAnnotations ||
        type.isObject ||
        type.isDynamic) {
      ClassElement cls = commonElements.jsJavaScriptObjectClass;
      nativeBehavior.typesInstantiated.add(cls.thisType);
    }

    String code;
    if (element.isGetter) {
      code = "#";
    } else if (element.isSetter) {
      code = "# = #";
    } else {
      var args = new List.filled(arguments.length, '#').join(',');
      code = element.isConstructor ? "new #($args)" : "#($args)";
    }
    js.Template codeTemplate = js.js.parseForeignJS(code);
    nativeBehavior.codeTemplate = codeTemplate;

    return new HForeignCode(codeTemplate, commonMasks.dynamicType, inputs,
        nativeBehavior: nativeBehavior)
      ..sourceInformation = sourceInformation;
  }

  void pushInvokeStatic(
      ast.Node location, MethodElement element, List<HInstruction> arguments,
      {TypeMask typeMask,
      ResolutionInterfaceType instanceType,
      SourceInformation sourceInformation}) {
    assert(element.isDeclaration);
    // TODO(johnniwinther): Use [sourceInformation] instead of [location].
    if (tryInlineMethod(element, null, null, arguments, location,
        instanceType: instanceType)) {
      return;
    }

    if (typeMask == null) {
      typeMask = TypeMaskFactory.inferredReturnTypeForElement(
          element, globalInferenceResults);
    }
    bool targetCanThrow = !closedWorld.getCannotThrow(element);
    // TODO(5346): Try to avoid the need for calling [declaration] before
    var instruction;
    if (nativeData.isJsInteropMember(element)) {
      instruction =
          invokeJsInteropFunction(element, arguments, sourceInformation);
    } else {
      // creating an [HInvokeStatic].
      instruction = new HInvokeStatic(
          element, arguments, typeMask, const <DartType>[],
          targetCanThrow: targetCanThrow)
        ..sourceInformation = sourceInformation;
      if (currentInlinedInstantiations.isNotEmpty) {
        instruction.instantiatedTypes = new List<ResolutionInterfaceType>.from(
            currentInlinedInstantiations);
      }
      instruction.sideEffects = closedWorld.getSideEffectsOfElement(element);
    }
    if (sourceInformation != null || location == null) {
      push(instruction);
    } else {
      pushWithPosition(instruction, location);
    }
  }

  HInstruction buildInvokeSuper(Selector selector, MemberElement element,
      List<HInstruction> arguments, SourceInformation sourceInformation) {
    HInstruction receiver =
        localsHandler.readThis(sourceInformation: sourceInformation);
    // TODO(5346): Try to avoid the need for calling [declaration] before
    // creating an [HStatic].
    List<HInstruction> inputs = <HInstruction>[];
    // Fields don't need an interceptor; consider generating HFieldGet/Set instead.

    bool isIntercepted = interceptorData.isInterceptedSelector(selector) &&
        element.kind != ElementKind.FIELD;
    if (isIntercepted) {
      inputs.add(invokeInterceptor(receiver));
    }
    inputs.add(receiver);
    inputs.addAll(arguments);
    TypeMask type;
    if (!element.isGetter && selector.isGetter) {
      type = TypeMaskFactory.inferredTypeForMember(
          element, globalInferenceResults);
    } else if (element.isFunction) {
      MethodElement method = element;
      type = TypeMaskFactory.inferredReturnTypeForElement(
          method, globalInferenceResults);
    } else {
      type = closedWorld.commonMasks.dynamicType;
    }
    HInstruction instruction = new HInvokeSuper(
        element,
        currentNonClosureClass,
        selector,
        inputs,
        isIntercepted,
        type,
        const <DartType>[],
        sourceInformation,
        isSetter: selector.isSetter || selector.isIndexSet);
    instruction.sideEffects =
        closedWorld.getSideEffectsOfSelector(selector, null);
    return instruction;
  }

  void handleComplexOperatorSend(
      ast.SendSet node, HInstruction receiver, Link<ast.Node> arguments) {
    HInstruction rhs;
    if (node.isPrefix || node.isPostfix) {
      rhs = graph.addConstantInt(1, closedWorld);
    } else {
      visit(arguments.head);
      assert(arguments.tail.isEmpty);
      rhs = pop();
    }
    visitBinarySend(
        receiver,
        rhs,
        elements.getOperatorSelectorInComplexSendSet(node),
        elementInferenceResults.typeOfOperator(node),
        node,
        sourceInformation:
            sourceInformationBuilder.buildGeneric(node.assignmentOperator));
  }

  void handleSuperSendSet(ast.SendSet node) {
    MemberElement element = elements[node];
    List<HInstruction> setterInputs = <HInstruction>[];
    void generateSuperSendSet() {
      Selector setterSelector = elements.getSelector(node);
      if (Elements.isUnresolved(element) || !setterSelector.applies(element)) {
        generateSuperNoSuchMethodSend(node, setterSelector, setterInputs);
        pop();
      } else {
        add(buildInvokeSuper(setterSelector, element, setterInputs,
            sourceInformationBuilder.buildAssignment(node)));
      }
    }

    if (identical(node.assignmentOperator.source, '=')) {
      addDynamicSendArgumentsToList(node, setterInputs);
      generateSuperSendSet();
      stack.add(setterInputs.last);
    } else {
      Element getter = elements[node.selector];
      List<HInstruction> getterInputs = <HInstruction>[];
      Link<ast.Node> arguments = node.arguments;
      if (node.isIndex) {
        // If node is of the form [:super.foo[0] += 2:], the send has
        // two arguments: the index and the left hand side. We get
        // the index and add it as input of the getter and the
        // setter.
        visit(arguments.head);
        arguments = arguments.tail;
        HInstruction index = pop();
        getterInputs.add(index);
        setterInputs.add(index);
      }
      HInstruction getterInstruction;
      Selector getterSelector =
          elements.getGetterSelectorInComplexSendSet(node);
      if (Elements.isUnresolved(getter)) {
        generateSuperNoSuchMethodSend(node, getterSelector, getterInputs);
        getterInstruction = pop();
      } else {
        getterInstruction = buildInvokeSuper(getterSelector, getter,
            getterInputs, sourceInformationBuilder.buildGet(node));
        add(getterInstruction);
      }

      if (node.isIfNullAssignment) {
        SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
        brancher.handleIfNull(() => stack.add(getterInstruction), () {
          addDynamicSendArgumentsToList(node, setterInputs);
          generateSuperSendSet();
          stack.add(setterInputs.last);
        });
      } else {
        handleComplexOperatorSend(node, getterInstruction, arguments);
        setterInputs.add(pop());
        generateSuperSendSet();
        stack.add(node.isPostfix ? getterInstruction : setterInputs.last);
      }
    }
  }

  @override
  void handleSuperCompounds(
      ast.SendSet node,
      Element getter,
      CompoundGetter getterKind,
      Element setter,
      CompoundSetter setterKind,
      CompoundRhs rhs,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitFinalSuperFieldSet(
      ast.SendSet node, FieldElement field, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperFieldSet(
      ast.SendSet node, FieldElement field, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperGetterSet(
      ast.SendSet node, FunctionElement getter, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperIndexSet(ast.SendSet node, FunctionElement function,
      ast.Node index, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperMethodSet(
      ast.SendSet node, MethodElement method, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperSetterSet(
      ast.SendSet node, FunctionElement setter, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperIndexSet(ast.SendSet node, ErroneousElement element,
      ast.Node index, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperIndexPrefix(
      ast.Send node,
      MethodElement indexFunction,
      MethodElement indexSetFunction,
      ast.Node index,
      IncDecOperator operator,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperIndexPostfix(
      ast.Send node,
      MethodElement indexFunction,
      MethodElement indexSetFunction,
      ast.Node index,
      IncDecOperator operator,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperGetterIndexPrefix(ast.SendSet node, Element element,
      MethodElement setter, ast.Node index, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperGetterIndexPostfix(ast.SendSet node, Element element,
      MethodElement setter, ast.Node index, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperSetterIndexPrefix(
      ast.SendSet node,
      MethodElement indexFunction,
      Element element,
      ast.Node index,
      IncDecOperator operator,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperSetterIndexPostfix(
      ast.SendSet node,
      MethodElement indexFunction,
      Element element,
      ast.Node index,
      IncDecOperator operator,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperIndexPrefix(ast.Send node, Element element,
      ast.Node index, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperIndexPostfix(ast.Send node, Element element,
      ast.Node index, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperCompoundIndexSet(
      ast.SendSet node,
      MethodElement getter,
      MethodElement setter,
      ast.Node index,
      AssignmentOperator operator,
      ast.Node rhs,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperGetterCompoundIndexSet(
      ast.SendSet node,
      Element element,
      MethodElement setter,
      ast.Node index,
      AssignmentOperator operator,
      ast.Node rhs,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperSetterCompoundIndexSet(
      ast.SendSet node,
      MethodElement getter,
      Element element,
      ast.Node index,
      AssignmentOperator operator,
      ast.Node rhs,
      _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperCompoundIndexSet(ast.SendSet node, Element element,
      ast.Node index, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperFieldCompound(ast.Send node, FieldElement field,
      AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitFinalSuperFieldCompound(ast.Send node, FieldElement field,
      AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitFinalSuperFieldPrefix(
      ast.Send node, FieldElement field, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperPrefix(
      ast.SendSet node, Element element, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperPostfix(
      ast.SendSet node, Element element, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperCompound(ast.Send node, Element element,
      AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitFinalSuperFieldPostfix(
      ast.Send node, FieldElement field, IncDecOperator operator, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperFieldFieldCompound(ast.Send node, FieldElement readField,
      FieldElement writtenField, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperGetterSetterCompound(ast.Send node, FunctionElement getter,
      FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperMethodSetterCompound(ast.Send node, FunctionElement method,
      FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperMethodCompound(ast.Send node, MethodElement method,
      AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperGetterCompound(ast.SendSet node, Element element,
      SetterElement setter, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitUnresolvedSuperSetterCompound(ast.Send node, GetterElement getter,
      Element element, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperFieldSetterCompound(ast.Send node, FieldElement field,
      FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitSuperGetterFieldCompound(ast.Send node, FunctionElement getter,
      FieldElement field, AssignmentOperator operator, ast.Node rhs, _) {
    handleSuperSendSet(node);
  }

  @override
  void visitIndexSet(
      ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, _) {
    generateDynamicSend(node);
  }

  @override
  void visitCompoundIndexSet(ast.SendSet node, ast.Node receiver,
      ast.Node index, AssignmentOperator operator, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    handleIndexSendSet(node);
  }

  @override
  void visitIndexPrefix(ast.Send node, ast.Node receiver, ast.Node index,
      IncDecOperator operator, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    handleIndexSendSet(node);
  }

  @override
  void visitIndexPostfix(ast.Send node, ast.Node receiver, ast.Node index,
      IncDecOperator operator, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    handleIndexSendSet(node);
  }

  void handleIndexSendSet(ast.SendSet node) {
    ast.Operator op = node.assignmentOperator;
    if ("=" == op.source) {
      internalError(node, "Unexpected index set.");
    } else {
      visit(node.receiver);
      HInstruction receiver = pop();
      Link<ast.Node> arguments = node.arguments;
      HInstruction index;
      if (node.isIndex) {
        visit(arguments.head);
        arguments = arguments.tail;
        index = pop();
      }

      pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node),
          elementInferenceResults.typeOfGetter(node), [receiver, index]);
      HInstruction getterInstruction = pop();
      if (node.isIfNullAssignment) {
        // Compile x[i] ??= e as:
        //   t1 = x[i]
        //   if (t1 == null)
        //      t1 = x[i] = e;
        //   result = t1
        SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
        brancher.handleIfNull(() => stack.add(getterInstruction), () {
          visit(arguments.head);
          HInstruction value = pop();
          pushInvokeDynamic(
              node,
              elements.getSelector(node),
              elementInferenceResults.typeOfSend(node),
              [receiver, index, value]);
          pop();
          stack.add(value);
        });
      } else {
        handleComplexOperatorSend(node, getterInstruction, arguments);
        HInstruction value = pop();
        pushInvokeDynamic(node, elements.getSelector(node),
            elementInferenceResults.typeOfSend(node), [receiver, index, value]);
        pop();
        if (node.isPostfix) {
          stack.add(getterInstruction);
        } else {
          stack.add(value);
        }
      }
    }
  }

  @override
  void visitThisPropertySet(ast.SendSet node, Name name, ast.Node rhs, _) {
    generateInstanceSetterWithCompiledReceiver(
        node,
        localsHandler.readThis(
            sourceInformation: sourceInformationBuilder.buildGet(node)),
        visitAndPop(rhs));
  }

  @override
  void visitDynamicPropertySet(
      ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) {
    generateInstanceSetterWithCompiledReceiver(
        node, generateInstanceSendReceiver(node), visitAndPop(rhs));
  }

  @override
  void visitIfNotNullDynamicPropertySet(
      ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) {
    // compile e?.x = e2 to:
    //
    // t1 = e
    // if (t1 == null)
    //   result = t1 // same as result = null
    // else
    //   result = e.x = e2
    HInstruction receiverInstruction;
    SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
    brancher.handleConditional(
        () {
          receiverInstruction = generateInstanceSendReceiver(node);
          pushCheckNull(receiverInstruction);
        },
        () => stack.add(receiverInstruction),
        () {
          generateInstanceSetterWithCompiledReceiver(
              node, receiverInstruction, visitAndPop(rhs));
        });
  }

  @override
  void visitParameterSet(
      ast.SendSet node, ParameterElement parameter, ast.Node rhs, _) {
    generateNonInstanceSetter(node, parameter, visitAndPop(rhs));
  }

  @override
  void visitFinalParameterSet(
      ast.SendSet node, ParameterElement parameter, ast.Node rhs, _) {
    generateNoSuchSetter(node, parameter, visitAndPop(rhs));
  }

  @override
  void visitLocalVariableSet(
      ast.SendSet node, LocalVariableElement variable, ast.Node rhs, _) {
    generateNonInstanceSetter(node, variable, visitAndPop(rhs));
  }

  @override
  void visitFinalLocalVariableSet(
      ast.SendSet node, LocalVariableElement variable, ast.Node rhs, _) {
    generateNoSuchSetter(node, variable, visitAndPop(rhs));
  }

  @override
  void visitLocalFunctionSet(
      ast.SendSet node, LocalFunctionElement function, ast.Node rhs, _) {
    generateNoSuchSetter(node, function, visitAndPop(rhs));
  }

  @override
  void visitTopLevelFieldSet(
      ast.SendSet node, FieldElement field, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNonInstanceSetter(node, field, visitAndPop(rhs));
  }

  @override
  void visitFinalTopLevelFieldSet(
      ast.SendSet node, FieldElement field, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNoSuchSetter(node, field, visitAndPop(rhs));
  }

  @override
  void visitTopLevelGetterSet(
      ast.SendSet node, GetterElement getter, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNoSuchSetter(node, getter, visitAndPop(rhs));
  }

  @override
  void visitTopLevelSetterSet(
      ast.SendSet node, SetterElement setter, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNonInstanceSetter(node, setter, visitAndPop(rhs));
  }

  @override
  void visitTopLevelFunctionSet(
      ast.SendSet node, MethodElement function, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNoSuchSetter(node, function, visitAndPop(rhs));
  }

  @override
  void visitStaticFieldSet(
      ast.SendSet node, FieldElement field, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNonInstanceSetter(node, field, visitAndPop(rhs));
  }

  @override
  void visitFinalStaticFieldSet(
      ast.SendSet node, FieldElement field, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNoSuchSetter(node, field, visitAndPop(rhs));
  }

  @override
  void visitStaticGetterSet(
      ast.SendSet node, GetterElement getter, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNoSuchSetter(node, getter, visitAndPop(rhs));
  }

  @override
  void visitStaticSetterSet(
      ast.SendSet node, SetterElement setter, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNonInstanceSetter(node, setter, visitAndPop(rhs));
  }

  @override
  void visitStaticFunctionSet(
      ast.SendSet node, MethodElement function, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNoSuchSetter(node, function, visitAndPop(rhs));
  }

  @override
  void visitUnresolvedSet(ast.SendSet node, Element element, ast.Node rhs, _) {
    generateIsDeferredLoadedCheckOfSend(node);
    generateNonInstanceSetter(node, element, visitAndPop(rhs));
  }

  @override
  void visitClassTypeLiteralSet(
      ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
    generateThrowNoSuchMethod(node, constant.name,
        argumentNodes: node.arguments);
  }

  @override
  void visitTypedefTypeLiteralSet(
      ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
    generateThrowNoSuchMethod(node, constant.name,
        argumentNodes: node.arguments);
  }

  @override
  void visitDynamicTypeLiteralSet(
      ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
    generateThrowNoSuchMethod(node, constant.name,
        argumentNodes: node.arguments);
  }

  @override
  void visitTypeVariableTypeLiteralSet(
      ast.SendSet node, TypeVariableElement element, ast.Node rhs, _) {
    generateThrowNoSuchMethod(node, element.name,
        argumentNodes: node.arguments);
  }

  void handleCompoundSendSet(ast.SendSet node) {
    Element element = elements[node];
    Element getter = elements[node.selector];

    if (!Elements.isUnresolved(getter) && getter.impliesType) {
      if (node.isIfNullAssignment) {
        // C ??= x is compiled just as C.
        stack.add(addConstant(node.selector));
      } else {
        ast.Identifier selector = node.selector;
        generateThrowNoSuchMethod(node, selector.source,
            argumentNodes: node.arguments);
      }
      return;
    }

    if (Elements.isInstanceSend(node, elements)) {
      void generateAssignment(HInstruction receiver) {
        // desugars `e.x op= e2` to `e.x = e.x op e2`
        generateInstanceGetterWithCompiledReceiver(
            node,
            elements.getGetterSelectorInComplexSendSet(node),
            elementInferenceResults.typeOfGetter(node),
            receiver);
        HInstruction getterInstruction = pop();
        if (node.isIfNullAssignment) {
          SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
          brancher.handleIfNull(() => stack.add(getterInstruction), () {
            visit(node.arguments.head);
            generateInstanceSetterWithCompiledReceiver(node, receiver, pop());
          });
        } else {
          handleComplexOperatorSend(node, getterInstruction, node.arguments);
          HInstruction value = pop();
          generateInstanceSetterWithCompiledReceiver(node, receiver, value);
        }
        if (node.isPostfix) {
          pop();
          stack.add(getterInstruction);
        }
      }

      if (node.isConditional) {
        // generate `e?.x op= e2` as:
        //   t1 = e
        //   t1 == null ? t1 : (t1.x = t1.x op e2);
        HInstruction receiver;
        SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
        brancher.handleConditional(() {
          receiver = generateInstanceSendReceiver(node);
          pushCheckNull(receiver);
        }, () => stack.add(receiver), () => generateAssignment(receiver));
      } else {
        generateAssignment(generateInstanceSendReceiver(node));
      }
      return;
    }

    if (getter.isMalformed) {
      generateStaticUnresolvedGet(node, getter);
    } else if (getter.isField) {
      generateStaticFieldGet(node, getter);
    } else if (getter.isGetter) {
      generateStaticGetterGet(node, getter);
    } else if (getter.isFunction) {
      generateStaticFunctionGet(node, getter);
    } else if (getter.isLocal) {
      handleLocalGet(node, getter);
    } else {
      internalError(node, "Unexpected getter: $getter");
    }
    HInstruction getterInstruction = pop();
    if (node.isIfNullAssignment) {
      SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
      brancher.handleIfNull(() => stack.add(getterInstruction), () {
        visit(node.arguments.head);
        generateNonInstanceSetter(node, element, pop());
      });
    } else {
      handleComplexOperatorSend(node, getterInstruction, node.arguments);
      HInstruction value = pop();
      generateNonInstanceSetter(node, element, value);
    }
    if (node.isPostfix) {
      pop();
      stack.add(getterInstruction);
    }
  }

  @override
  void handleDynamicCompounds(
      ast.Send node, ast.Node receiver, Name name, CompoundRhs rhs, _) {
    handleCompoundSendSet(node);
  }

  @override
  void handleLocalCompounds(
      ast.SendSet node, LocalElement local, CompoundRhs rhs, _,
      {bool isSetterValid}) {
    handleCompoundSendSet(node);
  }

  @override
  void handleStaticCompounds(
      ast.SendSet node,
      Element getter,
      CompoundGetter getterKind,
      Element setter,
      CompoundSetter setterKind,
      CompoundRhs rhs,
      _) {
    handleCompoundSendSet(node);
  }

  @override
  handleDynamicSetIfNulls(
      ast.Send node, ast.Node receiver, Name name, ast.Node rhs, arg) {
    handleCompoundSendSet(node);
  }

  @override
  handleLocalSetIfNulls(ast.SendSet node, LocalElement local, ast.Node rhs, arg,
      {bool isSetterValid}) {
    handleCompoundSendSet(node);
  }

  @override
  handleStaticSetIfNulls(
      ast.SendSet node,
      Element getter,
      CompoundGetter getterKind,
      Element setter,
      CompoundSetter setterKind,
      ast.Node rhs,
      arg) {
    handleCompoundSendSet(node);
  }

  @override
  handleSuperSetIfNulls(
      ast.SendSet node,
      Element getter,
      CompoundGetter getterKind,
      Element setter,
      CompoundSetter setterKind,
      ast.Node rhs,
      arg) {
    handleSuperSendSet(node);
  }

  @override
  handleSuperIndexSetIfNull(ast.SendSet node, Element indexFunction,
      Element indexSetFunction, ast.Node index, ast.Node rhs, arg,
      {bool isGetterValid, bool isSetterValid}) {
    handleCompoundSendSet(node);
  }

  @override
  visitIndexSetIfNull(
      ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, arg,
      {bool isGetterValid, bool isSetterValid}) {
    generateIsDeferredLoadedCheckOfSend(node);
    handleIndexSendSet(node);
  }

  @override
  handleTypeLiteralConstantSetIfNulls(
      ast.SendSet node, ConstantExpression constant, ast.Node rhs, arg) {
    // The type variable is never `null`.
    generateConstantTypeLiteral(node);
  }

  @override
  visitTypeVariableTypeLiteralSetIfNull(
      ast.Send node, TypeVariableElement element, ast.Node rhs, arg) {
    // The type variable is never `null`.
    generateTypeVariableLiteral(node, element.type);
  }

  void visitLiteralInt(ast.LiteralInt node) {
    stack.add(graph.addConstantInt(node.value, closedWorld));
  }

  void visitLiteralDouble(ast.LiteralDouble node) {
    stack.add(graph.addConstantDouble(node.value, closedWorld));
  }

  void visitLiteralBool(ast.LiteralBool node) {
    stack.add(graph.addConstantBool(node.value, closedWorld));
  }

  void visitLiteralString(ast.LiteralString node) {
    stack.add(
        graph.addConstantString(node.dartString.slowToString(), closedWorld));
  }

  void visitLiteralSymbol(ast.LiteralSymbol node) {
    stack.add(addConstant(node));
    registry?.registerConstSymbol(node.slowNameString);
  }

  void visitStringJuxtaposition(ast.StringJuxtaposition node) {
    if (!node.isInterpolation) {
      // This is a simple string with no interpolations.
      stack.add(
          graph.addConstantString(node.dartString.slowToString(), closedWorld));
      return;
    }
    StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node);
    stringBuilder.visit(node);
    stack.add(stringBuilder.result);
  }

  void visitLiteralNull(ast.LiteralNull node) {
    stack.add(graph.addConstantNull(closedWorld));
  }

  visitNodeList(ast.NodeList node) {
    for (Link<ast.Node> link = node.nodes; !link.isEmpty; link = link.tail) {
      if (isAborted()) {
        reporter.reportHintMessage(
            link.head, MessageKind.GENERIC, {'text': 'dead code'});
      } else {
        visit(link.head);
      }
    }
  }

  void visitParenthesizedExpression(ast.ParenthesizedExpression node) {
    visit(node.expression);
  }

  visitOperator(ast.Operator node) {
    // Operators are intercepted in their surrounding Send nodes.
    reporter.internalError(
        node, 'SsaBuilder.visitOperator should not be called.');
  }

  visitCascade(ast.Cascade node) {
    visit(node.expression);
    // Remove the result and reveal the duplicated receiver on the stack.
    pop();
  }

  visitCascadeReceiver(ast.CascadeReceiver node) {
    visit(node.expression);
    dup();
  }

  visitRethrow(ast.Rethrow node) {
    HInstruction exception = rethrowableException;
    if (exception == null) {
      exception = graph.addConstantNull(closedWorld);
      reporter.internalError(node, 'rethrowableException should not be null.');
    }
    handleInTryStatement();
    closeAndGotoExit(new HThrow(
        exception, sourceInformationBuilder.buildThrow(node),
        isRethrow: true));
  }

  visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
    ConstructorElement targetConstructor =
        elements.getRedirectingTargetConstructor(node).implementation;
    ConstructorElement redirectingConstructor = sourceElement.implementation;
    List<HInstruction> inputs = <HInstruction>[];
    FunctionSignature targetSignature = targetConstructor.functionSignature;
    FunctionSignature redirectingSignature =
        redirectingConstructor.functionSignature;

    List<Element> targetRequireds = targetSignature.requiredParameters;
    List<Element> redirectingRequireds =
        redirectingSignature.requiredParameters;

    List<Element> targetOptionals = targetSignature.orderedOptionalParameters;
    List<Element> redirectingOptionals =
        redirectingSignature.orderedOptionalParameters;

    // TODO(25579): This code can do the wrong thing redirecting constructor and
    // the target do not correspond. It is correct if there is no
    // warning. Ideally the redirecting constructor and the target would be the
    // same function.

    void loadLocal(ParameterElement parameter) {
      inputs.add(localsHandler.readLocal(parameter));
    }

    void loadPosition(int position, ParameterElement optionalParameter) {
      if (position < redirectingRequireds.length) {
        loadLocal(redirectingRequireds[position]);
      } else if (position < redirectingSignature.parameterCount &&
          !redirectingSignature.optionalParametersAreNamed) {
        loadLocal(redirectingOptionals[position - redirectingRequireds.length]);
      } else if (optionalParameter != null) {
        inputs.add(handleConstantForOptionalParameter(optionalParameter));
      } else {
        // Wrong.
        inputs.add(graph.addConstantNull(closedWorld));
      }
    }

    int position = 0;

    for (ParameterElement _ in targetRequireds) {
      loadPosition(position++, null);
    }

    if (targetOptionals.isNotEmpty) {
      if (targetSignature.optionalParametersAreNamed) {
        for (ParameterElement parameter in targetOptionals) {
          ParameterElement redirectingParameter = redirectingOptionals
              .firstWhere((p) => p.name == parameter.name, orElse: () => null);
          if (redirectingParameter == null) {
            inputs.add(handleConstantForOptionalParameter(parameter));
          } else {
            inputs.add(localsHandler.readLocal(redirectingParameter));
          }
        }
      } else {
        for (ParameterElement parameter in targetOptionals) {
          loadPosition(position++, parameter);
        }
      }
    }

    ClassElement targetClass = targetConstructor.enclosingClass;
    if (rtiNeed.classNeedsTypeArguments(targetClass)) {
      ClassElement cls = redirectingConstructor.enclosingClass;
      ResolutionDartType targetType =
          redirectingConstructor.computeEffectiveTargetType(cls.thisType);
      targetType = localsHandler.substInContext(targetType);
      if (targetType is ResolutionInterfaceType) {
        targetType.typeArguments.forEach((ResolutionDartType argument) {
          inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
        });
      }
    }
    pushInvokeStatic(node, targetConstructor.declaration, inputs);
    HInstruction value = pop();
    emitReturn(value, node);
  }

  /// Returns true if the [type] is a valid return type for an asynchronous
  /// function.
  ///
  /// Asynchronous functions return a `Future`, and a valid return is thus
  /// either dynamic, Object, or Future.
  ///
  /// We do not accept the internal Future implementation class.
  bool isValidAsyncReturnType(ResolutionDartType type) {
    assert(isBuildingAsyncFunction);
    // TODO(sigurdm): In an internal library a function could be declared:
    //
    // _FutureImpl foo async => 1;
    //
    // This should be valid (because the actual value returned from an async
    // function is a `_FutureImpl`), but currently false is returned in this
    // case.
    return type.isDynamic ||
        type.isObject ||
        (type is ResolutionInterfaceType &&
            type.element == commonElements.futureClass);
  }

  visitReturn(ast.Return node) {
    if (identical(node.beginToken.stringValue, 'native')) {
      native.handleSsaNative(this, node.expression);
      return;
    }
    HInstruction value;
    if (node.expression == null) {
      value = graph.addConstantNull(closedWorld);
    } else {
      visit(node.expression);
      value = pop();
      if (isBuildingAsyncFunction) {
        if (options.enableTypeAssertions &&
            !isValidAsyncReturnType(returnType)) {
          String message = "Async function returned a Future, "
              "was declared to return a $returnType.";
          generateTypeError(node, message);
          pop();
          return;
        }
      } else {
        value = typeBuilder.potentiallyCheckOrTrustType(value, returnType);
      }
    }

    handleInTryStatement();
    emitReturn(value, node);
  }

  visitThrow(ast.Throw node) {
    visitThrowExpression(node.expression);
    if (isReachable) {
      handleInTryStatement();
      push(new HThrowExpression(
          pop(), sourceInformationBuilder.buildThrow(node)));
      isReachable = false;
    }
  }

  visitYield(ast.Yield node) {
    visit(node.expression);
    HInstruction yielded = pop();
    add(new HYield(
        yielded, node.hasStar, sourceInformationBuilder.buildYield(node)));
  }

  visitAwait(ast.Await node) {
    visit(node.expression);
    HInstruction awaited = pop();
    // TODO(herhut): Improve this type.
    push(new HAwait(
        awaited, new TypeMask.subclass(commonElements.objectClass, closedWorld))
      ..sourceInformation = sourceInformationBuilder.buildAwait(node));
  }

  visitTypeAnnotation(ast.TypeAnnotation node) {
    reporter.internalError(node, 'Visiting type annotation in SSA builder.');
  }

  visitVariableDefinitions(ast.VariableDefinitions node) {
    assert(isReachable);
    for (Link<ast.Node> link = node.definitions.nodes;
        !link.isEmpty;
        link = link.tail) {
      ast.Node definition = link.head;
      LocalElement local = elements[definition];
      if (definition is ast.Identifier) {
        HInstruction initialValue = graph.addConstantNull(closedWorld);
        localsHandler.updateLocal(local, initialValue);
      } else {
        ast.SendSet node = definition;
        generateNonInstanceSetter(
            node, local, visitAndPop(node.arguments.first));
        pop(); // Discard value.
      }
    }
  }

  HInstruction setRtiIfNeeded(
      HInstruction object, ast.Node node, SourceInformation sourceInformation) {
    ResolutionInterfaceType type =
        localsHandler.substInContext(elements.getType(node));
    if (!rtiNeed.classNeedsTypeArguments(type.element) || type.treatAsRaw) {
      return object;
    }
    List<HInstruction> arguments = <HInstruction>[];
    for (ResolutionDartType argument in type.typeArguments) {
      arguments.add(typeBuilder.analyzeTypeArgument(argument, sourceElement,
          sourceInformation: sourceInformation));
    }
    // TODO(15489): Register at codegen.
    registry?.registerInstantiation(type);
    return callSetRuntimeTypeInfoWithTypeArguments(
        type, arguments, object, sourceInformation);
  }

  visitLiteralList(ast.LiteralList node) {
    HInstruction instruction;

    if (node.isConst) {
      instruction = addConstant(node);
    } else {
      List<HInstruction> inputs = <HInstruction>[];
      for (Link<ast.Node> link = node.elements.nodes;
          !link.isEmpty;
          link = link.tail) {
        visit(link.head);
        inputs.add(pop());
      }
      instruction = buildLiteralList(inputs);
      add(instruction);
      instruction = setRtiIfNeeded(
          instruction, node, sourceInformationBuilder.buildListLiteral(node));
    }

    TypeMask type = _inferredTypeOfListLiteral(node);
    if (!type.containsAll(closedWorld)) {
      instruction.instructionType = type;
    }
    stack.add(instruction);
  }

  _inferredTypeOfNewList(ast.Send node) =>
      _resultOf(sourceElement).typeOfNewList(node) ?? commonMasks.dynamicType;

  _inferredTypeOfListLiteral(ast.LiteralList node) =>
      _resultOf(sourceElement).typeOfListLiteral(node) ??
      commonMasks.dynamicType;

  visitConditional(ast.Conditional node) {
    SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
    brancher.handleConditional(() => visit(node.condition),
        () => visit(node.thenExpression), () => visit(node.elseExpression));
  }

  visitStringInterpolation(ast.StringInterpolation node) {
    StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node);
    stringBuilder.visit(node);
    stack.add(stringBuilder.result);
  }

  visitStringInterpolationPart(ast.StringInterpolationPart node) {
    // The parts are iterated in visitStringInterpolation.
    reporter.internalError(
        node, 'SsaBuilder.visitStringInterpolation should not be called.');
  }

  visitEmptyStatement(ast.EmptyStatement node) {
    // Do nothing, empty statement.
  }

  visitModifiers(ast.Modifiers node) {
    failedAt(node, 'SsaFromAstMixin.visitModifiers not implemented.');
  }

  visitBreakStatement(ast.BreakStatement node) {
    assert(!isAborted());
    handleInTryStatement();
    JumpTarget target = elements.getTargetOf(node);
    assert(target != null);
    JumpHandler handler = jumpTargets[target];
    assert(handler != null);
    if (node.target == null) {
      handler.generateBreak(sourceInformationBuilder.buildGoto(node));
    } else {
      LabelDefinition label = elements.getTargetLabel(node);
      handler.generateBreak(sourceInformationBuilder.buildGoto(node), label);
    }
  }

  visitContinueStatement(ast.ContinueStatement node) {
    handleInTryStatement();
    JumpTarget target = elements.getTargetOf(node);
    assert(target != null);
    JumpHandler handler = jumpTargets[target];
    assert(handler != null);
    if (node.target == null) {
      handler.generateContinue(sourceInformationBuilder.buildGoto(node));
    } else {
      LabelDefinition label = elements.getTargetLabel(node);
      assert(label != null);
      handler.generateContinue(sourceInformationBuilder.buildGoto(node), label);
    }
  }

  /**
   * Creates a [JumpHandler] for a statement. The node must be a jump
   * target. If there are no breaks or continues targeting the statement,
   * a special "null handler" is returned.
   *
   * [isLoopJump] is [:true:] when the jump handler is for a loop. This is used
   * to distinguish the synthesized loop created for a switch statement with
   * continue statements from simple switch statements.
   */
  JumpHandler createJumpHandler(ast.Statement node, JumpTarget jumpTarget,
      {bool isLoopJump}) {
    if (jumpTarget == null || !identical(jumpTarget.statement, node)) {
      // No breaks or continues to this node.
      return new NullJumpHandler(reporter);
    }
    if (isLoopJump && node is ast.SwitchStatement) {
      // Create a special jump handler for loops created for switch statements
      // with continue statements.
      return new AstSwitchCaseJumpHandler(this, jumpTarget, node);
    }
    return new JumpHandler(this, jumpTarget);
  }

  visitAsyncForIn(ast.AsyncForIn node) {
    // The async-for is implemented with a StreamIterator.
    HInstruction streamIterator;

    visit(node.expression);
    HInstruction expression = pop();
    ConstructorElement constructor = commonElements.streamIteratorConstructor;
    pushInvokeStatic(
        node, constructor, [expression, graph.addConstantNull(closedWorld)]);
    streamIterator = pop();

    void buildInitializer() {}

    HInstruction buildCondition() {
      Selector selector = Selectors.moveNext;
      TypeMask mask = elementInferenceResults.typeOfIteratorMoveNext(node);
      pushInvokeDynamic(node, selector, mask, [streamIterator]);
      HInstruction future = pop();
      push(new HAwait(future,
          new TypeMask.subclass(commonElements.objectClass, closedWorld)));
      return popBoolified();
    }

    void buildBody() {
      Selector call = Selectors.current;
      TypeMask callMask = elementInferenceResults.typeOfIteratorCurrent(node);
      pushInvokeDynamic(node, call, callMask, [streamIterator]);

      ast.Node identifier = node.declaredIdentifier;
      Element variable = elements.getForInVariable(node);
      Selector selector = elements.getSelector(identifier);
      HInstruction value = pop();
      if (identifier.asSend() != null &&
          Elements.isInstanceSend(identifier, elements)) {
        TypeMask mask = elementInferenceResults.typeOfSend(identifier);
        HInstruction receiver = generateInstanceSendReceiver(identifier);
        assert(receiver != null);
        generateInstanceSetterWithCompiledReceiver(null, receiver, value,
            selector: selector, mask: mask, location: identifier);
      } else {
        generateNonInstanceSetter(null, variable, value, location: identifier);
      }
      pop(); // Pop the value pushed by the setter call.

      visit(node.body);
    }

    void buildUpdate() {}

    buildProtectedByFinally(() {
      loopHandler.handleLoop(
          node,
          closureDataLookup.getCapturedLoopScope(node),
          elements.getTargetDefinition(node),
          buildInitializer,
          buildCondition,
          buildUpdate,
          buildBody,
          sourceInformationBuilder.buildLoop(node));
    }, () {
      pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]);
      add(new HAwait(pop(),
          new TypeMask.subclass(commonElements.objectClass, closedWorld)));
    });
  }

  visitSyncForIn(ast.SyncForIn node) {
    // The 'get iterator' selector for this node has the inferred receiver type.
    // If the receiver supports JavaScript indexing we generate an indexing loop
    // instead of allocating an iterator object.

    // This scheme recognizes for-in on direct lists.  It does not recognize all
    // uses of ArrayIterator.  They still occur when the receiver is an Iterable
    // with a `get iterator` method that delegates to another Iterable and the
    // method is inlined.  We would require full scalar replacement in that
    // case.

    TypeMask mask = elementInferenceResults.typeOfIterator(node);

    if (mask != null &&
        mask.satisfies(commonElements.jsIndexableClass, closedWorld) &&
        // String is indexable but not iterable.
        !mask.satisfies(commonElements.jsStringClass, closedWorld)) {
      return buildSyncForInIndexable(node, mask);
    }
    buildSyncForInIterator(node);
  }

  buildSyncForInIterator(ast.SyncForIn node) {
    // Generate a structure equivalent to:
    //   Iterator<E> $iter = <iterable>.iterator;
    //   while ($iter.moveNext()) {
    //     <declaredIdentifier> = $iter.current;
    //     <body>
    //   }

    // The iterator is shared between initializer, condition and body.
    HInstruction iterator;

    void buildInitializer() {
      Selector selector = Selectors.iterator;
      TypeMask mask = elementInferenceResults.typeOfIterator(node);
      visit(node.expression);
      HInstruction receiver = pop();
      pushInvokeDynamic(node, selector, mask, [receiver],
          sourceInformation: sourceInformationBuilder.buildForInIterator(node));
      iterator = pop();
    }

    HInstruction buildCondition() {
      Selector selector = Selectors.moveNext;
      TypeMask mask = elementInferenceResults.typeOfIteratorMoveNext(node);
      pushInvokeDynamic(node, selector, mask, [iterator],
          sourceInformation: sourceInformationBuilder.buildForInMoveNext(node));
      return popBoolified();
    }

    void buildBody() {
      Selector call = Selectors.current;
      TypeMask mask = elementInferenceResults.typeOfIteratorCurrent(node);
      pushInvokeDynamic(node, call, mask, [iterator],
          sourceInformation: sourceInformationBuilder.buildForInCurrent(node));
      buildAssignLoopVariable(node, pop());
      visit(node.body);
    }

    loopHandler.handleLoop(
        node,
        closureDataLookup.getCapturedLoopScope(node),
        elements.getTargetDefinition(node),
        buildInitializer,
        buildCondition,
        () {},
        buildBody,
        sourceInformationBuilder.buildLoop(node));
  }

  buildAssignLoopVariable(ast.ForIn node, HInstruction value) {
    ast.Node identifier = node.declaredIdentifier;
    Element variable = elements.getForInVariable(node);
    Selector selector = elements.getSelector(identifier);

    if (identifier.asSend() != null &&
        Elements.isInstanceSend(identifier, elements)) {
      TypeMask mask = elementInferenceResults.typeOfSend(identifier);
      HInstruction receiver = generateInstanceSendReceiver(identifier);
      assert(receiver != null);
      generateInstanceSetterWithCompiledReceiver(null, receiver, value,
          selector: selector, mask: mask, location: identifier);
    } else {
      generateNonInstanceSetter(null, variable, value, location: identifier);
    }
    pop(); // Discard the value pushed by the setter call.
  }

  buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) {
    // Generate a structure equivalent to:
    //
    //     int end = a.length;
    //     for (int i = 0;
    //          i < a.length;
    //          checkConcurrentModificationError(a.length == end, a), ++i) {
    //       <declaredIdentifier> = a[i];
    //       <body>
    //     }
    ExecutableElement loopVariable = elements.getForInVariable(node);
    SyntheticLocal indexVariable =
        new SyntheticLocal('_i', loopVariable, target);
    TypeMask boolType = commonMasks.boolType;

    // These variables are shared by initializer, condition, body and update.
    HInstruction array; // Set in buildInitializer.
    bool isFixed; // Set in buildInitializer.
    HInstruction originalLength = null; // Set for growable lists.

    HInstruction buildGetLength() {
      HInstruction result = new HGetLength(array, commonMasks.positiveIntType,
          isAssignable: !isFixed);
      add(result);
      return result;
    }

    void buildConcurrentModificationErrorCheck() {
      if (originalLength == null) return;
      // The static call checkConcurrentModificationError() is expanded in
      // codegen to:
      //
      //     array.length == _end || throwConcurrentModificationError(array)
      //
      HInstruction length = buildGetLength();
      push(new HIdentity(length, originalLength, null, boolType));
      pushInvokeStatic(node, commonElements.checkConcurrentModificationError,
          [pop(), array]);
      pop();
    }

    void buildInitializer() {
      visit(node.expression);
      array = pop();
      isFixed = isFixedLength(array.instructionType, closedWorld);
      localsHandler.updateLocal(
          indexVariable, graph.addConstantInt(0, closedWorld));
      originalLength = buildGetLength();
    }

    HInstruction buildCondition() {
      HInstruction index = localsHandler.readLocal(indexVariable);
      HInstruction length = buildGetLength();
      HInstruction compare = new HLess(index, length, null, boolType);
      add(compare);
      return compare;
    }

    void buildBody() {
      // If we had mechanically inlined ArrayIterator.moveNext(), it would have
      // inserted the ConcurrentModificationError check as part of the
      // condition.  It is not necessary on the first iteration since there is
      // no code between calls to `get iterator` and `moveNext`, so the test is
      // moved to the loop update.

      // Find a type for the element. Use the element type of the indexer of the
      // array, as this is stronger than the iterator's `get current` type, for
      // example, `get current` includes null.
      // TODO(sra): The element type of a container type mask might be better.
      Selector selector = new Selector.index();
      TypeMask type = TypeMaskFactory.inferredTypeForSelector(
          selector, arrayType, globalInferenceResults);

      HInstruction index = localsHandler.readLocal(indexVariable);
      HInstruction value = new HIndex(array, index, null, type);
      add(value);

      buildAssignLoopVariable(node, value);
      visit(node.body);
    }

    void buildUpdate() {
      // See buildBody as to why we check here.
      buildConcurrentModificationErrorCheck();

      // TODO(sra): It would be slightly shorter to generate `a[i++]` in the
      // body (and that more closely follows what an inlined iterator would do)
      // but the code is horrible as `i+1` is carried around the loop in an
      // additional variable.
      HInstruction index = localsHandler.readLocal(indexVariable);
      HInstruction one = graph.addConstantInt(1, closedWorld);
      HInstruction addInstruction =
          new HAdd(index, one, null, commonMasks.positiveIntType);
      add(addInstruction);
      localsHandler.updateLocal(indexVariable, addInstruction);
    }

    loopHandler.handleLoop(
        node,
        closureDataLookup.getCapturedLoopScope(node),
        elements.getTargetDefinition(node),
        buildInitializer,
        buildCondition,
        buildUpdate,
        buildBody,
        sourceInformationBuilder.buildLoop(node));
  }

  visitLabel(ast.Label node) {
    reporter.internalError(node, 'SsaFromAstMixin.visitLabel.');
  }

  visitLabeledStatement(ast.LabeledStatement node) {
    ast.Statement body = node.statement;
    if (body is ast.Loop ||
        body is ast.SwitchStatement ||
        Elements.isUnusedLabel(node, elements)) {
      // Loops and switches handle their own labels.
      visit(body);
      return;
    }
    JumpTarget targetElement = elements.getTargetDefinition(body);
    LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler);
    assert(targetElement.isBreakTarget);
    JumpHandler handler = new JumpHandler(this, targetElement);
    // Introduce a new basic block.
    HBasicBlock entryBlock = openNewBlock();
    visit(body);
    SubGraph bodyGraph = new SubGraph(entryBlock, lastOpenedBlock);

    HBasicBlock joinBlock = graph.addNewBlock();
    List<LocalsHandler> breakHandlers = <LocalsHandler>[];
    handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
      breakInstruction.block.addSuccessor(joinBlock);
      breakHandlers.add(locals);
    });
    bool hasBreak = breakHandlers.length > 0;
    if (!isAborted()) {
      goto(current, joinBlock);
      breakHandlers.add(localsHandler);
    }
    open(joinBlock);
    localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock);

    if (hasBreak) {
      // There was at least one reachable break, so the label is needed.
      entryBlock.setBlockFlow(
          new HLabeledBlockInformation(
              new HSubGraphBlockInformation(bodyGraph), handler.labels),
          joinBlock);
    }
    handler.close();
  }

  visitLiteralMap(ast.LiteralMap node) {
    if (node.isConst) {
      stack.add(addConstant(node));
      return;
    }
    List<HInstruction> listInputs = <HInstruction>[];
    for (Link<ast.Node> link = node.entries.nodes;
        !link.isEmpty;
        link = link.tail) {
      visit(link.head);
      listInputs.add(pop());
      listInputs.add(pop());
    }

    ConstructorElement listConstructor;
    List<HInstruction> inputs = <HInstruction>[];

    if (listInputs.isEmpty) {
      listConstructor = commonElements.mapLiteralConstructorEmpty;
    } else {
      listConstructor = commonElements.mapLiteralConstructor;
      HLiteralList keyValuePairs = buildLiteralList(listInputs);
      add(keyValuePairs);
      inputs.add(keyValuePairs);
    }

    assert(listConstructor.isFactoryConstructor);

    ConstructorElement constructorElement = listConstructor;
    listConstructor = constructorElement.effectiveTarget;

    ResolutionInterfaceType type = elements.getType(node);
    ResolutionDartType expectedType =
        constructorElement.computeEffectiveTargetType(type);
    expectedType = localsHandler.substInContext(expectedType);

    ClassElement cls = listConstructor.enclosingClass;

    MethodElement createFunction = listConstructor;
    if (expectedType is ResolutionInterfaceType &&
        rtiNeed.classNeedsTypeArguments(cls)) {
      List<HInstruction> typeInputs = <HInstruction>[];
      expectedType.typeArguments.forEach((ResolutionDartType argument) {
        typeInputs
            .add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
      });

      // We lift this common call pattern into a helper function to save space
      // in the output.
      if (typeInputs.every((HInstruction input) => input.isNull())) {
        if (listInputs.isEmpty) {
          createFunction = commonElements.mapLiteralUntypedEmptyMaker;
        } else {
          createFunction = commonElements.mapLiteralUntypedMaker;
        }
      } else {
        inputs.addAll(typeInputs);
      }
    }

    // If rti is needed and the map literal has no type parameters,
    // 'constructor' is a static function that forwards the call to the factory
    // constructor without type parameters.
    assert(createFunction is ConstructorElement ||
        createFunction is FunctionElement);

    // The instruction type will always be a subtype of the mapLiteralClass, but
    // type inference might discover a more specific type, or find nothing (in
    // dart2js unit tests).
    TypeMask mapType = new TypeMask.nonNullSubtype(
        commonElements.mapLiteralClass, closedWorld);
    TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement(
        createFunction, globalInferenceResults);
    TypeMask instructionType =
        mapType.intersection(returnTypeMask, closedWorld);

    addInlinedInstantiation(expectedType);
    pushInvokeStatic(node, createFunction, inputs,
        typeMask: instructionType, instanceType: expectedType);
    removeInlinedInstantiation(expectedType);
  }

  visitLiteralMapEntry(ast.LiteralMapEntry node) {
    visit(node.value);
    visit(node.key);
  }

  visitNamedArgument(ast.NamedArgument node) {
    visit(node.expression);
  }

  Map<ast.CaseMatch, ConstantValue> buildSwitchCaseConstants(
      ast.SwitchStatement node) {
    Map<ast.CaseMatch, ConstantValue> constants =
        new Map<ast.CaseMatch, ConstantValue>();
    for (ast.SwitchCase switchCase in node.cases) {
      for (ast.Node labelOrCase in switchCase.labelsAndCases) {
        if (labelOrCase is ast.CaseMatch) {
          ast.CaseMatch match = labelOrCase;
          ConstantValue constant = getConstantForNode(match.expression);
          constants[labelOrCase] = constant;
        }
      }
    }
    return constants;
  }

  visitSwitchStatement(ast.SwitchStatement node) {
    SourceInformation sourceInformation =
        sourceInformationBuilder.buildSwitch(node);
    Map<ast.CaseMatch, ConstantValue> constants =
        buildSwitchCaseConstants(node);

    // The switch case indices must match those computed in
    // [SwitchCaseJumpHandler].
    bool hasContinue = false;
    Map<ast.SwitchCase, int> caseIndex = new Map<ast.SwitchCase, int>();
    int switchIndex = 1;
    bool hasDefault = false;
    for (ast.SwitchCase switchCase in node.cases) {
      for (ast.Node labelOrCase in switchCase.labelsAndCases) {
        ast.Node label = labelOrCase.asLabel();
        if (label != null) {
          LabelDefinition labelElement = elements.getLabelDefinition(label);
          if (labelElement != null && labelElement.isContinueTarget) {
            hasContinue = true;
          }
        }
      }
      if (switchCase.isDefaultCase) {
        hasDefault = true;
      }
      caseIndex[switchCase] = switchIndex;
      switchIndex++;
    }
    if (!hasContinue) {
      // If the switch statement has no switch cases targeted by continue
      // statements we encode the switch statement directly.
      buildSimpleSwitchStatement(node, constants, sourceInformation);
    } else {
      buildComplexSwitchStatement(
          node, constants, caseIndex, hasDefault, sourceInformation);
    }
  }

  /**
   * Builds a simple switch statement which does not handle uses of continue
   * statements to labeled switch cases.
   */
  void buildSimpleSwitchStatement(
      ast.SwitchStatement node,
      Map<ast.CaseMatch, ConstantValue> constants,
      SourceInformation sourceInformation) {
    JumpHandler jumpHandler = createJumpHandler(
        node, elements.getTargetDefinition(node),
        isLoopJump: false);
    HInstruction buildExpression() {
      visit(node.expression);
      return pop();
    }

    Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) {
      List<ConstantValue> constantList = <ConstantValue>[];
      for (ast.Node labelOrCase in switchCase.labelsAndCases) {
        if (labelOrCase is ast.CaseMatch) {
          constantList.add(constants[labelOrCase]);
        }
      }
      return constantList;
    }

    bool isDefaultCase(ast.SwitchCase switchCase) {
      return switchCase.isDefaultCase;
    }

    void buildSwitchCase(ast.SwitchCase node) {
      visit(node.statements);
    }

    handleSwitch(node, jumpHandler, buildExpression, node.cases, getConstants,
        isDefaultCase, buildSwitchCase, sourceInformation);
    jumpHandler.close();
  }

  /**
   * Builds a switch statement that can handle arbitrary uses of continue
   * statements to labeled switch cases.
   */
  void buildComplexSwitchStatement(
      ast.SwitchStatement node,
      Map<ast.CaseMatch, ConstantValue> constants,
      Map<ast.SwitchCase, int> caseIndex,
      bool hasDefault,
      SourceInformation sourceInformation) {
    // If the switch statement has switch cases targeted by continue
    // statements we create the following encoding:
    //
    //   switch (e) {
    //     l_1: case e0: s_1; break;
    //     l_2: case e1: s_2; continue l_i;
    //     ...
    //     l_n: default: s_n; continue l_j;
    //   }
    //
    // is encoded as
    //
    //   var target;
    //   switch (e) {
    //     case e1: target = 1; break;
    //     case e2: target = 2; break;
    //     ...
    //     default: target = n; break;
    //   }
    //   l: while (true) {
    //    switch (target) {
    //       case 1: s_1; break l;
    //       case 2: s_2; target = i; continue l;
    //       ...
    //       case n: s_n; target = j; continue l;
    //     }
    //   }

    JumpTarget switchTarget = elements.getTargetDefinition(node);
    HInstruction initialValue = graph.addConstantNull(closedWorld);
    localsHandler.updateLocal(switchTarget, initialValue);

    JumpHandler jumpHandler =
        createJumpHandler(node, switchTarget, isLoopJump: false);
    dynamic switchCases = node.cases;
    if (!hasDefault) {
      // Use [:null:] as the marker for a synthetic default clause.
      // The synthetic default is added because otherwise, there would be no
      // good place to give a default value to the local.
      switchCases = node.cases.nodes.toList()..add(null);
    }
    HInstruction buildExpression() {
      visit(node.expression);
      return pop();
    }

    Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) {
      List<ConstantValue> constantList = <ConstantValue>[];
      if (switchCase != null) {
        for (ast.Node labelOrCase in switchCase.labelsAndCases) {
          if (labelOrCase is ast.CaseMatch) {
            constantList.add(constants[labelOrCase]);
          }
        }
      }
      return constantList;
    }

    bool isDefaultCase(ast.SwitchCase switchCase) {
      return switchCase == null || switchCase.isDefaultCase;
    }

    void buildSwitchCase(ast.SwitchCase switchCase) {
      SourceInformation caseSourceInformation = sourceInformation;
      if (switchCase != null) {
        caseSourceInformation = sourceInformationBuilder.buildGoto(switchCase);
        // Generate 'target = i; break;' for switch case i.
        int index = caseIndex[switchCase];
        HInstruction value = graph.addConstantInt(index, closedWorld);
        localsHandler.updateLocal(switchTarget, value,
            sourceInformation: caseSourceInformation);
      } else {
        // Generate synthetic default case 'target = null; break;'.
        HInstruction value = graph.addConstantNull(closedWorld);
        localsHandler.updateLocal(switchTarget, value,
            sourceInformation: caseSourceInformation);
      }
      jumpTargets[switchTarget].generateBreak(caseSourceInformation);
    }

    handleSwitch(node, jumpHandler, buildExpression, switchCases, getConstants,
        isDefaultCase, buildSwitchCase, sourceInformation);
    jumpHandler.close();

    HInstruction buildCondition() => graph.addConstantBool(true, closedWorld);

    void buildSwitch() {
      HInstruction buildExpression() {
        return localsHandler.readLocal(switchTarget);
      }

      Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) {
        return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])];
      }

      void buildSwitchCase(ast.SwitchCase switchCase) {
        visit(switchCase.statements);
        if (!isAborted()) {
          // Ensure that we break the loop if the case falls through. (This
          // is only possible for the last case.)
          jumpTargets[switchTarget].generateBreak(sourceInformation);
        }
      }

      // Pass a [NullJumpHandler] because the target for the contained break
      // is not the generated switch statement but instead the loop generated
      // in the call to [handleLoop] below.
      handleSwitch(
          node,
          new NullJumpHandler(reporter),
          buildExpression,
          node.cases,
          getConstants,
          (_) => false, // No case is default.
          buildSwitchCase,
          sourceInformation);
    }

    void buildLoop() {
      loopHandler.handleLoop(
          node,
          closureDataLookup.getCapturedLoopScope(node),
          switchTarget,
          () {},
          buildCondition,
          () {},
          buildSwitch,
          sourceInformationBuilder.buildLoop(node));
    }

    if (hasDefault) {
      buildLoop();
    } else {
      // If the switch statement has no default case, surround the loop with
      // a test of the target.
      void buildCondition() {
        js.Template code = js.js.parseForeignJS('#');
        push(new HForeignCode(
            code, commonMasks.boolType, [localsHandler.readLocal(switchTarget)],
            nativeBehavior: native.NativeBehavior.PURE));
      }

      handleIf(
          node: node,
          visitCondition: buildCondition,
          visitThen: buildLoop,
          visitElse: () => {},
          sourceInformation: sourceInformation);
    }
  }

  /**
   * Creates a switch statement.
   *
   * [jumpHandler] is the [JumpHandler] for the created switch statement.
   * [buildExpression] creates the switch expression.
   * [switchCases] must be either an [Iterable] of [ast.SwitchCase] nodes or
   *   a [Link] or a [ast.NodeList] of [ast.SwitchCase] nodes.
   * [getConstants] returns the set of constants for a switch case.
   * [isDefaultCase] returns true if the provided switch case should be
   *   considered default for the created switch statement.
   * [buildSwitchCase] creates the statements for the switch case.
   */
  void handleSwitch(
      ast.Node errorNode,
      JumpHandler jumpHandler,
      HInstruction buildExpression(),
      var switchCases,
      Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase),
      bool isDefaultCase(ast.SwitchCase switchCase),
      void buildSwitchCase(ast.SwitchCase switchCase),
      SourceInformation sourceInformation) {
    HBasicBlock expressionStart = openNewBlock();
    HInstruction expression = buildExpression();
    if (switchCases.isEmpty) {
      return;
    }

    HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
    HBasicBlock expressionEnd = close(switchInstruction);
    LocalsHandler savedLocals = localsHandler;

    List<HStatementInformation> statements = <HStatementInformation>[];
    bool hasDefault = false;
    HasNextIterator<ast.Node> caseIterator =
        new HasNextIterator<ast.Node>(switchCases.iterator);
    while (caseIterator.hasNext) {
      ast.SwitchCase switchCase = caseIterator.next();
      HBasicBlock block = graph.addNewBlock();
      for (ConstantValue constant in getConstants(switchCase)) {
        HConstant hConstant = graph.addConstant(constant, closedWorld);
        switchInstruction.inputs.add(hConstant);
        hConstant.usedBy.add(switchInstruction);
        expressionEnd.addSuccessor(block);
      }

      if (isDefaultCase(switchCase)) {
        // An HSwitch has n inputs and n+1 successors, the last being the
        // default case.
        expressionEnd.addSuccessor(block);
        hasDefault = true;
      }
      open(block);
      localsHandler = new LocalsHandler.from(savedLocals);
      buildSwitchCase(switchCase);
      if (!isAborted()) {
        if (caseIterator.hasNext && isReachable) {
          pushInvokeStatic(switchCase, commonElements.fallThroughError, []);
          HInstruction error = pop();
          closeAndGotoExit(new HThrow(error, error.sourceInformation));
        } else if (!isDefaultCase(switchCase)) {
          // If there is no default, we will add one later to avoid
          // the critical edge. So we generate a break statement to make
          // sure the last case does not fall through to the default case.
          jumpHandler.generateBreak(sourceInformation);
        }
      }
      statements.add(
          new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock)));
    }

    // Add a join-block if necessary.
    // We create [joinBlock] early, and then go through the cases that might
    // want to jump to it. In each case, if we add [joinBlock] as a successor
    // of another block, we also add an element to [caseHandlers] that is used
    // to create the phis in [joinBlock].
    // If we never jump to the join block, [caseHandlers] will stay empty, and
    // the join block is never added to the graph.
    HBasicBlock joinBlock = new HBasicBlock();
    List<LocalsHandler> caseHandlers = <LocalsHandler>[];
    jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
      instruction.block.addSuccessor(joinBlock);
      caseHandlers.add(locals);
    });
    jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) {
      assert(false, failedAt(errorNode, 'Continue cannot target a switch.'));
    });
    if (!isAborted()) {
      current.close(new HGoto());
      lastOpenedBlock.addSuccessor(joinBlock);
      caseHandlers.add(localsHandler);
    }
    if (!hasDefault) {
      // Always create a default case, to avoid a critical edge in the
      // graph.
      HBasicBlock defaultCase = addNewBlock();
      expressionEnd.addSuccessor(defaultCase);
      open(defaultCase);
      close(new HGoto());
      defaultCase.addSuccessor(joinBlock);
      caseHandlers.add(savedLocals);
      statements.add(new HSubGraphBlockInformation(
          new SubGraph(defaultCase, defaultCase)));
    }
    assert(caseHandlers.length == joinBlock.predecessors.length);
    if (caseHandlers.length != 0) {
      graph.addBlock(joinBlock);
      open(joinBlock);
      if (caseHandlers.length == 1) {
        localsHandler = caseHandlers[0];
      } else {
        localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock);
      }
    } else {
      // The joinblock is not used.
      joinBlock = null;
    }

    HSubExpressionBlockInformation expressionInfo =
        new HSubExpressionBlockInformation(
            new SubExpression(expressionStart, expressionEnd));
    expressionStart.setBlockFlow(
        new HSwitchBlockInformation(expressionInfo, statements,
            jumpHandler.target, jumpHandler.labels, sourceInformation),
        joinBlock);

    jumpHandler.close();
  }

  visitSwitchCase(ast.SwitchCase node) {
    reporter.internalError(node, 'SsaFromAstMixin.visitSwitchCase.');
  }

  visitCaseMatch(ast.CaseMatch node) {
    reporter.internalError(node, 'SsaFromAstMixin.visitCaseMatch.');
  }

  /// Calls [buildTry] inside a synthetic try block with [buildFinally] in the
  /// finally block.
  ///
  /// Note that to get the right locals behavior, the code visited by [buildTry]
  /// and [buildFinally] must have been analyzed as if inside a try-statement by
  /// [ClosureTranslator].
  void buildProtectedByFinally(void buildTry(), void buildFinally()) {
    // Save the current locals. The finally block must not reuse the existing
    // locals handler. None of the variables that have been defined in the
    // body-block will be used, but for loops we will add (unnecessary) phis
    // that will reference the body variables. This makes it look as if the
    // variables were used in a non-dominated block.
    LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
    HBasicBlock enterBlock = openNewBlock();
    HTry tryInstruction = new HTry();
    close(tryInstruction);
    bool oldInTryStatement = inTryStatement;
    inTryStatement = true;

    HBasicBlock startTryBlock;
    HBasicBlock endTryBlock;
    HBasicBlock startFinallyBlock;
    HBasicBlock endFinallyBlock;

    startTryBlock = graph.addNewBlock();
    open(startTryBlock);
    buildTry();
    // We use a [HExitTry] instead of a [HGoto] for the try block
    // because it will have two successors: the join block, and
    // the finally block.
    if (!isAborted()) endTryBlock = close(new HExitTry());
    SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock);

    SubGraph finallyGraph = null;

    localsHandler = new LocalsHandler.from(savedLocals);
    startFinallyBlock = graph.addNewBlock();
    open(startFinallyBlock);
    buildFinally();
    if (!isAborted()) endFinallyBlock = close(new HGoto());
    tryInstruction.finallyBlock = startFinallyBlock;
    finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock);

    HBasicBlock exitBlock = graph.addNewBlock();

    void addExitTrySuccessor(HBasicBlock successor) {
      // Iterate over all blocks created inside this try/catch, and
      // attach successor information to blocks that end with
      // [HExitTry].
      for (int i = startTryBlock.id; i < successor.id; i++) {
        HBasicBlock block = graph.blocks[i];
        var last = block.last;
        if (last is HExitTry) {
          block.addSuccessor(successor);
        }
      }
    }

    // Setup all successors. The entry block that contains the [HTry]
    // has 1) the body 2) the finally, and 4) the exit
    // blocks as successors.
    enterBlock.addSuccessor(startTryBlock);
    enterBlock.addSuccessor(startFinallyBlock);
    enterBlock.addSuccessor(exitBlock);

    // The body has the finally block as successor.
    if (endTryBlock != null) {
      endTryBlock.addSuccessor(startFinallyBlock);
      endTryBlock.addSuccessor(exitBlock);
    }

    // The finally block has the exit block as successor.
    endFinallyBlock.addSuccessor(exitBlock);

    // If a block inside try/catch aborts (eg with a return statement),
    // we explicitly mark this block a predecessor of the catch
    // block and the finally block.
    addExitTrySuccessor(startFinallyBlock);

    // Use the locals handler not altered by the catch and finally
    // blocks.
    // TODO(sigurdm): We can probably do this, because try-variables are boxed.
    // Need to verify.
    localsHandler = savedLocals;
    open(exitBlock);
    enterBlock.setBlockFlow(
        new HTryBlockInformation(
            wrapStatementGraph(bodyGraph),
            null, // No catch-variable.
            null, // No catchGraph.
            wrapStatementGraph(finallyGraph)),
        exitBlock);
    inTryStatement = oldInTryStatement;
  }

  visitTryStatement(ast.TryStatement node) {
    // Save the current locals. The catch block and the finally block
    // must not reuse the existing locals handler. None of the variables
    // that have been defined in the body-block will be used, but for
    // loops we will add (unnecessary) phis that will reference the body
    // variables. This makes it look as if the variables were used
    // in a non-dominated block.
    LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
    HBasicBlock enterBlock = openNewBlock();
    HTry tryInstruction = new HTry();
    close(tryInstruction);
    bool oldInTryStatement = inTryStatement;
    inTryStatement = true;

    HBasicBlock startTryBlock;
    HBasicBlock endTryBlock;
    HBasicBlock startCatchBlock;
    HBasicBlock endCatchBlock;
    HBasicBlock startFinallyBlock;
    HBasicBlock endFinallyBlock;

    startTryBlock = graph.addNewBlock();
    open(startTryBlock);
    visit(node.tryBlock);
    // We use a [HExitTry] instead of a [HGoto] for the try block
    // because it will have multiple successors: the join block, and
    // the catch or finally block.
    if (!isAborted()) endTryBlock = close(new HExitTry());
    SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock);
    SubGraph catchGraph = null;
    HLocalValue exception = null;

    if (!node.catchBlocks.isEmpty) {
      localsHandler = new LocalsHandler.from(savedLocals);
      startCatchBlock = graph.addNewBlock();
      open(startCatchBlock);
      // Note that the name of this local is irrelevant.
      SyntheticLocal local = localsHandler.createLocal('exception');
      SourceInformation trySourceInformation =
          sourceInformationBuilder.buildTry(node);
      exception = new HLocalValue(local, commonMasks.nonNullType)
        ..sourceInformation = trySourceInformation;
      add(exception);
      HInstruction oldRethrowableException = rethrowableException;
      rethrowableException = exception;

      pushInvokeStatic(node, commonElements.exceptionUnwrapper, [exception],
          sourceInformation: trySourceInformation);
      HInvokeStatic unwrappedException = pop();
      tryInstruction.exception = exception;
      Link<ast.Node> link = node.catchBlocks.nodes;

      void pushCondition(ast.CatchBlock catchBlock) {
        if (catchBlock.onKeyword != null) {
          ResolutionDartType type = elements.getType(catchBlock.type);
          if (type == null) {
            reporter.internalError(catchBlock.type, 'On with no type.');
          }
          HInstruction condition = buildIsNode(
              catchBlock.type,
              type,
              unwrappedException,
              sourceInformationBuilder.buildCatch(catchBlock.type));
          push(condition);
        } else {
          ast.VariableDefinitions declaration = catchBlock.formals.nodes.head;
          HInstruction condition = null;
          if (declaration.type == null) {
            condition = graph.addConstantBool(true, closedWorld);
            stack.add(condition);
          } else {
            // TODO(aprelev@gmail.com): Once old catch syntax is removed
            // "if" condition above and this "else" branch should be deleted as
            // type of declared variable won't matter for the catch
            // condition.
            ResolutionDartType type = elements.getType(declaration.type);
            if (type == null) {
              reporter.internalError(catchBlock, 'Catch with unresolved type.');
            }
            condition = buildIsNode(declaration.type, type, unwrappedException,
                sourceInformationBuilder.buildCatch(declaration));
            push(condition);
          }
        }
      }

      void visitThen() {
        ast.CatchBlock catchBlock = link.head;
        link = link.tail;
        if (catchBlock.exception != null) {
          LocalVariableElement exceptionVariable =
              elements[catchBlock.exception];
          localsHandler.updateLocal(exceptionVariable, unwrappedException,
              sourceInformation:
                  sourceInformationBuilder.buildCatch(catchBlock.exception));
        }
        ast.Node trace = catchBlock.trace;
        if (trace != null) {
          pushInvokeStatic(
              trace, commonElements.traceFromException, [exception]);
          HInstruction traceInstruction = pop();
          LocalVariableElement traceVariable = elements[trace];
          localsHandler.updateLocal(traceVariable, traceInstruction);
        }
        visit(catchBlock);
      }

      void visitElse() {
        if (link.isEmpty) {
          closeAndGotoExit(new HThrow(exception, exception.sourceInformation,
              isRethrow: true));
        } else {
          ast.CatchBlock newBlock = link.head;
          handleIf(
              node: node,
              visitCondition: () {
                pushCondition(newBlock);
              },
              visitThen: visitThen,
              visitElse: visitElse,
              sourceInformation: sourceInformationBuilder.buildCatch(newBlock));
        }
      }

      ast.CatchBlock firstBlock = link.head;
      handleIf(
          node: node,
          visitCondition: () {
            pushCondition(firstBlock);
          },
          visitThen: visitThen,
          visitElse: visitElse,
          sourceInformation: sourceInformationBuilder.buildCatch(firstBlock));
      if (!isAborted()) endCatchBlock = close(new HGoto());

      rethrowableException = oldRethrowableException;
      tryInstruction.catchBlock = startCatchBlock;
      catchGraph = new SubGraph(startCatchBlock, lastOpenedBlock);
    }

    SubGraph finallyGraph = null;
    if (node.finallyBlock != null) {
      localsHandler = new LocalsHandler.from(savedLocals);
      startFinallyBlock = graph.addNewBlock();
      open(startFinallyBlock);
      visit(node.finallyBlock);
      if (!isAborted()) endFinallyBlock = close(new HGoto());
      tryInstruction.finallyBlock = startFinallyBlock;
      finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock);
    }

    HBasicBlock exitBlock = graph.addNewBlock();

    addOptionalSuccessor(b1, b2) {
      if (b2 != null) b1.addSuccessor(b2);
    }

    addExitTrySuccessor(successor) {
      if (successor == null) return;
      // Iterate over all blocks created inside this try/catch, and
      // attach successor information to blocks that end with
      // [HExitTry].
      for (int i = startTryBlock.id; i < successor.id; i++) {
        HBasicBlock block = graph.blocks[i];
        var last = block.last;
        if (last is HExitTry) {
          block.addSuccessor(successor);
        }
      }
    }

    // Setup all successors. The entry block that contains the [HTry]
    // has 1) the body, 2) the catch, 3) the finally, and 4) the exit
    // blocks as successors.
    enterBlock.addSuccessor(startTryBlock);
    addOptionalSuccessor(enterBlock, startCatchBlock);
    addOptionalSuccessor(enterBlock, startFinallyBlock);
    enterBlock.addSuccessor(exitBlock);

    // The body has either the catch or the finally block as successor.
    if (endTryBlock != null) {
      assert(startCatchBlock != null || startFinallyBlock != null);
      endTryBlock.addSuccessor(
          startCatchBlock != null ? startCatchBlock : startFinallyBlock);
      endTryBlock.addSuccessor(exitBlock);
    }

    // The catch block has either the finally or the exit block as
    // successor.
    if (endCatchBlock != null) {
      endCatchBlock.addSuccessor(
          startFinallyBlock != null ? startFinallyBlock : exitBlock);
    }

    // The finally block has the exit block as successor.
    if (endFinallyBlock != null) {
      endFinallyBlock.addSuccessor(exitBlock);
    }

    // If a block inside try/catch aborts (eg with a return statement),
    // we explicitly mark this block a predecessor of the catch
    // block and the finally block.
    addExitTrySuccessor(startCatchBlock);
    addExitTrySuccessor(startFinallyBlock);

    // Use the locals handler not altered by the catch and finally
    // blocks.
    localsHandler = savedLocals;
    open(exitBlock);
    enterBlock.setBlockFlow(
        new HTryBlockInformation(wrapStatementGraph(bodyGraph), exception,
            wrapStatementGraph(catchGraph), wrapStatementGraph(finallyGraph)),
        exitBlock);
    inTryStatement = oldInTryStatement;
  }

  visitCatchBlock(ast.CatchBlock node) {
    visit(node.block);
  }

  visitTypedef(ast.Typedef node) {
    failedAt(node, 'SsaFromAstMixin.visitTypedef not implemented.');
  }

  visitTypeVariable(ast.TypeVariable node) {
    failedAt(node, 'SsaFromAstMixin.visitTypeVariable not implemented.');
  }

  /**
   * This method is invoked before inlining the body of [function] into this
   * [SsaBuilder].
   */
  void enterInlinedMethod(
      MethodElement function,
      ResolvedAst functionResolvedAst,
      List<HInstruction> compiledArguments,
      ResolutionInterfaceType instanceType) {
    AstInliningState state = new AstInliningState(
        function,
        returnLocal,
        returnType,
        resolvedAst,
        stack,
        localsHandler,
        inTryStatement,
        isCalledOnce(functionResolvedAst.element),
        elementInferenceResults);
    resolvedAst = functionResolvedAst;
    elementInferenceResults = _resultOf(functionResolvedAst.element);
    inliningStack.add(state);

    // Setting up the state of the (AST) builder is performed even when the
    // inlined function is in IR, because the irInliner uses the [returnElement]
    // of the AST builder.
    setupStateForInlining(function, compiledArguments,
        instanceType: instanceType);
  }

  void leaveInlinedMethod() {
    HInstruction result = localsHandler.readLocal(returnLocal);
    AstInliningState state = inliningStack.removeLast();
    restoreState(state);
    stack.add(result);
  }

  void doInline(ResolvedAst resolvedAst) {
    visitInlinedFunction(resolvedAst);
  }

  void emitReturn(HInstruction value, ast.Node node) {
    if (inliningStack.isEmpty) {
      closeAndGotoExit(
          new HReturn(value, sourceInformationBuilder.buildReturn(node)));
    } else {
      localsHandler.updateLocal(returnLocal, value);
    }
  }

  @override
  void handleTypeLiteralConstantCompounds(
      ast.SendSet node, ConstantExpression constant, CompoundRhs rhs, _) {
    handleTypeLiteralCompound(node);
  }

  @override
  void handleTypeVariableTypeLiteralCompounds(
      ast.SendSet node, TypeVariableElement typeVariable, CompoundRhs rhs, _) {
    handleTypeLiteralCompound(node);
  }

  void handleTypeLiteralCompound(ast.SendSet node) {
    generateIsDeferredLoadedCheckOfSend(node);
    ast.Identifier selector = node.selector;
    generateThrowNoSuchMethod(node, selector.source,
        argumentNodes: node.arguments);
  }

  @override
  void visitConstantGet(ast.Send node, ConstantExpression constant, _) {
    visitNode(node);
  }

  @override
  void visitConstantInvoke(ast.Send node, ConstantExpression constant,
      ast.NodeList arguments, CallStructure callStreucture, _) {
    visitNode(node);
  }

  @override
  void errorUndefinedBinaryExpression(
      ast.Send node, ast.Node left, ast.Operator operator, ast.Node right, _) {
    visitNode(node);
  }

  @override
  void errorUndefinedUnaryExpression(
      ast.Send node, ast.Operator operator, ast.Node expression, _) {
    visitNode(node);
  }

  @override
  void bulkHandleError(ast.Node node, ErroneousElement error, _) {
    // TODO(johnniwinther): Use an uncatchable error when supported.
    generateRuntimeError(node, error.message);
  }
}

/**
 * Visitor that handles generation of string literals (LiteralString,
 * StringInterpolation), and otherwise delegates to the given visitor for
 * non-literal subexpressions.
 */
class StringBuilderVisitor extends ast.Visitor {
  final SsaAstGraphBuilder builder;
  final ast.Node diagnosticNode;

  /**
   * The string value generated so far.
   */
  HInstruction result = null;

  StringBuilderVisitor(this.builder, this.diagnosticNode);

  void visit(ast.Node node) {
    node.accept(this);
  }

  visitNode(ast.Node node) {
    builder.reporter.internalError(node, 'Unexpected node.');
  }

  void visitExpression(ast.Node node) {
    node.accept(builder);
    HInstruction expression = builder.pop();

    // We want to use HStringify when:
    //   1. The value is known to be a primitive type, because it might get
    //      constant-folded and codegen has some tricks with JavaScript
    //      conversions.
    //   2. The value can be primitive, because the library stringifier has
    //      fast-path code for most primitives.
    if (expression.canBePrimitive(builder.closedWorld)) {
      append(stringify(node, expression));
      return;
    }

    // If the `toString` method is guaranteed to return a string we can call it
    // directly.
    Selector selector = Selectors.toString_;
    TypeMask type = TypeMaskFactory.inferredTypeForSelector(
        selector, expression.instructionType, builder.globalInferenceResults);
    if (type.containsOnlyString(builder.closedWorld)) {
      builder.pushInvokeDynamic(node, selector, expression.instructionType,
          <HInstruction>[expression]);
      append(builder.pop());
      return;
    }

    append(stringify(node, expression));
  }

  void visitStringInterpolation(ast.StringInterpolation node) {
    node.visitChildren(this);
  }

  void visitStringInterpolationPart(ast.StringInterpolationPart node) {
    visit(node.expression);
    visit(node.string);
  }

  void visitStringJuxtaposition(ast.StringJuxtaposition node) {
    node.visitChildren(this);
  }

  void visitNodeList(ast.NodeList node) {
    node.visitChildren(this);
  }

  void append(HInstruction expression) {
    result = (result == null) ? expression : concat(result, expression);
  }

  HInstruction concat(HInstruction left, HInstruction right) {
    HInstruction instruction =
        new HStringConcat(left, right, builder.commonMasks.stringType);
    builder.add(instruction);
    return instruction;
  }

  HInstruction stringify(ast.Node node, HInstruction expression) {
    HInstruction instruction =
        new HStringify(expression, builder.commonMasks.stringType)
          ..sourceInformation = expression.sourceInformation;
    builder.add(instruction);
    return instruction;
  }
}

/**
 * This class visits the method that is a candidate for inlining and
 * finds whether it is too difficult to inline.
 */
// TODO(karlklose): refactor to make it possible to distinguish between
// implementation restrictions (for example, we *can't* inline multiple returns)
// and heuristics (we *shouldn't* inline large functions).
class InlineWeeder extends ast.Visitor {
  // Invariant: *INSIDE_LOOP* > *OUTSIDE_LOOP*
  static const INLINING_NODES_OUTSIDE_LOOP = 18;
  static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 3;
  static const INLINING_NODES_INSIDE_LOOP = 42;
  static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4;

  bool seenReturn = false;
  String tooDifficultReason;
  int nodeCount = 0;
  final int maxInliningNodes; // `null` for unbounded.
  final bool allowLoops;
  final bool enableUserAssertions;
  final TreeElements elements;

  InlineWeeder._(this.elements, this.maxInliningNodes, this.allowLoops,
      this.enableUserAssertions);

  bool get tooDifficult => tooDifficultReason != null;

  static bool canBeInlined(ResolvedAst resolvedAst, int maxInliningNodes,
      {bool allowLoops: false, bool enableUserAssertions: null}) {
    return cannotBeInlinedReason(resolvedAst, maxInliningNodes,
            allowLoops: allowLoops,
            enableUserAssertions: enableUserAssertions) ==
        null;
  }

  static String cannotBeInlinedReason(
      ResolvedAst resolvedAst, int maxInliningNodes,
      {bool allowLoops: false, bool enableUserAssertions: null}) {
    assert(enableUserAssertions is bool); // Ensure we passed it.
    if (resolvedAst.elements.containsTryStatement) return 'try';

    InlineWeeder weeder = new InlineWeeder._(resolvedAst.elements,
        maxInliningNodes, allowLoops, enableUserAssertions);
    ast.FunctionExpression functionExpression = resolvedAst.node;

    weeder.visit(functionExpression.initializers);
    weeder.visit(functionExpression.body);
    weeder.visit(functionExpression.asyncModifier);
    return weeder.tooDifficultReason;
  }

  bool registerNode() {
    if (maxInliningNodes == null) return true;
    if (nodeCount++ > maxInliningNodes) {
      tooDifficultReason = 'too many nodes';
      return false;
    } else {
      return true;
    }
  }

  void visit(ast.Node node) {
    if (node != null) node.accept(this);
  }

  void visitNode(ast.Node node) {
    if (!registerNode()) return;
    if (seenReturn) {
      tooDifficultReason = 'code after return';
    } else {
      node.visitChildren(this);
    }
  }

  @override
  void visitAssert(ast.Assert node) {
    if (enableUserAssertions) {
      visitNode(node);
    }
  }

  @override
  void visitAsyncModifier(ast.AsyncModifier node) {
    if (node.isYielding || node.isAsynchronous) {
      tooDifficultReason = 'async/await';
    }
  }

  void visitFunctionExpression(ast.Node node) {
    if (!registerNode()) return;
    tooDifficultReason = 'closure';
  }

  void visitFunctionDeclaration(ast.Node node) {
    if (!registerNode()) return;
    tooDifficultReason = 'closure';
  }

  void visitSend(ast.Send node) {
    // TODO(sra): Investigate following, and possibly count occurrences, since
    // repeated references might cause a temporary to be assigned.
    //
    //     Element element = elements[node];
    //     if (element != null && element.isParameter) {
    //       // Don't count as additional node, since it's likely that passing
    //       // the argument would cost us as much space as we inline.
    //       return;
    //     }
    if (!registerNode()) return;
    node.visitChildren(this);
  }

  visitLoop(ast.Node node) {
    // It's actually not difficult to inline a method with a loop, but
    // our measurements show that it's currently better to not inline a
    // method that contains a loop.
    if (!allowLoops) {
      tooDifficultReason = 'loop';
    }
  }

  void visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
    if (!registerNode()) return;
    tooDifficultReason = 'redirecting factory';
  }

  void visitConditional(ast.Conditional node) {
    // Heuristic: In "parameter ? A : B" there is a high probability that
    // parameter is a constant. Assuming the parameter is constant, we can
    // compute a count that is bounded by the largest arm rather than the sum of
    // both arms.
    visit(node.condition);
    if (tooDifficult) return;
    int commonPrefixCount = nodeCount;

    visit(node.thenExpression);
    if (tooDifficult) return;
    int thenCount = nodeCount - commonPrefixCount;

    nodeCount = commonPrefixCount;
    visit(node.elseExpression);
    if (tooDifficult) return;
    int elseCount = nodeCount - commonPrefixCount;

    nodeCount = commonPrefixCount + thenCount + elseCount;
    if (node.condition.asSend() != null &&
        elements[node.condition]?.isParameter == true) {
      nodeCount =
          commonPrefixCount + (thenCount > elseCount ? thenCount : elseCount);
    }
    // This is last so that [tooDifficult] is always updated.
    if (!registerNode()) return;
  }

  void visitRethrow(ast.Rethrow node) {
    if (!registerNode()) return;
    tooDifficultReason = 'rethrow';
  }

  void visitReturn(ast.Return node) {
    if (!registerNode()) return;
    if (seenReturn || identical(node.beginToken.stringValue, 'native')) {
      tooDifficultReason = 'code after return';
      return;
    }
    node.visitChildren(this);
    seenReturn = true;
  }

  void visitThrow(ast.Throw node) {
    if (!registerNode()) return;
    // For now, we don't want to handle throw after a return even if
    // it is in an "if".
    if (seenReturn) {
      tooDifficultReason = 'code after return';
    } else {
      node.visitChildren(this);
    }
  }
}

abstract class InliningState {
  /**
   * Invariant: [function] must be an implementation element.
   */
  final MethodElement function;

  InliningState(this.function) {
    assert(function.isImplementation);
  }
}

class AstInliningState extends InliningState {
  final Local oldReturnLocal;
  final ResolutionDartType oldReturnType;
  final ResolvedAst oldResolvedAst;
  final List<HInstruction> oldStack;
  final LocalsHandler oldLocalsHandler;
  final bool inTryStatement;
  final bool allFunctionsCalledOnce;
  final GlobalTypeInferenceElementResult oldElementInferenceResults;

  AstInliningState(
      MethodElement function,
      this.oldReturnLocal,
      this.oldReturnType,
      this.oldResolvedAst,
      this.oldStack,
      this.oldLocalsHandler,
      this.inTryStatement,
      this.allFunctionsCalledOnce,
      this.oldElementInferenceResults)
      : super(function);
}

class AstTypeBuilder extends TypeBuilder {
  AstTypeBuilder(GraphBuilder builder) : super(builder);

  ClassTypeVariableAccess computeTypeVariableAccess(MemberEntity member) {
    bool isClosure = member.enclosingClass.isClosure;
    if (isClosure) {
      ClosureClassElement closureClass = member.enclosingClass;
      LocalFunctionElement localFunction = closureClass.methodElement;
      member = localFunction.memberContext;
    }
    bool isInConstructorContext =
        member.isConstructor || member is ConstructorBodyEntity;
    if (isClosure) {
      if ((member is ConstructorEntity && member.isFactoryConstructor) ||
          (isInConstructorContext)) {
        // The type variable is used from a closure in a factory constructor.
        // The value of the type argument is stored as a local on the closure
        // itself.
        return ClassTypeVariableAccess.parameter;
      } else if (member.isFunction ||
          member.isGetter ||
          member.isSetter ||
          isInConstructorContext) {
        // The type variable is stored on the "enclosing object" and needs to be
        // accessed using the this-reference in the closure.
        return ClassTypeVariableAccess.property;
      } else {
        assert(member.isField);
        // The type variable is stored in a parameter of the method.
        return ClassTypeVariableAccess.parameter;
      }
    } else if (isInConstructorContext) {
      // The type variable is stored in a parameter of the method.
      return ClassTypeVariableAccess.parameter;
    } else if (member.isInstanceMember) {
      if (member.isField) {
        // The type variable is stored in a parameter or on `this` depending
        // on the context.
        return ClassTypeVariableAccess.instanceField;
      } else {
        // The type variable is stored on the object.
        return ClassTypeVariableAccess.property;
      }
    } else {
      return ClassTypeVariableAccess.none;
    }
  }

  /// In checked mode, generate type tests for the parameters of the inlined
  /// function.
  void potentiallyCheckInlinedParameterTypes(covariant MethodElement function) {
    if (!checkOrTrustTypes) return;

    FunctionSignature signature = function.functionSignature;
    signature.forEachParameter((_parameter) {
      ParameterElement parameter = _parameter;
      HInstruction argument = builder.localsHandler.readLocal(parameter);
      potentiallyCheckOrTrustType(argument, parameter.type);
    });
  }
}
