// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:js_runtime/shared/embedded_names.dart';
import 'package:kernel/ast.dart' as ir;

import '../closure.dart';
import '../common.dart';
import '../common/codegen.dart' show CodegenRegistry;
import '../common/names.dart';
import '../common_elements.dart';
import '../constants/constant_system.dart' as constant_system;
import '../constants/values.dart';
import '../deferred_load/output_unit.dart';
import '../dump_info.dart';
import '../elements/entities.dart';
import '../elements/jumps.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../inferrer/abstract_value_domain.dart';
import '../inferrer/types.dart';
import '../io/source_information.dart';
import '../ir/static_type.dart';
import '../ir/static_type_provider.dart';
import '../ir/util.dart';
import '../js/js.dart' as js;
import '../js_backend/backend.dart' show FunctionInlineCache;
import '../js_backend/field_analysis.dart'
    show FieldAnalysisData, JFieldAnalysis;
import '../js_backend/interceptor_data.dart';
import '../js_backend/inferred_data.dart';
import '../js_backend/namer.dart' show ModularNamer;
import '../js_backend/native_data.dart';
import '../js_backend/runtime_types_resolution.dart';
import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
import '../js_model/locals.dart' show GlobalLocalsMap, JumpVisitor;
import '../js_model/elements.dart' show JGeneratorBody;
import '../js_model/element_map.dart';
import '../js_model/js_strategy.dart';
import '../js_model/type_recipe.dart';
import '../kernel/invocation_mirror_constants.dart';
import '../native/behavior.dart';
import '../native/js.dart';
import '../options.dart';
import '../tracer.dart';
import '../universe/call_structure.dart';
import '../universe/feature.dart';
import '../universe/member_usage.dart' show MemberAccess;
import '../universe/selector.dart';
import '../universe/target_checks.dart' show TargetChecks;
import '../universe/use.dart' show ConstantUse, StaticUse, TypeUse;
import '../world.dart';
import 'jump_handler.dart';
import 'kernel_string_builder.dart';
import 'locals_handler.dart';
import 'loop_handler.dart';
import 'nodes.dart';
import 'ssa_branch_builder.dart';
import 'switch_continue_analysis.dart';
import 'type_builder.dart';

// TODO(johnniwinther): Merge this with [KernelInliningState].
class StackFrame {
  final StackFrame parent;
  final MemberEntity member;
  final AsyncMarker asyncMarker;
  final KernelToLocalsMap localsMap;
  // [ir.Let] and [ir.LocalInitializer] bindings.
  final Map<ir.VariableDeclaration, HInstruction> letBindings;
  final KernelToTypeInferenceMap typeInferenceMap;
  final SourceInformationBuilder sourceInformationBuilder;
  final StaticTypeProvider staticTypeProvider;

  StackFrame(
      this.parent,
      this.member,
      this.asyncMarker,
      this.localsMap,
      this.letBindings,
      this.typeInferenceMap,
      this.sourceInformationBuilder,
      this.staticTypeProvider);
}

class KernelSsaGraphBuilder extends ir.Visitor<void> with ir.VisitorVoidMixin {
  /// Holds the resulting SSA graph.
  final HGraph graph = HGraph();

  /// True if the builder is processing nodes inside a try statement. This is
  /// important for generating control flow out of a try block like returns or
  /// breaks.
  bool _inTryStatement = false;

  /// Used to track the locals while building the graph.
  LocalsHandler localsHandler;

  /// A stack of instructions.
  ///
  /// We build the SSA graph by simulating a stack machine.
  List<HInstruction> stack = [];

  /// The count of nested loops we are currently building.
  ///
  /// The loop nesting is consulted when inlining a function invocation. The
  /// inlining heuristics take this information into account.
  int loopDepth = 0;

  /// A mapping from jump targets to their handlers.
  Map<JumpTarget, JumpHandler> jumpTargets = {};

  final CompilerOptions options;
  final DiagnosticReporter reporter;
  final ModularEmitter _emitter;
  final ModularNamer _namer;
  final MemberEntity targetElement;
  final MemberEntity _initialTargetElement;
  final JClosedWorld closedWorld;
  final CodegenRegistry registry;
  final ClosureData _closureDataLookup;
  final Tracer _tracer;

  /// A stack of [InterfaceType]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<InterfaceType> _currentImplicitInstantiations = [];

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

  HInstruction _rethrowableException;

  final SourceInformationStrategy _sourceInformationStrategy;
  final JsToElementMap _elementMap;
  final GlobalTypeInferenceResults globalInferenceResults;
  LoopHandler _loopHandler;
  TypeBuilder _typeBuilder;

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

  final List<KernelInliningState> _inliningStack = [];
  Local _returnLocal;
  DartType _returnType;

  StackFrame _currentFrame;

  final FunctionInlineCache _inlineCache;
  final InlineDataCache _inlineDataCache;

  final ir.Member _memberContextNode;

  KernelSsaGraphBuilder(
      this.options,
      this.reporter,
      this._initialTargetElement,
      InterfaceType instanceType,
      this._infoReporter,
      this._elementMap,
      this.globalInferenceResults,
      this.closedWorld,
      this.registry,
      this._namer,
      this._emitter,
      this._tracer,
      this._sourceInformationStrategy,
      this._inlineCache,
      this._inlineDataCache)
      : this.targetElement = _effectiveTargetElementFor(_initialTargetElement),
        this._closureDataLookup = closedWorld.closureDataLookup,
        _memberContextNode =
            _elementMap.getMemberContextNode(_initialTargetElement) {
    _enterFrame(targetElement, null);
    this._loopHandler = KernelLoopHandler(this);
    _typeBuilder = KernelTypeBuilder(this, _elementMap);
    graph.element = targetElement;
    graph.sourceInformation =
        _sourceInformationBuilder.buildVariableDeclaration();
    this.localsHandler = LocalsHandler(this, targetElement, targetElement,
        instanceType, _nativeData, _interceptorData);
  }

  KernelToLocalsMap get _localsMap => _currentFrame.localsMap;

  Map<ir.VariableDeclaration, HInstruction> get _letBindings =>
      _currentFrame.letBindings;

  JCommonElements get _commonElements => _elementMap.commonElements;

  JElementEnvironment get _elementEnvironment => _elementMap.elementEnvironment;

  JFieldAnalysis get _fieldAnalysis => closedWorld.fieldAnalysis;

  KernelToTypeInferenceMap get _typeInferenceMap =>
      _currentFrame.typeInferenceMap;

  SourceInformationBuilder get _sourceInformationBuilder =>
      _currentFrame.sourceInformationBuilder;

  AbstractValueDomain get _abstractValueDomain =>
      closedWorld.abstractValueDomain;

  NativeData get _nativeData => closedWorld.nativeData;

  InterceptorData get _interceptorData => closedWorld.interceptorData;

  RuntimeTypesNeed get _rtiNeed => closedWorld.rtiNeed;

  GlobalLocalsMap get _globalLocalsMap =>
      globalInferenceResults.globalLocalsMap;

  InferredData get _inferredData => globalInferenceResults.inferredData;

  DartTypes get dartTypes => closedWorld.dartTypes;

  void push(HInstruction instruction) {
    add(instruction);
    stack.add(instruction);
  }

  HInstruction pop() {
    return stack.removeLast();
  }

  /// Pushes a boolean checking [expression] against null.
  pushCheckNull(HInstruction expression) {
    push(HIdentity(expression, graph.addConstantNull(closedWorld),
        _abstractValueDomain.boolType));
  }

  HBasicBlock _current;

  /// The current block to add instructions to. Might be null, if we are
  /// visiting dead code, but see [_isReachable].
  HBasicBlock get current => _current;

  void set current(c) {
    _isReachable = c != null;
    _current = c;
  }

  /// The most recently opened block. Has the same value as [current] while
  /// the block is open, but unlike [current], it isn't cleared when the
  /// current block is closed.
  HBasicBlock lastOpenedBlock;

  /// Indicates whether the current block is dead (because it has a throw or a
  /// return further up). If this is false, then [current] may be null. If the
  /// block is dead then it may also be aborted, but for simplicity we only
  /// abort on statement boundaries, not in the middle of expressions. See
  /// [isAborted].
  bool _isReachable = true;

  HLocalValue lastAddedParameter;

  Map<Local, HInstruction> parameters = {};
  Set<Local> elidedParameters;

  HBasicBlock addNewBlock() {
    HBasicBlock block = graph.addNewBlock();
    // If adding a new block during building of an expression, it is due to
    // conditional expressions or short-circuit logical operators.
    return block;
  }

  void open(HBasicBlock block) {
    block.open();
    current = block;
    lastOpenedBlock = block;
  }

  HBasicBlock close(HControlFlow end) {
    HBasicBlock result = current;
    current.close(end);
    current = null;
    return result;
  }

  HBasicBlock _closeAndGotoExit(HControlFlow end) {
    HBasicBlock result = current;
    current.close(end);
    current = null;
    result.addSuccessor(graph.exit);
    return result;
  }

  void goto(HBasicBlock from, HBasicBlock to) {
    from.close(HGoto(_abstractValueDomain));
    from.addSuccessor(to);
  }

  bool isAborted() {
    return current == null;
  }

  /// Creates a new block, transitions to it from any current block, and
  /// opens the new block.
  HBasicBlock openNewBlock() {
    HBasicBlock newBlock = addNewBlock();
    if (!isAborted()) goto(current, newBlock);
    open(newBlock);
    return newBlock;
  }

  void add(HInstruction instruction) {
    current.add(instruction);
  }

  HLocalValue addParameter(Entity parameter, AbstractValue type,
      {bool isElided = false}) {
    HLocalValue result = isElided
        ? HLocalValue(parameter, type)
        : HParameterValue(parameter, type);
    if (lastAddedParameter == null) {
      graph.entry.addBefore(graph.entry.first, result);
    } else {
      graph.entry.addAfter(lastAddedParameter, result);
    }
    lastAddedParameter = result;
    return result;
  }

  HSubGraphBlockInformation wrapStatementGraph(SubGraph statements) {
    if (statements == null) return null;
    return HSubGraphBlockInformation(statements);
  }

  HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) {
    if (expression == null) return null;
    return HSubExpressionBlockInformation(expression);
  }

  HLiteralList _buildLiteralList(List<HInstruction> inputs) {
    return HLiteralList(inputs, _abstractValueDomain.growableListType);
  }

  /// Called when control flow is about to change, in which case we need to
  /// specify special successors if we are already in a try/catch/finally block.
  void _handleInTryStatement() {
    if (!_inTryStatement) return;
    HBasicBlock block = close(HExitTry(_abstractValueDomain));
    HBasicBlock newBlock = graph.addNewBlock();
    block.addSuccessor(newBlock);
    open(newBlock);
  }

  /// Helper to implement JS_GET_FLAG.
  ///
  /// The concrete SSA graph builder will extract a flag parameter from the
  /// JS_GET_FLAG call and then push a boolean result onto the stack. This
  /// function provides the boolean value corresponding to the given [flagName].
  /// If [flagName] is not recognized, this function returns `null` and the
  /// concrete SSA builder reports an error.
  bool _getFlagValue(String flagName) {
    switch (flagName) {
      case 'MINIFIED':
        return options.enableMinification;
      case 'MUST_RETAIN_METADATA':
        return false;
      case 'USE_CONTENT_SECURITY_POLICY':
        return options.features.useContentSecurityPolicy.isEnabled;
      case 'VARIANCE':
        return options.enableVariance;
      case 'LEGACY':
        return options.useLegacySubtyping;
      case 'LEGACY_JAVASCRIPT':
        return options.features.legacyJavaScript.isEnabled;
      case 'PRINT_LEGACY_STARS':
        return options.printLegacyStars;
      default:
        return null;
    }
  }

  StaticType _getStaticType(ir.Expression node) {
    // TODO(johnniwinther): Substitute the type by the this type and type
    // arguments of the current frame.
    ir.DartType type = _currentFrame.staticTypeProvider.getStaticType(node);
    return StaticType(
        _elementMap.getDartType(type), computeClassRelationFromType(type));
  }

  StaticType _getStaticForInIteratorType(ir.ForInStatement node) {
    // TODO(johnniwinther): Substitute the type by the this type and type
    // arguments of the current frame.
    ir.DartType type =
        _currentFrame.staticTypeProvider.getForInIteratorType(node);
    return StaticType(
        _elementMap.getDartType(type), computeClassRelationFromType(type));
  }

  static MemberEntity _effectiveTargetElementFor(MemberEntity member) {
    if (member is JGeneratorBody) return member.function;
    return member;
  }

  void _enterFrame(
      MemberEntity member, SourceInformation callSourceInformation) {
    AsyncMarker asyncMarker = AsyncMarker.SYNC;
    ir.FunctionNode function = getFunctionNode(_elementMap, member);
    if (function != null) {
      asyncMarker = getAsyncMarker(function);
    }
    _currentFrame = StackFrame(
        _currentFrame,
        member,
        asyncMarker,
        _globalLocalsMap.getLocalsMap(member),
        {},
        KernelToTypeInferenceMapImpl(member, globalInferenceResults),
        _currentFrame != null
            ? _currentFrame.sourceInformationBuilder
                .forContext(member, callSourceInformation)
            : _sourceInformationStrategy.createBuilderForContext(member),
        _elementMap.getStaticTypeProvider(member));
  }

  void _leaveFrame() {
    _currentFrame = _currentFrame.parent;
  }

  HGraph build() {
    return reporter.withCurrentElement(_localsMap.currentMember, () {
      // TODO(het): no reason to do this here...
      HInstruction.idCounter = 0;
      MemberDefinition definition =
          _elementMap.getMemberDefinition(_initialTargetElement);

      switch (definition.kind) {
        case MemberKind.regular:
        case MemberKind.closureCall:
          ir.Node target = definition.node;
          if (target is ir.Procedure) {
            if (target.isExternal) {
              _buildExternalFunctionNode(targetElement,
                  _ensureDefaultArgumentValues(target, target.function));
            } else {
              _buildFunctionNode(targetElement,
                  _ensureDefaultArgumentValues(target, target.function));
            }
          } else if (target is ir.Field) {
            FieldAnalysisData fieldData =
                closedWorld.fieldAnalysis.getFieldData(targetElement);

            if (fieldData.initialValue != null) {
              registry.registerConstantUse(
                  ConstantUse.init(fieldData.initialValue));
              if (targetElement.isStatic || targetElement.isTopLevel) {
                /// No code is created for this field: All references inline the
                /// constant value.
                return null;
              }
            } else if (fieldData.isLazy) {
              // The generated initializer needs be wrapped in the cyclic-error
              // helper.
              registry.registerStaticUse(StaticUse.staticInvoke(
                  closedWorld.commonElements.cyclicThrowHelper,
                  CallStructure.ONE_ARG));
              registry.registerStaticUse(StaticUse.staticInvoke(
                  closedWorld.commonElements.throwLateFieldADI,
                  CallStructure.ONE_ARG));
            }
            if (targetElement.isInstanceMember) {
              if (fieldData.isEffectivelyFinal ||
                  !closedWorld.annotationsData
                      .getParameterCheckPolicy(targetElement)
                      .isEmitted) {
                // No need for a checked setter.
                return null;
              }
            }
            _buildField(target);
          } else if (target is ir.LocalFunction) {
            _buildFunctionNode(targetElement,
                _ensureDefaultArgumentValues(null, target.function));
          } else {
            throw 'No case implemented to handle target: '
                '$target for $targetElement';
          }
          break;
        case MemberKind.constructor:
          ir.Constructor constructor = definition.node;
          _ensureDefaultArgumentValues(constructor, constructor.function);
          _buildConstructor(targetElement, constructor);
          break;
        case MemberKind.constructorBody:
          ir.Constructor constructor = definition.node;
          _ensureDefaultArgumentValues(constructor, constructor.function);
          _buildConstructorBody(constructor);
          break;
        case MemberKind.closureField:
          // Closure fields have no setter and therefore never require any code.
          return null;
        case MemberKind.signature:
          ir.Node target = definition.node;
          ir.FunctionNode originalClosureNode;
          if (target is ir.Procedure) {
            originalClosureNode = target.function;
          } else if (target is ir.LocalFunction) {
            originalClosureNode = target.function;
          } else {
            failedAt(
                targetElement,
                "Unexpected function signature: "
                "$targetElement inside a non-closure: $target");
          }
          _buildMethodSignatureNewRti(originalClosureNode);
          break;
        case MemberKind.generatorBody:
          _buildGeneratorBody(
              _initialTargetElement, _functionNodeOf(definition.node));
          break;
      }
      assert(graph.isValid(), "Invalid graph for $_initialTargetElement.");

      if (_tracer.isEnabled) {
        MemberEntity member = _initialTargetElement;
        String name = member.name;
        if (member.isInstanceMember ||
            member.isConstructor ||
            member.isStatic) {
          name = "${member.enclosingClass.name}.$name";
          if (definition.kind == MemberKind.constructorBody) {
            name += " (body)";
          }
        }
        _tracer.traceCompilation(name);
        _tracer.traceGraph('builder', graph);
      }

      return graph;
    });
  }

  ir.FunctionNode _functionNodeOf(ir.TreeNode node) {
    if (node is ir.Member) return node.function;
    if (node is ir.LocalFunction) return node.function;
    return null;
  }

  ir.FunctionNode _ensureDefaultArgumentValues(
      ir.Member member, ir.FunctionNode function) {
    // Register all [function]'s default argument values.
    //
    // Default values might be (or contain) functions that are not referenced
    // from anywhere else so we need to ensure these are enqueued.  Stubs and
    // `Function.apply` data are created after the codegen queue is closed, so
    // we force these functions into the queue by registering the constants as
    // used in advance. See language/cyclic_default_values_test.dart for an
    // example.
    //
    // TODO(sra): We could be more precise if stubs and `Function.apply` data
    // were generated by the codegen enqueuer. In practice even in huge programs
    // there are only very small number of constants created here that are not
    // actually used.
    void _registerDefaultValue(ir.VariableDeclaration node) {
      ConstantValue constantValue = _elementMap
          .getConstantValue(member, node.initializer, implicitNull: true);
      assert(
          constantValue != null,
          failedAt(_elementMap.getMethod(function.parent),
              'No constant computed for $node'));
      registry?.registerConstantUse(ConstantUse.init(constantValue));
    }

    function.positionalParameters
        .skip(function.requiredParameterCount)
        .forEach(_registerDefaultValue);
    function.namedParameters.forEach(_registerDefaultValue);
    return function;
  }

  void _buildField(ir.Field node) {
    graph.isLazyInitializer = node.isStatic;
    FieldEntity field = _elementMap.getMember(node);
    _openFunction(field, checks: TargetChecks.none);
    if (node.isInstanceMember &&
        closedWorld.annotationsData.getParameterCheckPolicy(field).isEmitted) {
      HInstruction thisInstruction = localsHandler.readThis(
          sourceInformation: _sourceInformationBuilder.buildGet(node));
      // Use dynamic type because the type computed by the inferrer is
      // narrowed to the type annotation.
      HInstruction parameter =
          HParameterValue(field, _abstractValueDomain.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);
      DartType type = _getDartTypeIfValid(node.type);
      HInstruction value = _typeBuilder.potentiallyCheckOrTrustTypeOfParameter(
          field, parameter, type);
      // TODO(sra): Pass source information to
      // [potentiallyCheckOrTrustTypeOfParameter].
      // TODO(sra): The source information should indiciate the field and
      // possibly its type but not the initializer.
      value.sourceInformation ??= _sourceInformationBuilder.buildSet(node);
      value = _potentiallyAssertNotNull(field, node, value, type);
      if (!_fieldAnalysis.getFieldData(field).isElided) {
        add(HFieldSet(_abstractValueDomain, field, thisInstruction, value));
      }
    } else {
      if (node.initializer != null) {
        node.initializer.accept(this);
        HInstruction fieldValue = pop();
        HInstruction checkInstruction =
            _typeBuilder.potentiallyCheckOrTrustTypeOfAssignment(
                field, fieldValue, _getDartTypeIfValid(node.type));
        stack.add(checkInstruction);
      } else {
        stack.add(graph.addConstantNull(closedWorld));
      }
      HInstruction value = pop();
      _closeAndGotoExit(HReturn(_abstractValueDomain, value,
          _sourceInformationBuilder.buildReturn(node)));
    }
    _closeFunction();
  }

  DartType _getDartTypeIfValid(ir.DartType type) {
    if (type is ir.InvalidType) return null;
    return _elementMap.getDartType(type);
  }

  /// Pops the most recent instruction from the stack and ensures that it is a
  /// non-null bool.
  HInstruction popBoolified() {
    HInstruction value = pop();
    return _typeBuilder.potentiallyCheckOrTrustTypeOfCondition(
        _currentFrame.member, value);
  }

  /// Extend current method parameters with parameters for the class type
  /// parameters.  If the class has type parameters but does not need them, bind
  /// to `dynamic` (represented as `null`) so the bindings are available for
  /// building types up the inheritance chain of generative constructors.
  void _addClassTypeVariablesIfNeeded(MemberEntity member) {
    if (!member.isConstructor && member is! ConstructorBodyEntity) {
      return;
    }
    ClassEntity cls = member.enclosingClass;
    InterfaceType thisType = _elementEnvironment.getThisType(cls);
    if (thisType.typeArguments.isEmpty) {
      return;
    }
    bool needsTypeArguments = _rtiNeed.classNeedsTypeArguments(cls);
    thisType.typeArguments.forEach((DartType _typeVariable) {
      TypeVariableType typeVariableType = _typeVariable;
      HInstruction param;
      if (needsTypeArguments) {
        param = addParameter(
            typeVariableType.element, _abstractValueDomain.nonNullType);
      } else {
        // Unused, so bind to `dynamic`.
        param = graph.addConstantNull(closedWorld);
      }
      Local local = localsHandler.getTypeVariableAsLocal(typeVariableType);
      localsHandler.directLocals[local] = param;
    });
  }

  /// Extend current method parameters with parameters for the function type
  /// variables.
  ///
  /// TODO(johnniwinther): Do we need this?
  /// If the method has type variables but does not need them, bind to `dynamic`
  /// (represented as `null`).
  void _addFunctionTypeVariablesIfNeeded(MemberEntity member) {
    if (member is! FunctionEntity) return;

    FunctionEntity function = member;
    List<TypeVariableType> typeVariables =
        _elementEnvironment.getFunctionTypeVariables(function);
    if (typeVariables.isEmpty) {
      return;
    }
    bool needsTypeArguments = _rtiNeed.methodNeedsTypeArguments(function);
    bool elideTypeParameters = function.parameterStructure.typeParameters == 0;
    for (TypeVariableType typeVariable
        in _elementEnvironment.getFunctionTypeVariables(function)) {
      HInstruction param;
      bool erased = false;
      if (elideTypeParameters) {
        // Add elided type parameters.
        param = _computeTypeArgumentDefaultValue(function, typeVariable);
        erased = true;
      } else if (needsTypeArguments) {
        param = addParameter(
            typeVariable.element, _abstractValueDomain.nonNullType);
      } else {
        // Unused, so bind to bound.
        param = _computeTypeArgumentDefaultValue(function, typeVariable);
        erased = true;
      }
      Local local = localsHandler.getTypeVariableAsLocal(typeVariable);
      localsHandler.directLocals[local] = param;
      if (!erased) {
        _functionTypeParameterLocals.add(local);
      }
    }
  }

  // Locals for function type parameters that can be forwarded, in argument
  // position order.
  final List<Local> _functionTypeParameterLocals = [];

  /// Builds a generative constructor.
  ///
  /// Generative constructors are built in stages, in effect inlining the
  /// initializers and constructor bodies up the inheritance chain.
  ///
  ///  1. Extend method parameters with parameters the class's type parameters.
  ///
  ///  2. Add type checks for value parameters (might need result of (1)).
  ///
  ///  3. Walk inheritance chain to build bindings for type parameters of
  ///     superclasses and mixed-in classes.
  ///
  ///  4. Collect initializer values. Walk up inheritance chain to collect field
  ///     initializers from field declarations, initializing parameters and
  ///     initializer.
  ///
  ///  5. Create reified type information for instance.
  ///
  ///  6. Allocate instance and assign initializers and reified type information
  ///     to fields by calling JavaScript constructor.
  ///
  ///  7. Walk inheritance chain to call or inline constructor bodies.
  ///
  /// All the bindings are put in the constructor's locals handler. The
  /// implication is that a class cannot be extended or mixed-in twice. If we in
  /// future support repeated uses of a mixin class, we should do so by cloning
  /// the mixin class in the Kernel input.
  void _buildConstructor(ConstructorEntity constructor, ir.Constructor node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCreate(node);
    ClassEntity cls = constructor.enclosingClass;

    if (_inliningStack.isEmpty) {
      _openFunction(constructor,
          functionNode: node.function,
          parameterStructure: constructor.parameterStructure,
          checks: TargetChecks.none);
    }

    // [constructorData.fieldValues] accumulates the field initializer values,
    // which may be overwritten by initializer-list initializers.
    ConstructorData constructorData = ConstructorData();
    _buildInitializers(node, constructorData);

    List<HInstruction> constructorArguments = [];
    // Doing this instead of fieldValues.forEach because we haven't defined the
    // order of the arguments here. We can define that with JElements.
    bool isCustomElement = _nativeData.isNativeOrExtendsNative(cls) &&
        !_nativeData.isJsInteropClass(cls);
    InterfaceType thisType = _elementEnvironment.getThisType(cls);
    List<FieldEntity> fields = [];
    _elementEnvironment.forEachInstanceField(cls,
        (ClassEntity enclosingClass, FieldEntity member) {
      HInstruction value = constructorData.fieldValues[member];
      FieldAnalysisData fieldData = _fieldAnalysis.getFieldData(member);
      if (value == null) {
        assert(
            fieldData.isInitializedInAllocator ||
                isCustomElement ||
                reporter.hasReportedError,
            'No initializer value for field ${member}');
      } else {
        if (!fieldData.isElided) {
          fields.add(member);
          DartType type = _elementEnvironment.getFieldType(member);
          type = localsHandler.substInContext(type);
          constructorArguments.add(_typeBuilder
              .potentiallyCheckOrTrustTypeOfAssignment(member, value, type));
        }
      }
    });

    _addImplicitInstantiation(thisType);
    List<DartType> instantiatedTypes =
        List<InterfaceType>.from(_currentImplicitInstantiations);

    HInstruction newObject;
    if (isCustomElement) {
      // 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.
      newObject = HNullCheck(newObject,
          _abstractValueDomain.excludeNull(newObject.instructionType))
        ..sourceInformation = sourceInformation;
      add(newObject);
      for (int i = 0; i < fields.length; i++) {
        add(HFieldSet(_abstractValueDomain, fields[i], newObject,
            constructorArguments[i]));
      }
    } else {
      // Create the runtime type information, if needed.
      bool needsTypeArguments =
          closedWorld.rtiNeed.classNeedsTypeArguments(cls);
      if (needsTypeArguments) {
        InterfaceType thisType = _elementEnvironment.getThisType(cls);
        HInstruction typeArgument = _typeBuilder.analyzeTypeArgumentNewRti(
            thisType, sourceElement,
            sourceInformation: sourceInformation);
        constructorArguments.add(typeArgument);
      }
      newObject = HCreate(cls, constructorArguments,
          _abstractValueDomain.createNonNullExact(cls), sourceInformation,
          instantiatedTypes: instantiatedTypes,
          hasRtiInput: needsTypeArguments);

      add(newObject);
    }
    _removeImplicitInstantiation(thisType);

    HInstruction interceptor;
    // Generate calls to the constructor bodies.
    for (ir.Constructor body in constructorData.constructorChain.reversed) {
      if (_isEmptyStatement(body.function.body)) continue;

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

      // Pass uncaptured arguments first, captured arguments in a box, then type
      // arguments.

      ConstructorEntity inlinedConstructor = _elementMap.getConstructor(body);

      _inlinedFrom(
          inlinedConstructor, _sourceInformationBuilder.buildCall(body, body),
          () {
        ConstructorBodyEntity constructorBody =
            _elementMap.getConstructorBody(body);

        void handleParameter(ir.VariableDeclaration node, {bool isElided}) {
          if (isElided) return;

          Local parameter = _localsMap.getLocalVariable(node);
          // 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));
          }
        }

        // Provide the parameters to the generative constructor body.
        forEachOrderedParameter(_elementMap, constructorBody, handleParameter);

        // If there are locals that escape (i.e. mutated in closures), we pass the
        // box to the constructor.
        CapturedScope scopeData =
            _closureDataLookup.getCapturedScope(constructorBody);
        if (scopeData.requiresContextBox) {
          bodyCallInputs.add(localsHandler.readLocal(scopeData.contextBox));
        }

        // Pass type arguments.
        ClassEntity inlinedConstructorClass = constructorBody.enclosingClass;
        if (closedWorld.rtiNeed
            .classNeedsTypeArguments(inlinedConstructorClass)) {
          InterfaceType thisType =
              _elementEnvironment.getThisType(inlinedConstructorClass);
          for (DartType typeVariable in thisType.typeArguments) {
            DartType result = localsHandler.substInContext(typeVariable);
            HInstruction argument =
                _typeBuilder.analyzeTypeArgument(result, sourceElement);
            bodyCallInputs.add(argument);
          }
        }

        if (!isCustomElement && // TODO(13836): Fix inlining.
            _tryInlineMethod(constructorBody, null, null, bodyCallInputs, null,
                node, sourceInformation)) {
          pop();
        } else {
          _invokeConstructorBody(body, bodyCallInputs,
              _sourceInformationBuilder.buildDeclaration(constructor));
        }
      });
    }

    if (_inliningStack.isEmpty) {
      _closeAndGotoExit(
          HReturn(_abstractValueDomain, newObject, sourceInformation));
      _closeFunction();
    } else {
      localsHandler.updateLocal(_returnLocal, newObject,
          sourceInformation: sourceInformation);
    }
  }

  static bool _isEmptyStatement(ir.Statement body) {
    if (body is ir.EmptyStatement) return true;
    if (body is ir.Block) return body.statements.every(_isEmptyStatement);
    return false;
  }

  void _invokeConstructorBody(ir.Constructor constructor,
      List<HInstruction> inputs, SourceInformation sourceInformation) {
    MemberEntity constructorBody = _elementMap.getConstructorBody(constructor);
    HInvokeConstructorBody invoke = HInvokeConstructorBody(constructorBody,
        inputs, _abstractValueDomain.nonNullType, sourceInformation);
    add(invoke);
  }

  /// Sets context for generating code that is the result of inlining
  /// [inlinedTarget].
  void _inlinedFrom(MemberEntity inlinedTarget,
      SourceInformation callSourceInformation, f()) {
    reporter.withCurrentElement(inlinedTarget, () {
      _enterFrame(inlinedTarget, callSourceInformation);
      var result = f();
      _leaveFrame();
      return result;
    });
  }

  void _ensureTypeVariablesForInitializers(
      ConstructorData constructorData, ClassEntity enclosingClass) {
    if (!constructorData.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 current class. For a redirecting constructor, the type is the
      // current type. [LocalsHandler.substInContext] takes care of both.
      InterfaceType thisType = _elementEnvironment.getThisType(enclosingClass);
      InterfaceType type = localsHandler.substInContext(thisType);
      List<DartType> arguments = type.typeArguments;
      List<DartType> typeVariables = thisType.typeArguments;
      assert(arguments.length == typeVariables.length);
      Iterator<DartType> variables = typeVariables.iterator;
      type.typeArguments.forEach((DartType argument) {
        variables.moveNext();
        TypeVariableType typeVariable = variables.current;
        localsHandler.updateLocal(
            localsHandler.getTypeVariableAsLocal(typeVariable),
            _typeBuilder.analyzeTypeArgument(argument, sourceElement));
      });
    }
  }

  /// Collects the values for field initializers for the direct fields of
  /// [clazz].
  void _collectFieldValues(ir.Class clazz, ConstructorData constructorData) {
    ClassEntity cls = _elementMap.getClass(clazz);
    _elementEnvironment.forEachDirectInstanceField(cls, (FieldEntity field) {
      _ensureTypeVariablesForInitializers(
          constructorData, field.enclosingClass);

      MemberDefinition definition = _elementMap.getMemberDefinition(field);
      ir.Field node;
      switch (definition.kind) {
        case MemberKind.regular:
          node = definition.node;
          break;
        default:
          failedAt(field, "Unexpected member definition $definition.");
      }

      bool ignoreAllocatorAnalysis = false;
      if (_nativeData.isNativeOrExtendsNative(cls)) {
        // @Native classes have 'fields' which are really getters/setter.  Do
        // not try to initialize e.g. 'tagName'.
        if (_nativeData.isNativeClass(cls)) return;
        // Fields that survive this test are fields of custom elements.
        ignoreAllocatorAnalysis = true;
      }

      if (ignoreAllocatorAnalysis ||
          !_fieldAnalysis.getFieldData(field).isInitializedInAllocator) {
        if (node.initializer == null) {
          constructorData.fieldValues[field] =
              graph.addConstantNull(closedWorld);
        } else {
          // Compile the initializer in the context of the field so we know that
          // class type parameters are accessed as values.
          // TODO(sra): It would be sufficient to know the context was a field
          // initializer.
          _inlinedFrom(field,
              _sourceInformationBuilder.buildAssignment(node.initializer), () {
            node.initializer.accept(this);
            constructorData.fieldValues[field] = pop();
          });
        }
      }
    });
  }

  static bool _isRedirectingConstructor(ir.Constructor constructor) =>
      constructor.initializers
          .any((initializer) => initializer is ir.RedirectingInitializer);

  /// Collects field initializers all the way up the inheritance chain.
  void _buildInitializers(
      ir.Constructor constructor, ConstructorData constructorData) {
    assert(
        _elementMap.getConstructor(constructor) == _localsMap.currentMember,
        failedAt(
            _localsMap.currentMember,
            'Expected ${_localsMap.currentMember} '
            'but found ${_elementMap.getConstructor(constructor)}.'));
    constructorData.constructorChain.add(constructor);

    if (!_isRedirectingConstructor(constructor)) {
      // Compute values for field initializers, but only if this is not a
      // redirecting constructor, since the target will compute the fields.
      _collectFieldValues(constructor.enclosingClass, constructorData);
    }
    var foundSuperOrRedirectCall = false;
    for (var initializer in constructor.initializers) {
      if (initializer is ir.FieldInitializer) {
        FieldEntity field = _elementMap.getField(initializer.field);
        if (!_fieldAnalysis.getFieldData(field).isInitializedInAllocator) {
          initializer.value.accept(this);
          constructorData.fieldValues[field] = pop();
        }
      } else if (initializer is ir.SuperInitializer) {
        assert(!foundSuperOrRedirectCall);
        foundSuperOrRedirectCall = true;
        _inlineSuperInitializer(initializer, constructorData, constructor);
      } else if (initializer is ir.RedirectingInitializer) {
        assert(!foundSuperOrRedirectCall);
        foundSuperOrRedirectCall = true;
        _inlineRedirectingInitializer(
            initializer, constructorData, constructor);
      } else if (initializer is ir.LocalInitializer) {
        // LocalInitializer is like a let-expression that is in scope for the
        // rest of the initializers.
        ir.VariableDeclaration variable = initializer.variable;
        assert(variable.isFinal);
        variable.initializer.accept(this);
        HInstruction value = pop();
        // TODO(sra): Apply inferred type information.
        _letBindings[variable] = value;
      } else if (initializer is ir.AssertInitializer) {
        initializer.statement.accept(this);
      } else if (initializer is ir.InvalidInitializer) {
        assert(false, 'ir.InvalidInitializer not handled');
      } else {
        assert(false, 'Unhandled initializer ir.${initializer.runtimeType}');
      }
    }

    if (!foundSuperOrRedirectCall) {
      assert(
          _elementMap.getClass(constructor.enclosingClass) ==
                  _elementMap.commonElements.objectClass ||
              constructor.initializers.any(_ErroneousInitializerVisitor.check),
          'All constructors should have super- or redirecting- initializers,'
          ' except Object()'
          ' ${constructor.initializers}');
    }
  }

  List<HInstruction> _normalizeAndBuildArguments(
      ir.Member member, ir.FunctionNode function, ir.Arguments arguments) {
    List<HInstruction> builtArguments = [];
    var positionalIndex = 0;
    function.positionalParameters.forEach((ir.VariableDeclaration parameter) {
      if (positionalIndex < arguments.positional.length) {
        arguments.positional[positionalIndex++].accept(this);
        builtArguments.add(pop());
      } else {
        builtArguments.add(_defaultValueForParameter(member, parameter));
      }
    });
    // Evaluate named arguments in given order.
    Map<String, HInstruction> namedArguments = _visitNamedArguments(arguments);
    // And add them to `builtArguments` in calling-convention order.
    function.namedParameters.toList()
      ..sort(namedOrdering)
      ..forEach((ir.VariableDeclaration parameter) {
        var argument = namedArguments[parameter.name];
        argument ??= _defaultValueForParameter(member, parameter);
        builtArguments.add(argument);
      });

    return builtArguments;
  }

  /// Inlines the given redirecting [constructor]'s initializers by collecting
  /// its field values and building its constructor initializers. We visit super
  /// constructors all the way up to the [Object] constructor.
  void _inlineRedirectingInitializer(ir.RedirectingInitializer initializer,
      ConstructorData constructorData, ir.Constructor caller) {
    ir.Constructor superOrRedirectConstructor = initializer.target;
    List<HInstruction> arguments = _normalizeAndBuildArguments(
        superOrRedirectConstructor,
        superOrRedirectConstructor.function,
        initializer.arguments);

    // Redirecting initializer already has [localsHandler] bindings for type
    // parameters from the redirecting constructor.

    // For redirecting constructors, the fields will be initialized later by the
    // effective target, so we don't do it here.

    _inlineSuperOrRedirectCommon(initializer, superOrRedirectConstructor,
        arguments, constructorData, caller);
  }

  /// Inlines the given super [constructor]'s initializers by collecting its
  /// field values and building its constructor initializers. We visit super
  /// constructors all the way up to the [Object] constructor.
  void _inlineSuperInitializer(ir.SuperInitializer initializer,
      ConstructorData constructorData, ir.Constructor caller) {
    ir.Constructor target = initializer.target;
    List<HInstruction> arguments = _normalizeAndBuildArguments(
        target, target.function, initializer.arguments);

    ir.Class callerClass = caller.enclosingClass;
    ir.Supertype supertype = callerClass.supertype;

    // The class of the super-constructor may not be the supertype class. In
    // this case, we must go up the class hierarchy until we reach the class
    // containing the super-constructor.
    while (supertype.classNode != target.enclosingClass) {
      // Fields from unnamed mixin application classes (ie Object&Foo) get
      // "collected" with the regular supertype fields, so we must bind type
      // parameters from both the supertype and the supertype's mixin classes
      // before collecting the field values.
      _collectFieldValues(supertype.classNode, constructorData);
      supertype = supertype.classNode.supertype;
    }
    supertype = supertype.classNode.supertype;

    _inlineSuperOrRedirectCommon(
        initializer, target, arguments, constructorData, caller);
  }

  void _inlineSuperOrRedirectCommon(
      ir.Initializer initializer,
      ir.Constructor constructor,
      List<HInstruction> arguments,
      ConstructorData constructorData,
      ir.Constructor caller) {
    var index = 0;

    ConstructorEntity element = _elementMap.getConstructor(constructor);
    MemberEntity oldScopeMember = localsHandler.scopeMember;

    _inlinedFrom(
        element, _sourceInformationBuilder.buildCall(initializer, initializer),
        () {
      void handleParameter(ir.VariableDeclaration node) {
        Local parameter = _localsMap.getLocalVariable(node);
        HInstruction argument = arguments[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);
      }

      constructor.function.positionalParameters.forEach(handleParameter);
      constructor.function.namedParameters.toList()
        ..sort(namedOrdering)
        ..forEach(handleParameter);

      _ensureTypeVariablesForInitializers(
          constructorData, element.enclosingClass);

      // Set the locals handler state as if we were inlining the constructor.
      localsHandler.setupScope(element);
      localsHandler.enterScope(_closureDataLookup.getCapturedScope(element),
          _sourceInformationBuilder.buildDeclaration(element));
      _buildInitializers(constructor, constructorData);
    });
    localsHandler.setupScope(oldScopeMember);
  }

  /// Constructs a special signature function for a closure.
  void _buildMethodSignatureNewRti(ir.FunctionNode originalClosureNode) {
    // The signature function has no corresponding ir.Node, so we just use the
    // targetElement to set up the type environment.
    _openFunction(targetElement, checks: TargetChecks.none);
    FunctionType functionType =
        _elementMap.getFunctionType(originalClosureNode);
    HInstruction rti =
        _typeBuilder.analyzeTypeArgumentNewRti(functionType, sourceElement);
    close(HReturn(_abstractValueDomain, rti,
            _sourceInformationBuilder.buildReturn(originalClosureNode)))
        .addSuccessor(graph.exit);
    _closeFunction();
  }

  /// Builds generative constructor body.
  void _buildConstructorBody(ir.Constructor constructor) {
    FunctionEntity constructorBody =
        _elementMap.getConstructorBody(constructor);
    _openFunction(constructorBody,
        functionNode: constructor.function,
        parameterStructure: constructorBody.parameterStructure,
        checks: TargetChecks.none);
    constructor.function.body.accept(this);
    _closeFunction();
  }

  /// Builds a SSA graph for FunctionNodes, found in FunctionExpressions and
  /// Procedures.
  void _buildFunctionNode(
      FunctionEntity function, ir.FunctionNode functionNode) {
    if (functionNode.asyncMarker != ir.AsyncMarker.Sync) {
      _buildGenerator(function, functionNode);
      return;
    }

    _openFunction(function,
        functionNode: functionNode,
        parameterStructure: function.parameterStructure,
        checks: _checksForFunction(function));

    if (options.experimentUnreachableMethodsThrow) {
      var emptyParameters = parameters.values.where((parameter) =>
          _abstractValueDomain
              .isEmpty(parameter.instructionType)
              .isDefinitelyTrue);
      if (emptyParameters.length > 0) {
        _addComment('${emptyParameters} inferred as [empty]');
        add(HInvokeStatic(_commonElements.assertUnreachableMethod, [],
            _abstractValueDomain.dynamicType, const []));
        _closeFunction();
        return;
      }
    }
    functionNode.body.accept(this);
    _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(HForeignCode(js.js.statementTemplateYielding(js.Comment(text)),
        _abstractValueDomain.dynamicType, [],
        isStatement: true));
  }

  /// Builds a SSA graph for a sync*/async/async* generator.  We generate a
  /// entry function which tail-calls a body function. The entry contains
  /// per-invocation checks and the body, which is later transformed, contains
  /// the re-entrant 'state machine' code.
  void _buildGenerator(FunctionEntity function, ir.FunctionNode functionNode) {
    _openFunction(function,
        functionNode: functionNode,
        parameterStructure: function.parameterStructure,
        checks: _checksForFunction(function));

    // Prepare to tail-call the body.

    // Is 'buildAsyncBody' the best location for the entry?
    var sourceInformation = _sourceInformationBuilder.buildAsyncBody();

    // Forward all the parameters to the body.
    List<HInstruction> inputs = [];
    if (graph.thisInstruction != null) {
      inputs.add(graph.thisInstruction);
    }
    if (graph.explicitReceiverParameter != null) {
      inputs.add(graph.explicitReceiverParameter);
    }
    for (Local local in parameters.keys) {
      if (!elidedParameters.contains(local)) {
        inputs.add(localsHandler.readLocal(local));
      }
    }
    for (Local local in _functionTypeParameterLocals) {
      inputs.add(localsHandler.readLocal(local));
    }

    // Add the type parameter for the generator's element type.
    DartType elementType = _elementEnvironment.getAsyncOrSyncStarElementType(
        function.asyncMarker, _returnType);

    // TODO(sra): [elementType] can contain free type variables that are erased
    // due to no rtiNeed. We will get getter code if these type variables are
    // substituted with an <any> or <erased> type.
    if (elementType.containsFreeTypeVariables) {
      // Type must be computed in the entry function, where the type variables
      // are in scope, and passed to the body function.
      inputs.add(_typeBuilder.analyzeTypeArgumentNewRti(elementType, function));
    } else {
      // Types with no type variables can be emitted as part of the generator,
      // avoiding an extra argument.
      if (_generatedEntryIsEmpty()) {
        // If the entry function is empty (e.g. no argument checks) and the type
        // can be generated in body, 'inline' the body by generating it in
        // place. This works because the subsequent transformation of the code
        // is 'correct' for the empty entry function code.
        graph.needsAsyncRewrite = true;
        graph.asyncElementType = elementType;
        functionNode.body.accept(this);
        _closeFunction();
        return;
      }
    }

    JGeneratorBody body = _elementMap.getGeneratorBody(function);
    push(HInvokeGeneratorBody(
        body,
        inputs,
        _abstractValueDomain.dynamicType, // TODO: better type.
        sourceInformation));

    _closeAndGotoExit(HReturn(_abstractValueDomain, pop(), sourceInformation));

    _closeFunction();
  }

  /// Builds a SSA graph for a sync*/async/async* generator body.
  void _buildGeneratorBody(
      JGeneratorBody function, ir.FunctionNode functionNode) {
    FunctionEntity entry = function.function;
    _openFunction(entry,
        functionNode: functionNode,
        parameterStructure: function.parameterStructure,
        checks: TargetChecks.none);
    graph.needsAsyncRewrite = true;
    if (!function.elementType.containsFreeTypeVariables) {
      // We can generate the element type in place
      graph.asyncElementType = function.elementType;
    }
    functionNode.body.accept(this);
    _closeFunction();
  }

  bool _generatedEntryIsEmpty() {
    HBasicBlock block = current;
    // If `block.id` is not 1 then we generated some control flow.
    if (block.id != 1) return false;
    for (HInstruction node = block.first; node != null; node = node.next) {
      if (node is HGoto) continue;
      if (node is HLoadType) continue; // Orphaned if check is redundant.
      return false;
    }
    return true;
  }

  void _potentiallyAddFunctionParameterTypeChecks(MemberEntity member,
      ir.FunctionNode function, TargetChecks targetChecks) {
    // 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.

    if (targetChecks.checkTypeParameters) {
      _checkTypeVariableBounds(targetElement);
    }

    MemberDefinition definition =
        _elementMap.getMemberDefinition(targetElement);
    bool nodeIsConstructorBody = definition.kind == MemberKind.constructorBody;

    void _handleParameter(ir.VariableDeclaration variable) {
      Local local = _localsMap.getLocalVariable(variable);
      if (nodeIsConstructorBody &&
          _closureDataLookup
              .getCapturedScope(targetElement)
              .isBoxedVariable(_localsMap, local)) {
        // If local is boxed, then `variable` will be a field inside the box
        // passed as the last parameter, so no need to update our locals
        // handler or check types at this point.
        return;
      }
      if (elidedParameters.contains(local)) {
        // Elided parameters are initialized to a default value that is
        // statically checked.
        return;
      }

      HInstruction newParameter = localsHandler.readLocal(local);
      assert(newParameter != null, "No initial instruction for ${local}.");
      DartType type = _getDartTypeIfValid(variable.type);

      if (targetChecks.checkAllParameters ||
          (targetChecks.checkCovariantParameters &&
              (variable.isCovariantByClass ||
                  variable.isCovariantByDeclaration))) {
        newParameter = _typeBuilder.potentiallyCheckOrTrustTypeOfParameter(
            targetElement, newParameter, type);
      } else {
        newParameter = _typeBuilder.trustTypeOfParameter(
            targetElement, newParameter, type);
      }
      // TODO(sra): Hoist out of loop.
      newParameter =
          _potentiallyAssertNotNull(member, variable, newParameter, type);
      localsHandler.updateLocal(local, newParameter);
    }

    function.positionalParameters.forEach(_handleParameter);
    function.namedParameters.toList().forEach(_handleParameter);
  }

  void _checkTypeVariableBounds(FunctionEntity method) {
    if (_rtiNeed.methodNeedsTypeArguments(method) &&
        closedWorld.annotationsData.getParameterCheckPolicy(method).isEmitted) {
      ir.FunctionNode function = getFunctionNode(_elementMap, method);
      for (ir.TypeParameter typeParameter in function.typeParameters) {
        Local local = _localsMap.getLocalTypeVariableEntity(_elementMap
            .getTypeVariableType(
                ir.TypeParameterType(typeParameter, ir.Nullability.nonNullable))
            .element);
        HInstruction newParameter = localsHandler.directLocals[local];
        DartType bound = _getDartTypeIfValid(typeParameter.bound);
        if (!dartTypes.isTopType(bound)) {
          registry.registerTypeUse(TypeUse.typeVariableBoundCheck(bound));
          // TODO(sigmund): method name here is not minified, should it be?
          _checkTypeBound(newParameter, bound, local.name, method.name);
        }
      }
    }
  }

  /// In mixed mode, inserts an assertion of the form `assert(x != null)` for
  /// parameters in opt-in libraries that have a static type that cannot be
  /// nullable under a strong interpretation.
  HInstruction _potentiallyAssertNotNull(MemberEntity member,
      ir.TreeNode context, HInstruction value, DartType type) {
    if (!options.enableNullAssertions) return value;
    if (!_isNonNullableByDefault(context)) return value;
    if (!dartTypes.isNonNullableIfSound(type)) return value;

    // `operator==` is usually augmented to handle a `null`-argument before this
    // test would be inserted.  There are a few exceptions (Object,
    // Interceptor), where the body of the `==` method is designed to handle a
    // `null` argument. In the usual case the null assertion is unnecessary and
    // will be optimized away. In the exception cases a null assertion would be
    // incorrect. Either way we should not do a null-assertion on the parameter
    // of any `operator==` method.
    if (member.name == '==') return value;

    if (options.enableUserAssertions) {
      pushCheckNull(value);
      push(HNot(pop(), _abstractValueDomain.boolType));
      var sourceInformation = _sourceInformationBuilder.buildAssert(context);
      _pushStaticInvocation(
          _commonElements.assertHelper,
          [pop()],
          _typeInferenceMap.getReturnTypeOf(_commonElements.assertHelper),
          const <DartType>[],
          sourceInformation: sourceInformation);
      pop();
      return value;
    } else {
      HInstruction nullCheck = HNullCheck(
          value, _abstractValueDomain.excludeNull(value.instructionType))
        ..sourceInformation = value.sourceInformation;
      add(nullCheck);
      return nullCheck;
    }
  }

  bool _isNonNullableByDefault(ir.TreeNode node) {
    if (node is ir.Library) return node.isNonNullableByDefault;
    return _isNonNullableByDefault(node.parent);
  }

  /// Builds a SSA graph for FunctionNodes of external methods. This produces a
  /// graph for a method with Dart calling conventions that forwards to the
  /// actual external method.
  void _buildExternalFunctionNode(
      FunctionEntity function, ir.FunctionNode functionNode) {
    assert(functionNode.body == null);

    bool isJsInterop = closedWorld.nativeData.isJsInteropMember(function);

    _openFunction(function,
        functionNode: functionNode,
        parameterStructure: function.parameterStructure,
        checks: _checksForFunction(function));

    if (closedWorld.nativeData.isNativeMember(targetElement)) {
      List<HInstruction> inputs = [];
      if (targetElement.isInstanceMember) {
        inputs.add(localsHandler.readThis(
            sourceInformation:
                _sourceInformationBuilder.buildGet(functionNode)));
      }

      void handleParameter(ir.VariableDeclaration param) {
        Local local = _localsMap.getLocalVariable(param);
        // Convert Dart function to JavaScript function.
        HInstruction argument = localsHandler.readLocal(local);
        ir.DartType type = param.type;
        if (!isJsInterop && type is ir.FunctionType) {
          int arity = type.positionalParameters.length;
          _pushStaticInvocation(
              _commonElements.closureConverter,
              [argument, graph.addConstantInt(arity, closedWorld)],
              _abstractValueDomain.dynamicType,
              const <DartType>[],
              sourceInformation: null);
          argument = pop();
        }
        inputs.add(argument);
      }

      for (int position = 0;
          position < function.parameterStructure.positionalParameters;
          position++) {
        handleParameter(functionNode.positionalParameters[position]);
      }
      if (functionNode.namedParameters.isNotEmpty) {
        List<ir.VariableDeclaration> namedParameters = functionNode
            .namedParameters
            // Filter elided parameters.
            .where((p) =>
                function.parameterStructure.namedParameters.contains(p.name))
            .toList();
        // Sort by file offset to visit parameters in declaration order.
        namedParameters.sort(nativeOrdering);
        namedParameters.forEach(handleParameter);
      }

      NativeBehavior nativeBehavior =
          _nativeData.getNativeMethodBehavior(function);
      AbstractValue returnType =
          _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);

      push(HInvokeExternal(targetElement, inputs, returnType, nativeBehavior,
          sourceInformation: null));
      HInstruction value = pop();
      // TODO(johnniwinther): Provide source information.
      if (options.nativeNullAssertions) {
        if (_isNonNullableByDefault(functionNode)) {
          DartType type = _getDartTypeIfValid(functionNode.returnType);
          if (dartTypes.isNonNullableIfSound(type) &&
              nodeIsInWebLibrary(functionNode)) {
            push(HNullCheck(value, _abstractValueDomain.excludeNull(returnType),
                sticky: true));
            value = pop();
          }
        }
      }
      if (targetElement.isSetter) {
        _closeAndGotoExit(HGoto(_abstractValueDomain));
      } else {
        _emitReturn(value, _sourceInformationBuilder.buildReturn(functionNode));
      }
    }

    _closeFunction();
  }

  void _addImplicitInstantiation(DartType type) {
    if (type != null) {
      _currentImplicitInstantiations.add(type);
    }
  }

  void _removeImplicitInstantiation(DartType type) {
    if (type != null) {
      _currentImplicitInstantiations.removeLast();
    }
  }

  TargetChecks _checksForFunction(FunctionEntity function) {
    if (!function.isInstanceMember) {
      // Static methods with no tear-off can be generated with no checks.
      MemberAccess access = closedWorld.getMemberAccess(function);
      if (access != null && access.reads.isEmpty) {
        return TargetChecks.none;
      }
    }
    // TODO(sra): Instance methods can be generated with reduced checks if
    // called only from non-dynamic call-sites.
    return TargetChecks.dynamicChecks;
  }

  void _openFunction(MemberEntity member,
      {ir.FunctionNode functionNode,
      ParameterStructure parameterStructure,
      TargetChecks checks}) {
    assert(checks != null);

    Map<Local, AbstractValue> parameterMap = {};
    List<ir.VariableDeclaration> elidedParameters = [];
    Set<Local> elidedParameterSet = Set();
    if (functionNode != null) {
      assert(parameterStructure != null);

      void handleParameter(ir.VariableDeclaration node,
          {bool isOptional, bool isElided}) {
        Local local = _localsMap.getLocalVariable(node);
        if (isElided) {
          elidedParameters.add(node);
          elidedParameterSet.add(local);
        }
        parameterMap[local] =
            _typeInferenceMap.getInferredTypeOfParameter(local);
      }

      forEachOrderedParameterByFunctionNode(
          functionNode, parameterStructure, handleParameter);

      _returnType = _elementMap.getDartType(functionNode.returnType);
    }

    HBasicBlock block = graph.addNewBlock();
    // Create `graph.entry` as an initially empty block. `graph.entry` is
    // treated specially (holding parameters, local variables and constants)
    // but cannot receive constants before it has been closed. By closing it
    // here, we can use constants in the code that sets up the function.
    open(graph.entry);
    close(HGoto(_abstractValueDomain)).addSuccessor(block);
    open(block);

    localsHandler.startFunction(targetElement, parameterMap, elidedParameterSet,
        _sourceInformationBuilder.buildDeclaration(targetElement),
        isGenerativeConstructorBody: targetElement is ConstructorBodyEntity);

    ir.Member memberContextNode = _elementMap.getMemberContextNode(member);
    for (ir.VariableDeclaration node in elidedParameters) {
      Local local = _localsMap.getLocalVariable(node);
      localsHandler.updateLocal(
          local, _defaultValueForParameter(memberContextNode, node));
    }

    _addClassTypeVariablesIfNeeded(member);
    _addFunctionTypeVariablesIfNeeded(member);

    // If [member] 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. The null check is added before the argument type checks since in
    // strong mode, the parameter type might be non-nullable.
    if (member.name == '==') {
      if (!_commonElements.operatorEqHandlesNullArgument(member)) {
        _handleIf(
            visitCondition: () {
              HParameterValue parameter = parameters.values.first;
              push(HIdentity(parameter, graph.addConstantNull(closedWorld),
                  _abstractValueDomain.boolType));
            },
            visitThen: () {
              _closeAndGotoExit(HReturn(
                  _abstractValueDomain,
                  graph.addConstantBool(false, closedWorld),
                  _sourceInformationBuilder.buildReturn(functionNode)));
            },
            visitElse: null,
            sourceInformation: _sourceInformationBuilder.buildIf(functionNode));
      }
    }

    if (functionNode != null) {
      _potentiallyAddFunctionParameterTypeChecks(member, functionNode, checks);
    }
    _insertCoverageCall(member);
  }

  void _closeFunction() {
    if (!isAborted()) _closeAndGotoExit(HGoto(_abstractValueDomain));
    graph.finalize(_abstractValueDomain);
  }

  @override
  void defaultNode(ir.Node node) {
    throw UnsupportedError("Unhandled node $node (${node.runtimeType})");
  }

  /// Returns the current source element. This is used by the type builder.
  // TODO(efortuna): Update this when we implement inlining.
  // TODO(sra): Re-implement type builder using Kernel types and the
  // `target` for context.
  MemberEntity get sourceElement => _currentFrame.member;

  @override
  void visitCheckLibraryIsLoaded(ir.CheckLibraryIsLoaded checkLoad) {
    ImportEntity import = _elementMap.getImport(checkLoad.import);
    String loadId = closedWorld.outputUnitData.getImportDeferName(
        _elementMap.getSpannable(targetElement, checkLoad), import);
    HInstruction prefixConstant = graph.addConstantString(loadId, closedWorld);
    _pushStaticInvocation(
        _commonElements.checkDeferredIsLoaded,
        [prefixConstant],
        _typeInferenceMap
            .getReturnTypeOf(_commonElements.checkDeferredIsLoaded),
        const <DartType>[],
        sourceInformation: null);
  }

  @override
  void visitLoadLibrary(ir.LoadLibrary loadLibrary) {
    String loadId = closedWorld.outputUnitData.getImportDeferName(
        _elementMap.getSpannable(targetElement, loadLibrary),
        _elementMap.getImport(loadLibrary.import));
    // TODO(efortuna): Source information!
    push(HInvokeStatic(
        _commonElements.loadDeferredLibrary,
        [graph.addConstantString(loadId, closedWorld)],
        _abstractValueDomain.nonNullType,
        const <DartType>[],
        targetCanThrow: false));
  }

  @override
  void visitBlock(ir.Block block) {
    assert(!isAborted());
    // [block] can be unreachable at the beginning of a block if an
    // ir.BlockExpression that is a subexpression of an expression that contains
    // a throwing prior subexpression, e.g. `[throw e, {...[]}]`.
    if (!_isReachable) return;

    for (ir.Statement statement in block.statements) {
      statement.accept(this);
      if (!_isReachable) {
        // The block has been aborted by a return or a throw.
        if (stack.isNotEmpty) {
          reporter.internalError(
              NO_LOCATION_SPANNABLE, 'Non-empty instruction stack.');
        }
        return;
      }
    }
    assert(!current.isClosed());
    if (stack.isNotEmpty) {
      reporter.internalError(
          NO_LOCATION_SPANNABLE, 'Non-empty instruction stack');
    }
  }

  @override
  void visitEmptyStatement(ir.EmptyStatement node) {
    // Empty statement adds no instructions to current block.
  }

  @override
  void visitExpressionStatement(ir.ExpressionStatement node) {
    if (!_isReachable) return;
    ir.Expression expression = node.expression;
    if (expression is ir.Throw && _inliningStack.isEmpty) {
      _visitThrowExpression(expression.expression);
      _handleInTryStatement();
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildThrow(node.expression);
      _closeAndGotoExit(HThrow(_abstractValueDomain, pop(), sourceInformation));
    } else {
      expression.accept(this);
      pop();
    }
  }

  @override
  void visitConstantExpression(ir.ConstantExpression node) {
    ConstantValue value =
        _elementMap.getConstantValue(_memberContextNode, node);
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildGet(node);
    if (!closedWorld.outputUnitData
        .hasOnlyNonDeferredImportPathsToConstant(targetElement, value)) {
      OutputUnit outputUnit =
          closedWorld.outputUnitData.outputUnitForConstant(value);
      ConstantValue deferredConstant =
          DeferredGlobalConstantValue(value, outputUnit);
      registry.registerConstantUse(ConstantUse.deferred(deferredConstant));
      stack.add(graph.addDeferredConstant(
          deferredConstant, sourceInformation, closedWorld));
    } else {
      stack.add(graph.addConstant(value, closedWorld,
          sourceInformation: sourceInformation));
    }
  }

  @override
  void visitReturnStatement(ir.ReturnStatement node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildReturn(node);
    HInstruction value = null;
    if (node.expression != null) {
      node.expression.accept(this);
      value = pop();
      if (_currentFrame.asyncMarker == AsyncMarker.ASYNC) {
        // TODO(johnniwinther): Is this special-casing of async still needed
        // or should we use the general check below?
        /*if (options.enableTypeAssertions &&
            !isValidAsyncReturnType(_returnType)) {
          generateTypeError(
              "Async function returned a Future,"
              " was declared to return a ${_returnType}.",
              sourceInformation);
          pop();
          return;
        }*/
      } else {
        value = _typeBuilder.potentiallyCheckOrTrustTypeOfAssignment(
            _currentFrame.member, value, _returnType);
      }
    }
    _handleInTryStatement();
    if (_inliningStack.isEmpty && targetElement.isSetter) {
      if (node.parent is ir.FunctionNode) {
        // An arrow function definition of a setter has a ReturnStatemnt as a
        // body, e.g. "set foo(x) => this._x = x;". There is no way to access
        // the returned value, so don't emit a return.
        return;
      }
    }
    _emitReturn(value, sourceInformation);
  }

  @override
  void visitForStatement(ir.ForStatement node) {
    assert(_isReachable);
    assert(node.body != null);
    void buildInitializer() {
      for (ir.VariableDeclaration declaration in node.variables) {
        declaration.accept(this);
      }
    }

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

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

    void buildBody() {
      node.body.accept(this);
    }

    JumpTarget jumpTarget = _localsMap.getJumpTargetForFor(node);
    _loopHandler.handleLoop(
        node,
        _closureDataLookup.getCapturedLoopScope(node),
        jumpTarget,
        buildInitializer,
        buildCondition,
        buildUpdate,
        buildBody,
        _sourceInformationBuilder.buildLoop(node));
  }

  @override
  void visitForInStatement(ir.ForInStatement node) {
    if (node.isAsync) {
      _buildAsyncForIn(node);
    } else if (_typeInferenceMap.isJsIndexableIterator(
        node, _abstractValueDomain)) {
      // If the expression being iterated over is a JS indexable type, we can
      // generate an optimized version of for-in that uses indexing.
      _buildForInIndexable(node);
    } else {
      _buildForInIterator(node);
    }
  }

  /// Builds the graph for a for-in node with an indexable expression.
  ///
  /// In this case we build:
  ///
  ///    int end = a.length;
  ///    for (int i = 0;
  ///         i < a.length;
  ///         checkConcurrentModificationError(a.length == end, a), ++i) {
  ///      <declaredIdentifier> = a[i];
  ///      <body>
  ///    }
  void _buildForInIndexable(ir.ForInStatement node) {
    SyntheticLocal indexVariable = localsHandler.createLocal('_i');

    // 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(SourceInformation sourceInformation) {
      HGetLength result = HGetLength(
          array, _abstractValueDomain.positiveIntType,
          isAssignable: !isFixed)
        ..sourceInformation = sourceInformation;
      add(result);
      return result;
    }

    void buildConcurrentModificationErrorCheck() {
      if (originalLength == null) return;
      // The static call checkConcurrentModificationError() is expanded in
      // codegen to:
      //
      //     array.length == _end || throwConcurrentModificationError(array)
      //
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildForInMoveNext(node);
      HInstruction length = buildGetLength(sourceInformation);
      push(HIdentity(length, originalLength, _abstractValueDomain.boolType)
        ..sourceInformation = sourceInformation);
      _pushStaticInvocation(
          _commonElements.checkConcurrentModificationError,
          [pop(), array],
          _typeInferenceMap.getReturnTypeOf(
              _commonElements.checkConcurrentModificationError),
          const <DartType>[],
          sourceInformation: sourceInformation);
      pop();
    }

    void buildInitializer() {
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildForInIterator(node);

      node.iterable.accept(this);
      array = pop();
      isFixed = _abstractValueDomain
          .isFixedLengthJsIndexable(array.instructionType)
          .isDefinitelyTrue;
      localsHandler.updateLocal(
          indexVariable, graph.addConstantInt(0, closedWorld),
          sourceInformation: sourceInformation);
      originalLength = buildGetLength(sourceInformation);
    }

    HInstruction buildCondition() {
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildForInMoveNext(node);
      HInstruction index = localsHandler.readLocal(indexVariable,
          sourceInformation: sourceInformation);
      HInstruction length = buildGetLength(sourceInformation);
      HInstruction compare = HLess(index, length, _abstractValueDomain.boolType)
        ..sourceInformation = sourceInformation;
      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.
      AbstractValue type = _typeInferenceMap.inferredIndexType(node);

      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildForInCurrent(node);
      HInstruction index = localsHandler.readLocal(indexVariable,
          sourceInformation: sourceInformation);
      // No bound check is necessary on indexer as it is immediately guarded by
      // the condition.
      HInstruction value = HIndex(array, index, type)
        ..sourceInformation = sourceInformation;
      add(value);

      Local loopVariableLocal = _localsMap.getLocalVariable(node.variable);
      localsHandler.updateLocal(loopVariableLocal, value,
          sourceInformation: sourceInformation);
      // Hint to name loop value after name of loop variable.
      if (loopVariableLocal is! SyntheticLocal) {
        value.sourceElement ??= loopVariableLocal;
      }

      node.body.accept(this);
    }

    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.
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildForInSet(node);
      HInstruction index = localsHandler.readLocal(indexVariable,
          sourceInformation: sourceInformation);
      HInstruction one = graph.addConstantInt(1, closedWorld);
      HInstruction addInstruction =
          HAdd(index, one, _abstractValueDomain.positiveIntType)
            ..sourceInformation = sourceInformation;
      add(addInstruction);
      localsHandler.updateLocal(indexVariable, addInstruction,
          sourceInformation: sourceInformation);
    }

    _loopHandler.handleLoop(
        node,
        _closureDataLookup.getCapturedLoopScope(node),
        _localsMap.getJumpTargetForForIn(node),
        buildInitializer,
        buildCondition,
        buildUpdate,
        buildBody,
        _sourceInformationBuilder.buildLoop(node));
  }

  void _buildForInIterator(ir.ForInStatement node) {
    // Generate a structure equivalent to:
    //   Iterator<E> $iter = <iterable>.iterator;
    //   while ($iter.moveNext()) {
    //     <variable> = $iter.current;
    //     <body>
    //   }

    // The iterator is shared between initializer, condition and body.
    HInstruction iterator;
    StaticType iteratorType = _getStaticForInIteratorType(node);

    void buildInitializer() {
      AbstractValue receiverType = _typeInferenceMap.typeOfIterator(node);
      node.iterable.accept(this);
      HInstruction receiver = pop();
      _pushDynamicInvocation(
          node,
          _getStaticType(node.iterable),
          receiverType,
          Selectors.iterator,
          [receiver],
          const <DartType>[],
          _sourceInformationBuilder.buildForInIterator(node));
      iterator = pop();
    }

    HInstruction buildCondition() {
      AbstractValue receiverType =
          _typeInferenceMap.typeOfIteratorMoveNext(node);
      _pushDynamicInvocation(
          node,
          iteratorType,
          receiverType,
          Selectors.moveNext,
          [iterator],
          const <DartType>[],
          _sourceInformationBuilder.buildForInMoveNext(node));
      return popBoolified();
    }

    void buildBody() {
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildForInCurrent(node);
      AbstractValue receiverType =
          _typeInferenceMap.typeOfIteratorCurrent(node);
      _pushDynamicInvocation(node, iteratorType, receiverType,
          Selectors.current, [iterator], const <DartType>[], sourceInformation);

      Local loopVariableLocal = _localsMap.getLocalVariable(node.variable);
      HInstruction value = _typeBuilder.potentiallyCheckOrTrustTypeOfAssignment(
          _currentFrame.member, pop(), _getDartTypeIfValid(node.variable.type));
      localsHandler.updateLocal(loopVariableLocal, value,
          sourceInformation: sourceInformation);
      // Hint to name loop value after name of loop variable.
      if (loopVariableLocal is! SyntheticLocal) {
        value.sourceElement ??= loopVariableLocal;
      }
      node.body.accept(this);
    }

    _loopHandler.handleLoop(
        node,
        _closureDataLookup.getCapturedLoopScope(node),
        _localsMap.getJumpTargetForForIn(node),
        buildInitializer,
        buildCondition,
        () {},
        buildBody,
        _sourceInformationBuilder.buildLoop(node));
  }

  void _buildAsyncForIn(ir.ForInStatement node) {
    // The async-for is implemented with a StreamIterator.
    HInstruction streamIterator;

    node.iterable.accept(this);

    List<HInstruction> arguments = [pop()];
    ClassEntity cls = _commonElements.streamIterator;
    DartType typeArg = _elementMap.getDartType(node.variable.type);
    InterfaceType instanceType =
        localsHandler.substInContext(dartTypes.interfaceType(cls, [typeArg]));
    // TODO(johnniwinther): This should be the exact type.
    StaticType staticInstanceType =
        StaticType(instanceType, ClassRelation.subtype);
    _addImplicitInstantiation(instanceType);
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildForInIterator(node);
    // TODO(johnniwinther): Pass type arguments to constructors like calling
    // a generic method.
    if (_rtiNeed.classNeedsTypeArguments(cls)) {
      _addTypeArguments(arguments, [typeArg], sourceInformation);
    }
    ConstructorEntity constructor = _commonElements.streamIteratorConstructor;
    _pushStaticInvocation(constructor, arguments,
        _typeInferenceMap.getReturnTypeOf(constructor), const <DartType>[],
        instanceType: instanceType, sourceInformation: sourceInformation);

    streamIterator = pop();

    void buildInitializer() {}

    HInstruction buildCondition() {
      AbstractValue receiverType =
          _typeInferenceMap.typeOfIteratorMoveNext(node);
      _pushDynamicInvocation(
          node,
          staticInstanceType,
          receiverType,
          Selectors.moveNext,
          [streamIterator],
          const <DartType>[],
          _sourceInformationBuilder.buildForInMoveNext(node));
      HInstruction future = pop();
      push(HAwait(future, _abstractValueDomain.dynamicType));
      return popBoolified();
    }

    void buildBody() {
      AbstractValue receiverType =
          _typeInferenceMap.typeOfIteratorCurrent(node);
      _pushDynamicInvocation(
          node,
          staticInstanceType,
          receiverType,
          Selectors.current,
          [streamIterator],
          const <DartType>[],
          _sourceInformationBuilder.buildForInIterator(node));
      localsHandler.updateLocal(
          _localsMap.getLocalVariable(node.variable), pop());
      node.body.accept(this);
    }

    void buildUpdate() {}

    // Creates a synthetic try/finally block in case anything async goes amiss.
    TryCatchFinallyBuilder tryBuilder =
        TryCatchFinallyBuilder(this, _sourceInformationBuilder.buildLoop(node));
    // Build fake try body:
    _loopHandler.handleLoop(
        node,
        _closureDataLookup.getCapturedLoopScope(node),
        _localsMap.getJumpTargetForForIn(node),
        buildInitializer,
        buildCondition,
        buildUpdate,
        buildBody,
        _sourceInformationBuilder.buildLoop(node));

    void finalizerFunction() {
      _pushDynamicInvocation(
          node,
          staticInstanceType,
          null,
          Selectors.cancel,
          [streamIterator],
          const <DartType>[],
          _sourceInformationBuilder
              // ignore:deprecated_member_use_from_same_package
              .buildGeneric(node));
      add(HAwait(pop(), _abstractValueDomain.dynamicType));
    }

    tryBuilder
      ..closeTryBody()
      ..buildFinallyBlock(finalizerFunction)
      ..cleanUp();
  }

  HInstruction _callSetRuntimeTypeInfo(HInstruction typeInfo,
      HInstruction newObject, SourceInformation sourceInformation) {
    // Set the runtime type information on the object.
    FunctionEntity typeInfoSetterFn = _commonElements.setArrayType;
    // TODO(efortuna): Insert source information in this static invocation.
    _pushStaticInvocation(typeInfoSetterFn, [newObject, typeInfo],
        _abstractValueDomain.dynamicType, const <DartType>[],
        sourceInformation: sourceInformation);

    // The new object will now be referenced through the
    // `setArrayType` 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();
  }

  @override
  void visitWhileStatement(ir.WhileStatement node) {
    assert(_isReachable);
    HInstruction buildCondition() {
      node.condition.accept(this);
      return popBoolified();
    }

    _loopHandler.handleLoop(
        node,
        _closureDataLookup.getCapturedLoopScope(node),
        _localsMap.getJumpTargetForWhile(node),
        () {},
        buildCondition,
        () {}, () {
      node.body.accept(this);
    }, _sourceInformationBuilder.buildLoop(node));
  }

  @override
  void visitDoStatement(ir.DoStatement node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildLoop(node);
    // TODO(efortuna): I think this can be rewritten using
    // LoopHandler.handleLoop with some tricks about when the "update" happens.
    LocalsHandler savedLocals = LocalsHandler.from(localsHandler);
    CapturedLoopScope loopClosureInfo =
        _closureDataLookup.getCapturedLoopScope(node);
    localsHandler.startLoop(loopClosureInfo, sourceInformation);
    JumpTarget target = _localsMap.getJumpTargetForDo(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);
    node.body.accept(this);

    // 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(HGoto(_abstractValueDomain));
    } 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 = SubGraph(bodyEntryBlock, bodyExitBlock);
        List<LabelDefinition> labels = jumpHandler.labels;
        HSubGraphBlockInformation bodyInfo =
            HSubGraphBlockInformation(bodyGraph);
        HLabeledBlockInformation info;
        if (!labels.isEmpty) {
          info = HLabeledBlockInformation(bodyInfo, labels, isContinue: true);
        } else {
          info = HLabeledBlockInformation.implicit(bodyInfo, target,
              isContinue: true);
        }
        bodyEntryBlock.setBlockFlow(info, conditionBlock);
      }
      open(conditionBlock);

      node.condition.accept(this);
      assert(!isAborted());
      HInstruction conditionInstruction = popBoolified();
      HBasicBlock conditionEndBlock = close(HLoopBranch(_abstractValueDomain,
          conditionInstruction, HLoopBranch.DO_WHILE_LOOP));

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

      conditionExpression = SubExpression(conditionBlock, conditionEndBlock);

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

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

      loopEntryBlock.postProcessLoopHeader();
      SubGraph bodyGraph = SubGraph(loopEntryBlock, bodyExitBlock);
      HLoopBlockInformation loopBlockInfo = 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 = SubGraph(bodyEntryBlock, bodyExitBlock);
        JumpTarget target = _localsMap.getJumpTargetForDo(node);
        LabelDefinition label = target.addLabel('loop', isBreakTarget: true);
        HLabeledBlockInformation info = HLabeledBlockInformation(
            HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]);
        loopEntryBlock.setBlockFlow(info, current);
        jumpHandler.forEachBreak((HBreak breakInstruction, _) {
          HBasicBlock block = breakInstruction.block;
          block.addAtExit(
              HBreak.toLabel(_abstractValueDomain, label, sourceInformation));
          block.remove(breakInstruction);
        });
      }
    }
    jumpHandler.close();
  }

  @override
  void visitIfStatement(ir.IfStatement node) {
    _handleIf(
        visitCondition: () => node.condition.accept(this),
        visitThen: () => node.then.accept(this),
        visitElse: () => node.otherwise?.accept(this),
        sourceInformation: _sourceInformationBuilder.buildIf(node));
  }

  void _handleIf(
      {ir.Node node,
      void visitCondition(),
      void visitThen(),
      void visitElse(),
      SourceInformation sourceInformation}) {
    SsaBranchBuilder branchBuilder = SsaBranchBuilder(this,
        node == null ? null : _elementMap.getSpannable(targetElement, node));
    branchBuilder.handleIf(visitCondition, visitThen, visitElse,
        sourceInformation: sourceInformation);
  }

  @override
  void visitAsExpression(ir.AsExpression node) {
    ir.Expression operand = node.operand;
    operand.accept(this);

    StaticType operandType = _getStaticType(operand);
    DartType type = _elementMap.getDartType(node.type);
    if (!node.isCovarianceCheck &&
        _elementMap.types.isSubtype(operandType.type, type)) {
      // Skip unneeded casts.
      return;
    }

    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildAs(node);
    HInstruction expressionInstruction = pop();

    if (node.type is ir.InvalidType) {
      _generateTypeError('invalid type', sourceInformation);
      return;
    }

    CheckPolicy policy;
    if (node.isTypeError) {
      policy = closedWorld.annotationsData
          .getImplicitDowncastCheckPolicy(_currentFrame.member);
    } else {
      policy = closedWorld.annotationsData
          .getExplicitCastCheckPolicy(_currentFrame.member);
    }

    if (policy.isEmitted) {
      HInstruction converted = _typeBuilder.buildAsCheck(
          expressionInstruction, localsHandler.substInContext(type),
          isTypeError: node.isTypeError, sourceInformation: sourceInformation);
      if (converted != expressionInstruction) {
        add(converted);
      }
      stack.add(converted);
    } else {
      stack.add(expressionInstruction);
    }
  }

  @override
  void visitNullCheck(ir.NullCheck node) {
    node.operand.accept(this);
    HInstruction expression = pop();
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildUnary(node);
    push(HNullCheck(expression,
        _abstractValueDomain.excludeNull(expression.instructionType))
      ..sourceInformation = sourceInformation);
  }

  void _generateError(FunctionEntity function, String message,
      AbstractValue typeMask, SourceInformation sourceInformation) {
    HInstruction errorMessage = graph.addConstantString(message, closedWorld);
    _pushStaticInvocation(
        function, [errorMessage], typeMask, const <DartType>[],
        sourceInformation: sourceInformation);
  }

  void _generateTypeError(String message, SourceInformation sourceInformation) {
    _generateError(
        _commonElements.throwTypeError,
        message,
        _typeInferenceMap.getReturnTypeOf(_commonElements.throwTypeError),
        sourceInformation);
  }

  void _generateUnsupportedError(
      String message, SourceInformation sourceInformation) {
    _generateError(
        _commonElements.throwUnsupportedError,
        message,
        _typeInferenceMap
            .getReturnTypeOf(_commonElements.throwUnsupportedError),
        sourceInformation);
  }

  @override
  void visitAssertStatement(ir.AssertStatement node) {
    if (!options.enableUserAssertions) return;
    var sourceInformation = _sourceInformationBuilder.buildAssert(node);
    if (node.message == null) {
      node.condition.accept(this);
      _pushStaticInvocation(
          _commonElements.assertHelper,
          [pop()],
          _typeInferenceMap.getReturnTypeOf(_commonElements.assertHelper),
          const <DartType>[],
          sourceInformation: sourceInformation);
      pop();
      return;
    }

    // if (assertTest(condition)) assertThrow(message);
    void buildCondition() {
      node.condition.accept(this);
      _pushStaticInvocation(
          _commonElements.assertTest,
          [pop()],
          _typeInferenceMap.getReturnTypeOf(_commonElements.assertTest),
          const <DartType>[],
          sourceInformation: sourceInformation);
    }

    void fail() {
      node.message.accept(this);
      _pushStaticInvocation(
          _commonElements.assertThrow,
          [pop()],
          _typeInferenceMap.getReturnTypeOf(_commonElements.assertThrow),
          const <DartType>[],
          sourceInformation: sourceInformation);
      pop();
    }

    _handleIf(visitCondition: buildCondition, visitThen: fail);
  }

  /// 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(ir.TreeNode node, JumpTarget target,
      {bool isLoopJump = false}) {
    if (target == null) {
      // No breaks or continues to this node.
      return NullJumpHandler(reporter);
    }
    if (isLoopJump && node is ir.SwitchStatement) {
      return KernelSwitchCaseJumpHandler(this, target, node, _localsMap);
    }

    return JumpHandler(this, target);
  }

  @override
  void visitBreakStatement(ir.BreakStatement node) {
    assert(!isAborted());
    _handleInTryStatement();
    JumpTarget target = _localsMap.getJumpTargetForBreak(node);
    assert(target != null);
    JumpHandler handler = jumpTargets[target];
    assert(handler != null);
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildGoto(node);
    if (_localsMap.generateContinueForBreak(node)) {
      if (handler.labels.isNotEmpty) {
        handler.generateContinue(sourceInformation, handler.labels.first);
      } else {
        handler.generateContinue(sourceInformation);
      }
    } else {
      if (handler.labels.isNotEmpty) {
        handler.generateBreak(sourceInformation, handler.labels.first);
      } else {
        handler.generateBreak(sourceInformation);
      }
    }
  }

  @override
  void visitLabeledStatement(ir.LabeledStatement node) {
    ir.Statement body = node.body;
    if (JumpVisitor.canBeBreakTarget(body)) {
      // loops and switches handle breaks on their own
      body.accept(this);
      return;
    }
    JumpTarget jumpTarget = _localsMap.getJumpTargetForLabel(node);
    if (jumpTarget == null) {
      // The label is not needed.
      body.accept(this);
      return;
    }

    JumpHandler handler = createJumpHandler(node, jumpTarget);

    LocalsHandler beforeLocals = LocalsHandler.from(localsHandler);

    HBasicBlock newBlock = openNewBlock();
    body.accept(this);
    SubGraph bodyGraph = SubGraph(newBlock, lastOpenedBlock);

    HBasicBlock joinBlock = graph.addNewBlock();
    List<LocalsHandler> breakHandlers = [];
    handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
      breakInstruction.block.addSuccessor(joinBlock);
      breakHandlers.add(locals);
    });

    if (!isAborted()) {
      goto(current, joinBlock);
      breakHandlers.add(localsHandler);
    }

    open(joinBlock);
    localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock);

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

  /// Loop through the cases in a switch and create a mapping of case
  /// expressions to constants.
  Map<ir.Expression, ConstantValue> _buildSwitchCaseConstants(
      ir.SwitchStatement switchStatement) {
    Map<ir.Expression, ConstantValue> constants = {};
    for (ir.SwitchCase switchCase in switchStatement.cases) {
      for (ir.Expression caseExpression in switchCase.expressions) {
        ConstantValue constant =
            _elementMap.getConstantValue(_memberContextNode, caseExpression);
        constants[caseExpression] = constant;
      }
    }
    return constants;
  }

  @override
  void visitContinueSwitchStatement(ir.ContinueSwitchStatement node) {
    _handleInTryStatement();
    JumpTarget target = _localsMap.getJumpTargetForContinueSwitch(node);
    assert(target != null);
    JumpHandler handler = jumpTargets[target];
    assert(handler != null);
    assert(target.labels.isNotEmpty);
    handler.generateContinue(
        _sourceInformationBuilder.buildGoto(node), target.labels.first);
  }

  @override
  void visitSwitchStatement(ir.SwitchStatement node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildSwitch(node);
    // The switch case indices must match those computed in
    // [KernelSwitchCaseJumpHandler].
    bool hasContinue = false;
    Map<ir.SwitchCase, int> caseIndex = {};
    int switchIndex = 1;
    bool hasDefault = false;
    for (ir.SwitchCase switchCase in node.cases) {
      if (_isDefaultCase(switchCase)) {
        hasDefault = true;
      }
      if (SwitchContinueAnalysis.containsContinue(switchCase.body)) {
        hasContinue = true;
      }
      caseIndex[switchCase] = switchIndex;
      switchIndex++;
    }

    JumpHandler jumpHandler =
        createJumpHandler(node, _localsMap.getJumpTargetForSwitch(node));
    if (!hasContinue) {
      // If the switch statement has no switch cases targeted by continue
      // statements we encode the switch statement directly.
      _buildSimpleSwitchStatement(node, jumpHandler, sourceInformation);
    } else {
      _buildComplexSwitchStatement(
          node, jumpHandler, caseIndex, hasDefault, sourceInformation);
    }
  }

  /// Helper for building switch statements.
  static bool _isDefaultCase(ir.SwitchCase switchCase) =>
      switchCase == null || switchCase.isDefault;

  /// Helper for building switch statements.
  HInstruction _buildExpression(ir.SwitchStatement switchStatement) {
    switchStatement.expression.accept(this);
    return pop();
  }

  /// Helper method for creating the list of constants that make up the
  /// switch case branches.
  List<ConstantValue> _getSwitchConstants(
      ir.SwitchStatement parentSwitch, ir.SwitchCase switchCase) {
    Map<ir.Expression, ConstantValue> constantsLookup =
        _buildSwitchCaseConstants(parentSwitch);
    List<ConstantValue> constantList = [];
    if (switchCase != null) {
      for (var expression in switchCase.expressions) {
        constantList.add(constantsLookup[expression]);
      }
    }
    return constantList;
  }

  /// Builds a simple switch statement which does not handle uses of continue
  /// statements to labeled switch cases.
  void _buildSimpleSwitchStatement(ir.SwitchStatement switchStatement,
      JumpHandler jumpHandler, SourceInformation sourceInformation) {
    void buildSwitchCase(ir.SwitchCase switchCase) {
      switchCase.body.accept(this);
    }

    _handleSwitch(
        switchStatement,
        jumpHandler,
        _buildExpression,
        switchStatement.cases,
        _getSwitchConstants,
        _isDefaultCase,
        buildSwitchCase,
        sourceInformation);
    jumpHandler.close();
  }

  /// Builds a switch statement that can handle arbitrary uses of continue
  /// statements to labeled switch cases.
  void _buildComplexSwitchStatement(
      ir.SwitchStatement switchStatement,
      JumpHandler jumpHandler,
      Map<ir.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;
    //     }
    //   }
    //
    // This is because JS does not have this same "continue label" semantics so
    // we encode it in the form of a state machine.

    JumpTarget switchTarget =
        _localsMap.getJumpTargetForSwitch(switchStatement);
    localsHandler.updateLocal(switchTarget, graph.addConstantNull(closedWorld));

    var switchCases = switchStatement.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 = List<ir.SwitchCase>.from(switchCases);
      switchCases.add(null);
    }

    void buildSwitchCase(ir.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 nullValue = graph.addConstantNull(closedWorld);
        localsHandler.updateLocal(switchTarget, nullValue,
            sourceInformation: caseSourceInformation);
      }
      jumpTargets[switchTarget].generateBreak(caseSourceInformation);
    }

    _handleSwitch(
        switchStatement,
        jumpHandler,
        _buildExpression,
        switchCases,
        _getSwitchConstants,
        _isDefaultCase,
        buildSwitchCase,
        sourceInformation);
    jumpHandler.close();

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

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

      List<ConstantValue> getConstants(
          ir.SwitchStatement parentSwitch, ir.SwitchCase switchCase) {
        return [constant_system.createIntFromInt(caseIndex[switchCase])];
      }

      void buildSwitchCase(ir.SwitchCase switchCase) {
        switchCase.body.accept(this);
        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(
          switchStatement, // nor is buildExpression.
          NullJumpHandler(reporter),
          buildExpression,
          switchStatement.cases,
          getConstants,
          (_) => false, // No case is default.
          buildSwitchCase,
          sourceInformation);
    }

    void buildLoop() {
      _loopHandler.handleLoop(
          switchStatement,
          _closureDataLookup.getCapturedLoopScope(switchStatement),
          switchTarget,
          () {},
          buildCondition,
          () {},
          buildSwitch,
          _sourceInformationBuilder.buildLoop(switchStatement));
    }

    if (hasDefault) {
      buildLoop();
    } else {
      // If the switch statement has no default case, surround the loop with
      // a test of the target. So:
      // `if (target) while (true) ...` If there's no default case, target is
      // null, so we don't drop into the while loop.
      void buildCondition() {
        js.Template code = js.js.parseForeignJS('#');
        push(HForeignCode(code, _abstractValueDomain.boolType,
            [localsHandler.readLocal(switchTarget)],
            nativeBehavior: NativeBehavior.PURE));
      }

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

  /// Creates a switch statement.
  ///
  /// [jumpHandler] is the [JumpHandler] for the created switch statement.
  /// [buildSwitchCase] creates the statements for the switch case.
  void _handleSwitch(
      ir.SwitchStatement switchStatement,
      JumpHandler jumpHandler,
      HInstruction buildExpression(ir.SwitchStatement statement),
      List<ir.SwitchCase> switchCases,
      List<ConstantValue> getConstants(
          ir.SwitchStatement parentSwitch, ir.SwitchCase switchCase),
      bool isDefaultCase(ir.SwitchCase switchCase),
      void buildSwitchCase(ir.SwitchCase switchCase),
      SourceInformation sourceInformation) {
    HBasicBlock expressionStart = openNewBlock();
    HInstruction expression = buildExpression(switchStatement);

    if (switchCases.isEmpty) {
      return;
    }

    HSwitch switchInstruction = HSwitch(_abstractValueDomain, [expression]);
    HBasicBlock expressionEnd = close(switchInstruction);
    LocalsHandler savedLocals = localsHandler;

    List<HStatementInformation> statements = [];
    bool hasDefault = false;
    for (ir.SwitchCase switchCase in switchCases) {
      HBasicBlock block = graph.addNewBlock();
      for (ConstantValue constant
          in getConstants(switchStatement, 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 = LocalsHandler.from(savedLocals);
      buildSwitchCase(switchCase);
      if (!isAborted() &&
          // TODO(johnniwinther): Reinsert this if `isReachable` is no longer
          // set to `false` when `_tryInlineMethod` sees an always throwing
          // method.
          //switchCase == switchCases.last &&
          !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(HSubGraphBlockInformation(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 = HBasicBlock();
    List<LocalsHandler> caseHandlers = [];
    jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
      instruction.block.addSuccessor(joinBlock);
      caseHandlers.add(locals);
    });
    jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) {
      assert(
          false,
          failedAt(_elementMap.getSpannable(targetElement, switchStatement),
              'Continue cannot target a switch.'));
    });
    if (!isAborted()) {
      current.close(HGoto(_abstractValueDomain));
      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(HGoto(_abstractValueDomain));
      defaultCase.addSuccessor(joinBlock);
      caseHandlers.add(savedLocals);
      statements
          .add(HSubGraphBlockInformation(SubGraph(defaultCase, defaultCase)));
    }
    assert(caseHandlers.length == joinBlock.predecessors.length);
    if (caseHandlers.isNotEmpty) {
      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 =
        HSubExpressionBlockInformation(
            SubExpression(expressionStart, expressionEnd));
    expressionStart.setBlockFlow(
        HSwitchBlockInformation(expressionInfo, statements, jumpHandler.target,
            jumpHandler.labels, sourceInformation),
        joinBlock);

    jumpHandler.close();
  }

  @override
  void visitConditionalExpression(ir.ConditionalExpression node) {
    SsaBranchBuilder brancher = SsaBranchBuilder(this);
    brancher.handleConditional(() => node.condition.accept(this),
        () => node.then.accept(this), () => node.otherwise.accept(this));
  }

  @override
  void visitLogicalExpression(ir.LogicalExpression node) {
    SsaBranchBuilder brancher = SsaBranchBuilder(this);
    _handleLogicalExpression(node.left, () => node.right.accept(this), brancher,
        node.operatorEnum, _sourceInformationBuilder.buildBinary(node));
  }

  /// Optimizes logical binary expression where the left has the same logical
  /// binary operator.
  ///
  /// 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)`:
  ///
  void _handleLogicalExpression(
      ir.Expression left,
      void visitRight(),
      SsaBranchBuilder brancher,
      ir.LogicalExpressionOperator operatorEnum,
      SourceInformation sourceInformation) {
    if (left is ir.LogicalExpression && left.operatorEnum == operatorEnum) {
      ir.Expression innerLeft = left.left;
      ir.Expression middle = left.right;
      _handleLogicalExpression(
          innerLeft,
          () => _handleLogicalExpression(middle, visitRight, brancher,
              operatorEnum, _sourceInformationBuilder.buildBinary(middle)),
          brancher,
          operatorEnum,
          sourceInformation);
    } else {
      brancher.handleLogicalBinary(
          () => left.accept(this), visitRight, sourceInformation,
          isAnd: operatorEnum == ir.LogicalExpressionOperator.AND);
    }
  }

  @override
  void visitIntLiteral(ir.IntLiteral node) {
    stack.add(graph.addConstantIntAsUnsigned(node.value, closedWorld));
  }

  @override
  void visitDoubleLiteral(ir.DoubleLiteral node) {
    stack.add(graph.addConstantDouble(node.value, closedWorld));
  }

  @override
  void visitBoolLiteral(ir.BoolLiteral node) {
    stack.add(graph.addConstantBool(node.value, closedWorld));
  }

  @override
  void visitStringLiteral(ir.StringLiteral node) {
    stack.add(graph.addConstantString(node.value, closedWorld));
  }

  @override
  void visitSymbolLiteral(ir.SymbolLiteral node) {
    stack.add(graph.addConstant(
        _elementMap.getConstantValue(_memberContextNode, node), closedWorld));
    registry?.registerConstSymbol(node.value);
  }

  @override
  void visitNullLiteral(ir.NullLiteral node) {
    stack.add(graph.addConstantNull(closedWorld));
  }

  /// Set the runtime type information if necessary.
  HInstruction _setListRuntimeTypeInfoIfNeeded(HInstruction object,
      InterfaceType type, SourceInformation sourceInformation) {
    // [type] could be `List<T>`, so ensure it is `JSArray<T>`.
    InterfaceType arrayType = dartTypes.interfaceType(
        _commonElements.jsArrayClass, type.typeArguments);
    if (!_rtiNeed.classNeedsTypeArguments(type.element) ||
        _equivalentToMissingRti(arrayType)) {
      return object;
    }
    HInstruction rti =
        _typeBuilder.analyzeTypeArgumentNewRti(arrayType, sourceElement);

    // TODO(15489): Register at codegen.
    registry?.registerInstantiation(type);
    return _callSetRuntimeTypeInfo(rti, object, sourceInformation);
  }

  @override
  void visitListLiteral(ir.ListLiteral node) {
    HInstruction listInstruction;
    if (node.isConst) {
      listInstruction = graph.addConstant(
          _elementMap.getConstantValue(_memberContextNode, node), closedWorld);
    } else {
      List<HInstruction> elements = [];
      for (ir.Expression element in node.expressions) {
        element.accept(this);
        elements.add(pop());
      }
      listInstruction = _buildLiteralList(elements);
      add(listInstruction);
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildListLiteral(node);
      InterfaceType type = localsHandler.substInContext(
          _commonElements.listType(_elementMap.getDartType(node.typeArgument)));
      listInstruction = _setListRuntimeTypeInfoIfNeeded(
          listInstruction, type, sourceInformation);
    }

    AbstractValue type =
        _typeInferenceMap.typeOfListLiteral(node, _abstractValueDomain);
    if (_abstractValueDomain.containsAll(type).isDefinitelyFalse) {
      listInstruction.instructionType = type;
    }
    stack.add(listInstruction);
  }

  @override
  void visitSetLiteral(ir.SetLiteral node) {
    if (node.isConst) {
      stack.add(graph.addConstant(
          _elementMap.getConstantValue(_memberContextNode, node), closedWorld));
      return;
    }

    // The set literal constructors take the elements as a List.
    List<HInstruction> elements = [];
    for (ir.Expression element in node.expressions) {
      element.accept(this);
      elements.add(pop());
    }

    // The constructor is a procedure because it's a factory.
    FunctionEntity constructor;
    List<HInstruction> inputs = [];
    if (elements.isEmpty) {
      constructor = _commonElements.setLiteralConstructorEmpty;
    } else {
      constructor = _commonElements.setLiteralConstructor;
      HLiteralList argList = _buildLiteralList(elements);
      add(argList);
      inputs.add(argList);
    }

    assert(
        constructor is ConstructorEntity && constructor.isFactoryConstructor);

    InterfaceType type = localsHandler.substInContext(
        _commonElements.setType(_elementMap.getDartType(node.typeArgument)));
    ClassEntity cls = constructor.enclosingClass;

    if (_rtiNeed.classNeedsTypeArguments(cls)) {
      List<HInstruction> typeInputs = [];
      type.typeArguments.forEach((DartType 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(_abstractValueDomain).isDefinitelyTrue)) {
        if (elements.isEmpty) {
          constructor = _commonElements.setLiteralUntypedEmptyMaker;
        } else {
          constructor = _commonElements.setLiteralUntypedMaker;
        }
      } else {
        inputs.addAll(typeInputs);
      }
    }

    // If runtime type information is needed and the set literal has no type
    // parameter, 'constructor' is a static function that forwards the call to
    // the factory constructor without a type parameter.
    assert(constructor.isFunction ||
        (constructor is ConstructorEntity && constructor.isFactoryConstructor));

    // The instruction type will always be a subtype of the setLiteralClass, but
    // type inference might discover a more specific type or find nothing (in
    // dart2js unit tests).

    AbstractValue setType = _abstractValueDomain
        .createNonNullSubtype(_commonElements.setLiteralClass);
    AbstractValue returnTypeMask =
        _typeInferenceMap.getReturnTypeOf(constructor);
    AbstractValue instructionType =
        _abstractValueDomain.intersection(setType, returnTypeMask);

    _addImplicitInstantiation(type);
    _pushStaticInvocation(
        constructor, inputs, instructionType, const <DartType>[],
        sourceInformation: _sourceInformationBuilder.buildNew(node));
    _removeImplicitInstantiation(type);
  }

  @override
  void visitMapLiteral(ir.MapLiteral node) {
    if (node.isConst) {
      stack.add(graph.addConstant(
          _elementMap.getConstantValue(_memberContextNode, node), closedWorld));
      return;
    }

    // The map literal constructors take the key-value pairs as a List
    List<HInstruction> constructorArgs = [];
    for (ir.MapLiteralEntry mapEntry in node.entries) {
      mapEntry.key.accept(this);
      constructorArgs.add(pop());
      mapEntry.value.accept(this);
      constructorArgs.add(pop());
    }

    // The constructor is a procedure because it's a factory.
    FunctionEntity constructor;
    List<HInstruction> inputs = [];
    if (constructorArgs.isEmpty) {
      constructor = _commonElements.mapLiteralConstructorEmpty;
    } else {
      constructor = _commonElements.mapLiteralConstructor;
      HLiteralList argList = _buildLiteralList(constructorArgs);
      add(argList);
      inputs.add(argList);
    }

    assert(
        constructor is ConstructorEntity && constructor.isFactoryConstructor);

    InterfaceType type = localsHandler.substInContext(_commonElements.mapType(
        _elementMap.getDartType(node.keyType),
        _elementMap.getDartType(node.valueType)));
    ClassEntity cls = constructor.enclosingClass;

    if (_rtiNeed.classNeedsTypeArguments(cls)) {
      List<HInstruction> typeInputs = [];
      type.typeArguments.forEach((DartType 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(_abstractValueDomain).isDefinitelyTrue)) {
        if (constructorArgs.isEmpty) {
          constructor = _commonElements.mapLiteralUntypedEmptyMaker;
        } else {
          constructor = _commonElements.mapLiteralUntypedMaker;
        }
      } else {
        inputs.addAll(typeInputs);
      }
    }

    // If runtime type information 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(constructor.isFunction ||
        (constructor is ConstructorEntity && constructor.isFactoryConstructor));

    // 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).

    AbstractValue mapType = _abstractValueDomain
        .createNonNullSubtype(_commonElements.mapLiteralClass);
    AbstractValue returnTypeMask =
        _typeInferenceMap.getReturnTypeOf(constructor);
    AbstractValue instructionType =
        _abstractValueDomain.intersection(mapType, returnTypeMask);

    _addImplicitInstantiation(type);
    _pushStaticInvocation(
        constructor, inputs, instructionType, const <DartType>[],
        sourceInformation: _sourceInformationBuilder.buildNew(node));
    _removeImplicitInstantiation(type);
  }

  @override
  void visitMapLiteralEntry(ir.MapLiteralEntry node) {
    failedAt(CURRENT_ELEMENT_SPANNABLE,
        'ir.MapEntry should be handled in visitMapLiteral');
  }

  @override
  void visitTypeLiteral(ir.TypeLiteral node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildGet(node);
    ir.DartType type = node.type;
    DartType dartType = _elementMap.getDartType(type);
    if (!dartType.containsTypeVariables) {
      ConstantValue constant =
          _elementMap.getConstantValue(_memberContextNode, node);
      stack.add(graph.addConstant(constant, closedWorld,
          sourceInformation: sourceInformation));
      return;
    }
    // For other types (e.g. TypeParameterType, function types from expanded
    // typedefs), look-up or construct a reified type representation and convert
    // to a RuntimeType.

    dartType = localsHandler.substInContext(dartType);
    HInstruction value = _typeBuilder.analyzeTypeArgument(
        dartType, sourceElement,
        sourceInformation: sourceInformation);
    _pushStaticInvocation(
        _commonElements.createRuntimeType,
        [value],
        _typeInferenceMap.getReturnTypeOf(_commonElements.createRuntimeType),
        const <DartType>[],
        sourceInformation: sourceInformation);
  }

  @override
  void visitStaticGet(ir.StaticGet node) {
    ir.Member staticTarget = node.target;
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildGet(node);
    if (staticTarget is ir.Procedure &&
        staticTarget.kind == ir.ProcedureKind.Getter) {
      FunctionEntity getter = _elementMap.getMember(staticTarget);
      // Invoke the getter
      _pushStaticInvocation(getter, const [],
          _typeInferenceMap.getReturnTypeOf(getter), const <DartType>[],
          sourceInformation: sourceInformation);
    } else if (staticTarget is ir.Field) {
      FieldEntity field = _elementMap.getField(staticTarget);
      FieldAnalysisData fieldData = _fieldAnalysis.getFieldData(field);
      if (fieldData.isEager) {
        push(HStatic(field, _typeInferenceMap.getInferredTypeOf(field),
            sourceInformation));
      } else if (fieldData.isEffectivelyConstant) {
        OutputUnit outputUnit =
            closedWorld.outputUnitData.outputUnitForMember(field);
        // TODO(sigmund): this is not equivalent to what the old FE does: if
        // there is no prefix the old FE wouldn't treat this in any special
        // way. Also, if the prefix points to a constant in the main output
        // unit, the old FE would still generate a deferred wrapper here.
        if (!closedWorld.outputUnitData
            .hasOnlyNonDeferredImportPaths(targetElement, field)) {
          ConstantValue deferredConstant =
              DeferredGlobalConstantValue(fieldData.initialValue, outputUnit);
          registry.registerConstantUse(ConstantUse.deferred(deferredConstant));
          stack.add(graph.addDeferredConstant(
              deferredConstant, sourceInformation, closedWorld));
        } else {
          stack.add(graph.addConstant(fieldData.initialValue, closedWorld,
              sourceInformation: sourceInformation));
        }
      } else {
        assert(
            fieldData.isLazy, "Unexpected field data for $field: $fieldData");
        push(HLazyStatic(field, _typeInferenceMap.getInferredTypeOf(field),
            sourceInformation));
      }
    } else {
      // TODO(johnniwinther): This is a constant tear off, so we should have
      // created a constant value instead. Remove this case when we use CFE
      // constants.
      FunctionEntity member = _elementMap.getMember(staticTarget);
      push(HStatic(member, _typeInferenceMap.getInferredTypeOf(member),
          sourceInformation));
    }
  }

  @override
  void visitStaticTearOff(ir.StaticTearOff node) {
    // TODO(johnniwinther): This is a constant tear off, so we should have
    // created a constant value instead. Remove this case when we use CFE
    // constants.
    ir.Member staticTarget = node.target;
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildGet(node);
    FunctionEntity member = _elementMap.getMember(staticTarget);
    push(HStatic(member, _typeInferenceMap.getInferredTypeOf(member),
        sourceInformation));
  }

  @override
  void visitStaticSet(ir.StaticSet node) {
    node.value.accept(this);
    HInstruction value = pop();

    ir.Member staticTarget = node.target;
    if (staticTarget is ir.Procedure) {
      FunctionEntity setter = _elementMap.getMember(staticTarget);
      // Invoke the setter
      _pushStaticInvocation(setter, [value],
          _typeInferenceMap.getReturnTypeOf(setter), const <DartType>[],
          sourceInformation: _sourceInformationBuilder.buildSet(node));
      pop();
    } else {
      MemberEntity target = _elementMap.getMember(staticTarget);
      if (!_fieldAnalysis.getFieldData(target).isElided) {
        add(HStaticStore(
            _abstractValueDomain,
            target,
            _typeBuilder.potentiallyCheckOrTrustTypeOfAssignment(
                target, value, _getDartTypeIfValid(staticTarget.setterType))));
      }
    }
    stack.add(value);
  }

  void _handlePropertyGet(
      ir.Expression node, ir.Expression receiver, ir.Name name) {
    receiver.accept(this);
    HInstruction receiverInstruction = pop();
    _pushDynamicInvocation(
        node,
        _getStaticType(receiver),
        _typeInferenceMap.receiverTypeOfGet(node),
        Selector.getter(_elementMap.getName(name)),
        [receiverInstruction],
        const <DartType>[],
        _sourceInformationBuilder.buildGet(node));
  }

  @override
  void visitInstanceGet(ir.InstanceGet node) {
    _handlePropertyGet(node, node.receiver, node.name);
  }

  @override
  void visitInstanceTearOff(ir.InstanceTearOff node) {
    _handlePropertyGet(node, node.receiver, node.name);
  }

  @override
  void visitDynamicGet(ir.DynamicGet node) {
    _handlePropertyGet(node, node.receiver, node.name);
  }

  @override
  void visitFunctionTearOff(ir.FunctionTearOff node) {
    _handlePropertyGet(node, node.receiver, ir.Name.callName);
  }

  @override
  void visitVariableGet(ir.VariableGet node) {
    ir.VariableDeclaration variable = node.variable;
    HInstruction letBinding = _letBindings[variable];
    if (letBinding != null) {
      stack.add(letBinding);
      return;
    }

    Local local = _localsMap.getLocalVariable(node.variable);
    stack.add(localsHandler.readLocal(local,
        sourceInformation: _sourceInformationBuilder.buildGet(node)));
  }

  void _handlePropertySet(ir.Expression node, ir.Expression receiver,
      ir.Name name, ir.Expression value) {
    receiver.accept(this);
    HInstruction receiverInstruction = pop();
    value.accept(this);
    HInstruction valueInstruction = pop();

    _pushDynamicInvocation(
        node,
        _getStaticType(receiver),
        _typeInferenceMap.receiverTypeOfSet(node, _abstractValueDomain),
        Selector.setter(_elementMap.getName(name)),
        [receiverInstruction, valueInstruction],
        const <DartType>[],
        _sourceInformationBuilder.buildAssignment(node));

    pop();
    stack.add(valueInstruction);
  }

  @override
  void visitInstanceSet(ir.InstanceSet node) {
    _handlePropertySet(node, node.receiver, node.name, node.value);
  }

  @override
  void visitDynamicSet(ir.DynamicSet node) {
    _handlePropertySet(node, node.receiver, node.name, node.value);
  }

  @override
  void visitSuperPropertySet(ir.SuperPropertySet node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildAssignment(node);
    node.value.accept(this);
    HInstruction value = pop();

    ir.Member target = getEffectiveSuperTarget(node.interfaceTarget);
    if (target == null) {
      // TODO(johnniwinther): Remove this when the CFE checks for missing
      //  concrete super targets.
      _generateSuperNoSuchMethod(node, _elementMap.getSelector(node).name + "=",
          [value], const <DartType>[], sourceInformation);
    } else {
      MemberEntity member = _elementMap.getMember(target);
      _buildInvokeSuper(
          _elementMap.getSelector(node),
          _elementMap.getClass(_containingClass(node)),
          member,
          [value],
          const <DartType>[],
          sourceInformation);
    }
    pop();
    stack.add(value);
  }

  @override
  void visitVariableSet(ir.VariableSet node) {
    node.value.accept(this);
    HInstruction value = pop();
    _visitLocalSetter(
        node.variable, value, _sourceInformationBuilder.buildAssignment(node));
  }

  @override
  void visitVariableDeclaration(ir.VariableDeclaration node) {
    Local local = _localsMap.getLocalVariable(node);
    if (node.initializer == null) {
      HInstruction initialValue = graph.addConstantNull(closedWorld);
      localsHandler.updateLocal(local, initialValue);
    } else if (node.isConst) {
      ConstantValue constant =
          _elementMap.getConstantValue(_memberContextNode, node.initializer);
      assert(constant != null, failedAt(CURRENT_ELEMENT_SPANNABLE));
      HInstruction initialValue = graph.addConstant(constant, closedWorld);
      localsHandler.updateLocal(local, initialValue);
    } else {
      node.initializer.accept(this);
      HInstruction initialValue = pop();

      _visitLocalSetter(
          node, initialValue, _sourceInformationBuilder.buildAssignment(node));

      // Ignore value
      pop();
    }
  }

  void _visitLocalSetter(ir.VariableDeclaration variable, HInstruction value,
      SourceInformation sourceInformation) {
    Local local = _localsMap.getLocalVariable(variable);

    // Give the value a name if it doesn't have one already.
    if (value.sourceElement == null) {
      value.sourceElement = local;
    }

    stack.add(value);
    localsHandler.updateLocal(
        local,
        _typeBuilder.potentiallyCheckOrTrustTypeOfAssignment(
            _currentFrame.member, value, _getDartTypeIfValid(variable.type)),
        sourceInformation: sourceInformation);
  }

  @override
  void visitLet(ir.Let node) {
    ir.VariableDeclaration variable = node.variable;
    variable.initializer.accept(this);
    HInstruction initializedValue = pop();
    // TODO(sra): Apply inferred type information.
    _letBindings[variable] = initializedValue;
    node.body.accept(this);
  }

  @override
  void visitBlockExpression(ir.BlockExpression node) {
    node.body.accept(this);
    // Body can be partially generated due to an exception exit and be missing
    // bindings referenced in the value.
    if (!_isReachable) {
      stack.add(graph.addConstantUnreachable(closedWorld));
    } else {
      node.value.accept(this);
    }
  }

  /// Generate instructions to evaluate the positional arguments in source
  /// order.
  List<HInstruction> _visitPositionalArguments(ir.Arguments arguments) {
    List<HInstruction> result = [];
    for (ir.Expression argument in arguments.positional) {
      argument.accept(this);
      result.add(pop());
    }
    return result;
  }

  /// Generate instructions to evaluate the named arguments in source order.
  /// Returns a fresh map from parameter name to evaluated argument.
  Map<String, HInstruction> _visitNamedArguments(ir.Arguments arguments) {
    Map<String, HInstruction> values = {};
    for (ir.NamedExpression argument in arguments.named) {
      argument.value.accept(this);
      values[argument.name] = pop();
    }
    return values;
  }

  /// Builds the list of instructions for the expressions in the arguments to a
  /// dynamic target (member function).  Dynamic targets use stubs to add
  /// defaulted arguments, so (unlike static targets) we do not add the default
  /// values.
  List<HInstruction> _visitArgumentsForDynamicTarget(
      Selector selector, ir.Arguments arguments, List<DartType> typeArguments,
      [SourceInformation sourceInformation]) {
    List<HInstruction> values = _visitPositionalArguments(arguments);

    if (arguments.named.isNotEmpty) {
      Map<String, HInstruction> namedValues = _visitNamedArguments(arguments);
      for (String name in selector.callStructure.getOrderedNamedArguments()) {
        values.add(namedValues[name]);
      }
    }

    _addTypeArguments(values, typeArguments, sourceInformation);

    return values;
  }

  /// Build the argument list for JS-interop invocations, which have slightly
  /// different semantics than dart because of JS's null vs undefined and lack
  /// of named arguments. Return null if the arguments could not be correctly
  /// parsed because the user provided code with named parameters in a JS (non
  /// factory) function.
  List<HInstruction> _visitArgumentsForNativeStaticTarget(
      ir.FunctionNode target, ir.Arguments arguments) {
    // Visit arguments in source order, then re-order and fill in defaults.
    var values = _visitPositionalArguments(arguments);

    if (target.namedParameters.isNotEmpty) {
      // Only anonymous factory constructors involving JS interop are allowed to
      // have named parameters. Otherwise, throw an error.
      FunctionEntity function = _elementMap.getMember(target.parent);
      if (function is ConstructorEntity && function.isFactoryConstructor) {
        // TODO(sra): Have a "CompiledArguments" structure to just update with
        // what values we have rather than creating a map and de-populating it.
        Map<String, HInstruction> namedValues = _visitNamedArguments(arguments);

        // Visit named arguments in parameter-position order, selecting provided
        // or default value.
        var namedParameters = target.namedParameters.toList();
        namedParameters.sort(nativeOrdering);
        for (ir.VariableDeclaration parameter in namedParameters) {
          HInstruction value = namedValues[parameter.name];
          values.add(value);
          if (value != null) {
            namedValues.remove(parameter.name);
          }
        }
        assert(namedValues.isEmpty);
      }
    }
    return values;
  }

  /// Fills [typeArguments] with the type arguments needed for [selector] and
  /// returns the selector corresponding to the passed type arguments.
  Selector _fillDynamicTypeArguments(
      Selector selector, ir.Arguments arguments, List<DartType> typeArguments) {
    if (selector.typeArgumentCount > 0) {
      if (_rtiNeed.selectorNeedsTypeArguments(selector)) {
        typeArguments.addAll(arguments.types.map(_elementMap.getDartType));
      } else {
        return selector.toNonGeneric();
      }
    }
    return selector;
  }

  List<DartType> _getConstructorTypeArguments(
      ConstructorEntity constructor, ir.Arguments arguments) {
    // TODO(johnniwinther): Pass type arguments to constructors like calling
    // a generic method.
    return const <DartType>[];
  }

  // TODO(johnniwinther): Remove this when type arguments are passed to
  // constructors like calling a generic method.
  List<DartType> _getClassTypeArguments(
      ClassEntity cls, ir.Arguments arguments) {
    if (_rtiNeed.classNeedsTypeArguments(cls)) {
      return arguments.types.map(_elementMap.getDartType).toList();
    }
    return const <DartType>[];
  }

  List<DartType> _getStaticTypeArguments(
      FunctionEntity function, ir.Arguments arguments) {
    if (_rtiNeed.methodNeedsTypeArguments(function)) {
      return arguments.types.map(_elementMap.getDartType).toList();
    }
    return const <DartType>[];
  }

  /// Build argument list in canonical order for a static [target], including
  /// filling in the default argument value.
  List<HInstruction> _visitArgumentsForStaticTarget(
      ir.Member memberContextNode,
      ir.FunctionNode target,
      ParameterStructure parameterStructure,
      ir.Arguments arguments,
      List<DartType> typeArguments,
      SourceInformation sourceInformation) {
    // Visit arguments in source order, then re-order and fill in defaults.
    List<HInstruction> values = _visitPositionalArguments(arguments);

    while (values.length < parameterStructure.positionalParameters) {
      ir.VariableDeclaration parameter =
          target.positionalParameters[values.length];
      values.add(_defaultValueForParameter(memberContextNode, parameter));
    }

    if (parameterStructure.namedParameters.isNotEmpty) {
      Map<String, HInstruction> namedValues = _visitNamedArguments(arguments);

      // Visit named arguments in parameter-position order, selecting provided
      // or default value.
      // TODO(sra): Ensure the stored order is canonical so we don't have to
      // sort. The old builder uses CallStructure.makeArgumentList which depends
      // on the old element model.
      List<ir.VariableDeclaration> namedParameters = target.namedParameters
          // Filter elided parameters.
          .where((p) => parameterStructure.namedParameters.contains(p.name))
          .toList()
        ..sort(namedOrdering);
      for (ir.VariableDeclaration parameter in namedParameters) {
        HInstruction value = namedValues[parameter.name];
        if (value == null) {
          values.add(_defaultValueForParameter(memberContextNode, parameter));
        } else {
          values.add(value);
          namedValues.remove(parameter.name);
        }
      }
      assert(namedValues.isEmpty);
    } else {
      assert(arguments.named.isEmpty);
    }

    _addTypeArguments(values, typeArguments, sourceInformation);
    return values;
  }

  void _addTypeArguments(List<HInstruction> values,
      List<DartType> typeArguments, SourceInformation sourceInformation) {
    if (typeArguments.isEmpty) return;
    for (DartType type in typeArguments) {
      values.add(_typeBuilder.analyzeTypeArgument(type, sourceElement,
          sourceInformation: sourceInformation));
    }
  }

  HInstruction _defaultValueForParameter(
      ir.Member memberContextNode, ir.VariableDeclaration parameter) {
    ConstantValue constant = _elementMap.getConstantValue(
        memberContextNode, parameter.initializer,
        implicitNull: true);
    assert(constant != null, failedAt(CURRENT_ELEMENT_SPANNABLE));
    return graph.addConstant(constant, closedWorld);
  }

  @override
  void visitStaticInvocation(ir.StaticInvocation node) {
    ir.Procedure target = node.target;
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(node, node);
    FunctionEntity function = _elementMap.getMember(target);
    if (_commonElements.isForeignHelper(function)) {
      _handleInvokeStaticForeign(node, function);
      return;
    }

    if (_commonElements.isExtractTypeArguments(function) &&
        _handleExtractTypeArguments(node, sourceInformation)) {
      return;
    }

    AbstractValue typeMask = _typeInferenceMap.getReturnTypeOf(function);

    List<DartType> typeArguments =
        _getStaticTypeArguments(function, node.arguments);
    List<HInstruction> arguments = closedWorld.nativeData
            .isJsInteropMember(function)
        ? _visitArgumentsForNativeStaticTarget(target.function, node.arguments)
        : _visitArgumentsForStaticTarget(
            target,
            target.function,
            function.parameterStructure,
            node.arguments,
            typeArguments,
            sourceInformation);

    // Error in the arguments provided. Do not process further.
    if (arguments == null) {
      stack.add(graph.addConstantNull(closedWorld)); // Result expected on stack
      return;
    }

    if (function is ConstructorEntity && function.isFactoryConstructor) {
      _handleInvokeFactoryConstructor(
          node, function, typeMask, arguments, sourceInformation);
      return;
    }

    // Static methods currently ignore the type parameters.
    _pushStaticInvocation(function, arguments, typeMask, typeArguments,
        sourceInformation: sourceInformation);
  }

  void _handleInvokeFactoryConstructor(
      ir.StaticInvocation invocation,
      ConstructorEntity function,
      AbstractValue typeMask,
      List<HInstruction> arguments,
      SourceInformation sourceInformation) {
    // Recognize e.g. `bool.fromEnvironment('x')`
    // TODO(sra): Can we delete this code now that the CFE does constant folding
    // for us during loading?
    if (function.isExternal && function.isFromEnvironmentConstructor) {
      if (invocation.isConst) {
        // Just like all const constructors (see visitConstructorInvocation).
        stack.add(graph.addConstant(
            _elementMap.getConstantValue(_memberContextNode, invocation),
            closedWorld,
            sourceInformation: sourceInformation));
      } else {
        _generateUnsupportedError(
            '${function.enclosingClass.name}.${function.name} '
            'can only be used as a const constructor',
            sourceInformation);
      }
      return;
    }

    // Recognize `List()` and `List(n)`.
    if (_commonElements.isUnnamedListConstructor(function)) {
      if (invocation.arguments.named.isEmpty) {
        int argumentCount = invocation.arguments.positional.length;
        if (argumentCount == 0) {
          // `List()` takes no arguments, `JSArray.list()` takes a sentinel.
          assert(arguments.length == 0 || arguments.length == 1,
              '\narguments: $arguments\n');
          _handleInvokeLegacyGrowableListFactoryConstructor(
              invocation, function, typeMask, arguments, sourceInformation);
          return;
        }
        if (argumentCount == 1) {
          assert(arguments.length == 1);
          _handleInvokeLegacyFixedListFactoryConstructor(
              invocation, function, typeMask, arguments, sourceInformation);
          return;
        }
      }
    }

    // Recognize `JSArray<E>.typed(allocation)`.
    if (function == _commonElements.jsArrayTypedConstructor) {
      if (invocation.arguments.named.isEmpty) {
        if (invocation.arguments.positional.length == 1) {
          assert(arguments.length == 1);
          _handleInvokeJSArrayTypedConstructor(
              invocation, function, typeMask, arguments, sourceInformation);
          return;
        }
      }
    }

    InterfaceType instanceType = _elementMap.createInterfaceType(
        invocation.target.enclosingClass, invocation.arguments.types);

    // Factory constructors take type parameters.
    List<DartType> typeArguments =
        _getConstructorTypeArguments(function, invocation.arguments);

    // This could be a List factory constructor that returned a fresh list and
    // we have a call-site-specific type from type inference.
    var allocatedListType = globalInferenceResults.typeOfNewList(invocation);
    AbstractValue resultType = allocatedListType ?? typeMask;

    // TODO(johnniwinther): Remove this when type arguments are passed to
    // constructors like calling a generic method.
    _addTypeArguments(
        arguments,
        _getClassTypeArguments(function.enclosingClass, invocation.arguments),
        sourceInformation);
    instanceType = localsHandler.substInContext(instanceType);
    _addImplicitInstantiation(instanceType);
    _pushStaticInvocation(function, arguments, resultType, typeArguments,
        sourceInformation: sourceInformation, instanceType: instanceType);

    if (allocatedListType != null) {
      HInstruction newInstance = stack.last.nonCheck();
      if (newInstance is HInvokeStatic) {
        newInstance.setAllocation(true);
      }
      // Is the constructor call one from which we can extract the length
      // argument?
      bool isFixedList = false;

      if (_abstractValueDomain.isFixedArray(resultType).isDefinitelyTrue) {
        // These constructors all take a length as the first argument.
        if (_commonElements.isNamedListConstructor('filled', function) ||
            _commonElements.isNamedListConstructor('generate', function) ||
            _commonElements.isNamedJSArrayConstructor('fixed', function) ||
            _commonElements.isNamedJSArrayConstructor(
                'allocateFixed', function)) {
          isFixedList = true;
        }
      }

      if (_abstractValueDomain.isTypedArray(resultType).isDefinitelyTrue) {
        // The unnamed constructors of typed arrays take a length as the first
        // argument.
        if (function.name == '') isFixedList = true;
        // TODO(sra): Can this misfire?
      }

      if (isFixedList) {
        if (newInstance is HInvokeStatic || newInstance is HForeignCode) {
          graph.allocatedFixedLists.add(newInstance);
        }
      }
    }
  }

  /// Handle the `JSArray<E>.typed` constructor, which returns its argument,
  /// which must be a JSArray, with the JSArray type Rti information added on a
  /// property.
  void _handleInvokeJSArrayTypedConstructor(
      ir.StaticInvocation invocation,
      ConstructorEntity function,
      AbstractValue typeMask,
      List<HInstruction> arguments,
      SourceInformation sourceInformation) {
    // TODO(sra): We rely here on inlining the identity-like factory
    // constructor. Instead simply select the single argument and add the type.

    // Factory constructors take type parameters.
    List<DartType> typeArguments =
        _getConstructorTypeArguments(function, invocation.arguments);
    // TODO(johnniwinther): Remove this when type arguments are passed to
    // constructors like calling a generic method.
    _addTypeArguments(
        arguments,
        _getClassTypeArguments(function.enclosingClass, invocation.arguments),
        sourceInformation);
    _pushStaticInvocation(function, arguments, typeMask, typeArguments,
        sourceInformation: sourceInformation);

    InterfaceType type = _elementMap.createInterfaceType(
        invocation.target.enclosingClass, invocation.arguments.types);
    stack.add(_setListRuntimeTypeInfoIfNeeded(pop(), type, sourceInformation));
  }

  /// Handle the legacy `List<T>()` constructor.
  void _handleInvokeLegacyGrowableListFactoryConstructor(
      ir.StaticInvocation invocation,
      ConstructorEntity function,
      AbstractValue typeMask,
      List<HInstruction> arguments,
      SourceInformation sourceInformation) {
    // `List<T>()` is essentially the same as `<T>[]`.
    push(_buildLiteralList([]));
    HInstruction allocation = pop();
    var inferredType = globalInferenceResults.typeOfNewList(invocation);
    if (inferredType != null) {
      allocation.instructionType = inferredType;
    }
    InterfaceType type = _elementMap.createInterfaceType(
        invocation.target.enclosingClass, invocation.arguments.types);
    stack.add(
        _setListRuntimeTypeInfoIfNeeded(allocation, type, sourceInformation));
  }

  /// Handle the `JSArray<T>.list(length)` and legacy `List<T>(length)`
  /// constructors.
  void _handleInvokeLegacyFixedListFactoryConstructor(
      ir.StaticInvocation invocation,
      ConstructorEntity function,
      AbstractValue typeMask,
      List<HInstruction> arguments,
      SourceInformation sourceInformation) {
    assert(
        // Arguments may include the type.
        arguments.length == 1 || arguments.length == 2,
        failedAt(
            function,
            "Unexpected arguments. "
            "Expected 1-2 argument, actual: $arguments."));
    HInstruction lengthInput = arguments.first;
    if (lengthInput.isNumber(_abstractValueDomain).isPotentiallyFalse) {
      HPrimitiveCheck conversion = HPrimitiveCheck(
          _commonElements.numType,
          HPrimitiveCheck.ARGUMENT_TYPE_CHECK,
          _abstractValueDomain.numType,
          lengthInput,
          sourceInformation);
      add(conversion);
      lengthInput = conversion;
    }
    js.Template code = js.js.parseForeignJS('new Array(#)');
    var behavior = NativeBehavior();

    DartType expectedType = _getStaticType(invocation).type;
    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 (lengthInput.isUInt32(_abstractValueDomain).isDefinitelyTrue) {
      canThrow = false;
    }

    var resultType = globalInferenceResults.typeOfNewList(invocation) ??
        _abstractValueDomain.fixedListType;

    HForeignCode foreign = HForeignCode(code, resultType, [lengthInput],
        nativeBehavior: behavior,
        throwBehavior:
            canThrow ? NativeThrowBehavior.MAY : NativeThrowBehavior.NEVER)
      ..sourceInformation = sourceInformation;
    push(foreign);
    // TODO(redemption): Global type analysis tracing may have determined that
    // the fixed-length property is never checked. If so, we can avoid marking
    // the array.
    {
      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(HForeignCode(code, _abstractValueDomain.nullType, [stack.last],
          throwBehavior: NativeThrowBehavior.MAY));
    }

    HInstruction newInstance = stack.last;

    // If we inlined a constructor the call-site-specific type from type
    // inference (e.g. a container type) will not be on the node. Store the
    // more specialized type on the allocation.
    newInstance.instructionType = resultType;
    graph.allocatedFixedLists.add(newInstance);

    InterfaceType type = _elementMap.createInterfaceType(
        invocation.target.enclosingClass, invocation.arguments.types);
    stack.add(_setListRuntimeTypeInfoIfNeeded(pop(), type, sourceInformation));
  }

  /// Replace calls to `extractTypeArguments` with equivalent code. Returns
  /// `true` if `extractTypeArguments` is handled.
  bool _handleExtractTypeArguments(
      ir.StaticInvocation invocation, SourceInformation sourceInformation) {
    // Expand calls as follows:
    //
    //     r = extractTypeArguments<Map>(e, f)
    // -->
    //     environment = HInstanceEnvironment(e);
    //     T1 = HTypeEval( environment, 'Map.K');
    //     T2 = HTypeEval( environment, 'Map.V');
    //     r = f<T1, T2>();
    //
    // TODO(sra): Should we add a check before the variable extraction? We could
    // add a type check (which would permit `null`), or add an is-check with an
    // explicit throw.

    if (invocation.arguments.positional.length != 2) return false;
    if (invocation.arguments.named.isNotEmpty) return false;
    var types = invocation.arguments.types;
    if (types.length != 1) return false;

    // The type should be a single type name.
    ir.DartType type = types.first;
    DartType typeValue = dartTypes.eraseLegacy(
        localsHandler.substInContext(_elementMap.getDartType(type)));
    if (typeValue is! InterfaceType) return false;
    InterfaceType interfaceType = typeValue;
    if (!dartTypes.treatAsRawType(interfaceType)) return false;

    ClassEntity cls = interfaceType.element;
    InterfaceType thisType = _elementEnvironment.getThisType(cls);

    List<HInstruction> arguments =
        _visitPositionalArguments(invocation.arguments);

    HInstruction object = arguments[0];
    HInstruction closure = arguments[1];

    List<HInstruction> inputs = [closure];
    List<DartType> typeArguments = [];

    closedWorld.registerExtractTypeArguments(cls);
    HInstruction instanceType =
        HInstanceEnvironment(object, _abstractValueDomain.dynamicType);
    add(instanceType);
    TypeEnvironmentStructure envStructure =
        FullTypeEnvironmentStructure(classType: thisType);

    thisType.typeArguments.forEach((_typeVariable) {
      TypeVariableType variable = _typeVariable;
      typeArguments.add(variable);
      TypeRecipe recipe = TypeExpressionRecipe(variable);
      HInstruction typeEval = HTypeEval(
          instanceType, envStructure, recipe, _abstractValueDomain.dynamicType);
      add(typeEval);
      inputs.add(typeEval);
    });

    // TODO(sra): In compliance mode, insert a check that [closure] is a
    // function of N type arguments.

    Selector selector =
        Selector.callClosure(0, const <String>[], typeArguments.length);
    StaticType receiverStaticType =
        _getStaticType(invocation.arguments.positional[1]);
    AbstractValue receiverType = _abstractValueDomain
        .createFromStaticType(receiverStaticType.type,
            classRelation: receiverStaticType.relation, nullable: true)
        .abstractValue;
    push(HInvokeClosure(selector, receiverType, inputs,
        _abstractValueDomain.dynamicType, typeArguments));

    return true;
  }

  void _handleInvokeStaticForeign(
      ir.StaticInvocation invocation, MemberEntity member) {
    String name = member.name;
    if (name == 'JS') {
      _handleForeignJs(invocation);
    } else if (name == 'DART_CLOSURE_TO_JS') {
      _handleForeignDartClosureToJs(invocation, 'DART_CLOSURE_TO_JS');
    } else if (name == 'RAW_DART_FUNCTION_REF') {
      _handleForeignRawFunctionRef(invocation, 'RAW_DART_FUNCTION_REF');
    } else if (name == 'JS_GET_NAME') {
      _handleForeignJsGetName(invocation);
    } else if (name == 'JS_EMBEDDED_GLOBAL') {
      _handleForeignJsEmbeddedGlobal(invocation);
    } else if (name == 'JS_BUILTIN') {
      _handleForeignJsBuiltin(invocation);
    } else if (name == 'JS_GET_FLAG') {
      _handleForeignJsGetFlag(invocation);
    } else if (name == 'JS_EFFECT') {
      stack.add(graph.addConstantNull(closedWorld));
    } else if (name == 'JS_INTERCEPTOR_CONSTANT') {
      _handleJsInterceptorConstant(invocation);
    } else if (name == 'getInterceptor') {
      _handleForeignGetInterceptor(invocation);
    } else if (name == 'getJSArrayInteropRti') {
      _handleForeignGetJSArrayInteropRti(invocation);
    } else if (name == 'JS_STRING_CONCAT') {
      _handleJsStringConcat(invocation);
    } else if (name == '_createInvocationMirror') {
      _handleCreateInvocationMirror(invocation);
    } else if (name == 'TYPE_REF') {
      _handleForeignTypeRef(invocation);
    } else if (name == 'LEGACY_TYPE_REF') {
      _handleForeignLegacyTypeRef(invocation);
    } else if (name == 'createJsSentinel') {
      _handleForeignCreateJsSentinel(invocation);
    } else if (name == 'isJsSentinel') {
      _handleForeignIsJsSentinel(invocation);
    } else {
      reporter.internalError(
          _elementMap.getSpannable(targetElement, invocation),
          "Unknown foreign: ${name}");
    }
  }

  String _readStringLiteral(ir.Expression node) {
    if (node is ir.StringLiteral) {
      return node.value;
    } else if (node is ir.ConstantExpression &&
        node.constant is ir.StringConstant) {
      ir.StringConstant constant = node.constant;
      return constant.value;
    } else {
      return reporter.internalError(
          _elementMap.getSpannable(targetElement, node),
          "Unexpected string literal: "
          "${node is ir.ConstantExpression ? node.constant : node}");
    }
  }

  int _readIntLiteral(ir.Expression node) {
    if (node is ir.IntLiteral) {
      return node.value;
    } else if (node is ir.ConstantExpression &&
        node.constant is ir.IntConstant) {
      ir.IntConstant constant = node.constant;
      return constant.value;
    } else if (node is ir.ConstantExpression &&
        node.constant is ir.DoubleConstant) {
      ir.DoubleConstant constant = node.constant;
      assert(constant.value.floor() == constant.value,
          "Unexpected int literal value ${constant.value}.");
      return constant.value.toInt();
    } else {
      return reporter.internalError(
          _elementMap.getSpannable(targetElement, node),
          "Unexpected int literal: "
          "${node is ir.ConstantExpression ? node.constant : node}");
    }
  }

  void _handleCreateInvocationMirror(ir.StaticInvocation invocation) {
    String name = _readStringLiteral(invocation.arguments.positional[0]);
    ir.ListLiteral typeArgumentsLiteral = invocation.arguments.positional[1];
    List<DartType> typeArguments =
        typeArgumentsLiteral.expressions.map((ir.Expression expression) {
      ir.TypeLiteral typeLiteral = expression;
      return _elementMap.getDartType(typeLiteral.type);
    }).toList();

    ir.ListLiteral positionalArgumentsLiteral =
        invocation.arguments.positional[2];
    ir.Expression namedArgumentsLiteral = invocation.arguments.positional[3];
    Map<String, ir.Expression> namedArguments = {};
    int kind = _readIntLiteral(invocation.arguments.positional[4]);

    Name memberName = Name(name, _currentFrame.member.library);
    Selector selector;
    switch (kind) {
      case invocationMirrorGetterKind:
        selector = Selector.getter(memberName);
        break;
      case invocationMirrorSetterKind:
        selector = Selector.setter(memberName);
        break;
      case invocationMirrorMethodKind:
        if (memberName == Names.INDEX_NAME) {
          selector = Selector.index();
        } else if (memberName == Names.INDEX_SET_NAME) {
          selector = Selector.indexSet();
        } else {
          if (namedArgumentsLiteral is ir.MapLiteral) {
            namedArgumentsLiteral.entries.forEach((ir.MapLiteralEntry entry) {
              String key = _readStringLiteral(entry.key);
              namedArguments[key] = entry.value;
            });
          } else if (namedArgumentsLiteral is ir.ConstantExpression &&
              namedArgumentsLiteral.constant is ir.MapConstant) {
            ir.MapConstant constant = namedArgumentsLiteral.constant;
            for (ir.ConstantMapEntry entry in constant.entries) {
              ir.StringConstant key = entry.key;
              namedArguments[key.value] = ir.ConstantExpression(entry.value);
            }
          } else {
            reporter.internalError(
                computeSourceSpanFromTreeNode(invocation),
                "Unexpected named arguments value in createInvocationMirrror: "
                "${namedArgumentsLiteral}.");
          }
          CallStructure callStructure = CallStructure(
              positionalArgumentsLiteral.expressions.length,
              namedArguments.keys.toList(),
              typeArguments.length);
          if (Selector.isOperatorName(name)) {
            selector =
                Selector(SelectorKind.OPERATOR, memberName, callStructure);
          } else {
            selector = Selector.call(memberName, callStructure);
          }
        }
        break;
    }

    HConstant nameConstant = graph.addConstant(
        constant_system.createSymbol(closedWorld.commonElements, name),
        closedWorld);

    List<HInstruction> arguments = [];
    for (ir.Expression argument in positionalArgumentsLiteral.expressions) {
      argument.accept(this);
      arguments.add(pop());
    }
    if (namedArguments.isNotEmpty) {
      Map<String, HInstruction> namedValues = {};
      namedArguments.forEach((String name, ir.Expression value) {
        value.accept(this);
        namedValues[name] = pop();
      });
      for (String name in selector.callStructure.getOrderedNamedArguments()) {
        arguments.add(namedValues[name]);
      }
    }

    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(invocation, invocation);
    _addTypeArguments(arguments, typeArguments, sourceInformation);

    HInstruction argumentsInstruction = _buildLiteralList(arguments);
    add(argumentsInstruction);

    List<HInstruction> argumentNames = <HInstruction>[];
    for (String argumentName
        in selector.callStructure.getOrderedNamedArguments()) {
      ConstantValue argumentNameConstant =
          constant_system.createString(argumentName);
      argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld));
    }
    HInstruction argumentNamesInstruction = _buildLiteralList(argumentNames);
    add(argumentNamesInstruction);

    HInstruction typeArgumentCount =
        graph.addConstantInt(typeArguments.length, closedWorld);

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

    ConstantValue kindConstant =
        constant_system.createIntFromInt(selector.invocationMirrorKind);

    _pushStaticInvocation(
        _commonElements.createUnmangledInvocationMirror,
        [
          nameConstant,
          graph.addConstantStringFromName(internalName, closedWorld),
          graph.addConstant(kindConstant, closedWorld),
          argumentsInstruction,
          argumentNamesInstruction,
          typeArgumentCount,
        ],
        _abstractValueDomain.dynamicType,
        const <DartType>[],
        sourceInformation: sourceInformation);
  }

  bool _unexpectedForeignArguments(ir.StaticInvocation invocation,
      {int minPositional, int maxPositional, int typeArgumentCount = 0}) {
    String pluralizeArguments(int count, [String adjective = '']) {
      if (count == 0) return 'no ${adjective}arguments';
      if (count == 1) return 'one ${adjective}argument';
      if (count == 2) return 'two ${adjective}arguments';
      return '$count ${adjective}arguments';
    }

    String name() => invocation.target.name.text;

    ir.Arguments arguments = invocation.arguments;
    bool bad = false;
    if (arguments.types.length != typeArgumentCount) {
      String expected = pluralizeArguments(typeArgumentCount, 'type ');
      String actual = pluralizeArguments(arguments.types.length, 'type ');
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, invocation),
          MessageKind.GENERIC,
          {'text': "Error: '${name()}' takes $expected, not $actual."});
      bad = true;
    }
    if (arguments.positional.length < minPositional) {
      String phrase = pluralizeArguments(minPositional);
      if (maxPositional != minPositional) phrase = 'at least $phrase';
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, invocation),
          MessageKind.GENERIC,
          {'text': "Error: Too few arguments. '${name()}' takes $phrase."});
      bad = true;
    }
    if (maxPositional != null && arguments.positional.length > maxPositional) {
      String phrase = pluralizeArguments(maxPositional);
      if (maxPositional != minPositional) phrase = 'at most $phrase';
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, invocation),
          MessageKind.GENERIC,
          {'text': "Error: Too many arguments. '${name()}' takes $phrase."});
      bad = true;
    }
    if (arguments.named.isNotEmpty) {
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, invocation),
          MessageKind.GENERIC,
          {'text': "Error: '${name()}' does not take named arguments."});
      bad = true;
    }
    return bad;
  }

  /// Returns the value of the string argument. The argument must evaluate to a
  /// constant.  If there is an error, the error is reported and `null` is
  /// returned.
  String _foreignConstantStringArgument(
      ir.StaticInvocation invocation, int position, String methodName,
      [String adjective = '']) {
    ir.Expression argument = invocation.arguments.positional[position];
    argument.accept(this);
    HInstruction instruction = pop();

    if (!instruction.isConstantString()) {
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, argument),
          MessageKind.GENERIC, {
        'text': "Error: Expected String constant as ${adjective}argument "
            "to '$methodName'."
      });
      return null;
    }

    HConstant hConstant = instruction;
    StringConstantValue stringConstant = hConstant.constant;
    return stringConstant.stringValue;
  }

  void _handleForeignDartClosureToJs(
      ir.StaticInvocation invocation, String name) {
    // TODO(sra): Do we need to wrap the closure in something that saves the
    // current isolate?
    _handleForeignRawFunctionRef(invocation, name);
  }

  void _handleForeignRawFunctionRef(
      ir.StaticInvocation invocation, String name) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 1, maxPositional: 1)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    ir.Expression closure = invocation.arguments.positional.single;
    String problem = 'requires a static method or top-level method';

    bool handleTarget(ir.Procedure procedure) {
      ir.FunctionNode function = procedure.function;
      if (function != null &&
          function.requiredParameterCount ==
              function.positionalParameters.length &&
          function.namedParameters.isEmpty) {
        push(HFunctionReference(_elementMap.getMethod(procedure),
            _abstractValueDomain.dynamicType));
        return true;
      }
      problem = 'does not handle a closure with optional parameters';
      return false;
    }

    if (closure is ir.StaticGet) {
      ir.Member staticTarget = closure.target;
      if (staticTarget is ir.Procedure) {
        if (staticTarget.kind == ir.ProcedureKind.Method) {
          if (handleTarget(staticTarget)) {
            return;
          }
        }
      }
    } else if (closure is ir.ConstantExpression &&
        closure.constant is ir.StaticTearOffConstant) {
      ir.StaticTearOffConstant tearOff = closure.constant;
      ir.Procedure member = tearOff.target;
      if (handleTarget(member)) {
        return;
      }
    }

    reporter.reportErrorMessage(
        _elementMap.getSpannable(targetElement, invocation),
        MessageKind.GENERIC,
        {'text': "'$name' $problem."});
    stack.add(graph.addConstantNull(closedWorld)); // Result expected on stack.
    return;
  }

  void _handleForeignJsGetName(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 1, maxPositional: 1)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    ir.Node argument = invocation.arguments.positional.first;
    argument.accept(this);
    HInstruction instruction = pop();

    if (instruction is HConstant) {
      js.Name name = _getNameForJsGetName(instruction.constant, _namer);
      stack.add(graph.addConstantStringFromName(name, closedWorld));
      return;
    }

    reporter.reportErrorMessage(
        _elementMap.getSpannable(targetElement, argument),
        MessageKind.GENERIC,
        {'text': 'Error: Expected a JsGetName enum value.'});
    // Result expected on stack.
    stack.add(graph.addConstantNull(closedWorld));
  }

  int _extractEnumIndexFromConstantValue(
      ConstantValue constant, ClassEntity classElement) {
    if (constant is ConstructedConstantValue &&
        constant.type.element == classElement) {
      assert(constant.fields.length >= 1);
      for (var field in constant.fields.keys) {
        if (field.memberName.text == "index") {
          ConstantValue indexConstant = constant.fields[field];
          if (indexConstant is IntConstantValue) {
            return indexConstant.intValue.toInt();
          }
          break;
        }
      }
    }
    return null;
  }

  /// Returns the [js.Name] for the `JsGetName` [constant] value.
  js.Name _getNameForJsGetName(ConstantValue constant, ModularNamer namer) {
    int index = _extractEnumIndexFromConstantValue(
        constant, _commonElements.jsGetNameEnum);
    if (index == null) return null;
    return namer.getNameForJsGetName(
        CURRENT_ELEMENT_SPANNABLE, JsGetName.values[index]);
  }

  void _handleForeignJsEmbeddedGlobal(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 2, maxPositional: 2)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }
    String globalName = _foreignConstantStringArgument(
        invocation, 1, 'JS_EMBEDDED_GLOBAL', 'second ');
    js.Template expr = js.js.expressionTemplateYielding(
        _emitter.generateEmbeddedGlobalAccess(globalName));

    NativeBehavior nativeBehavior =
        _elementMap.getNativeBehaviorForJsEmbeddedGlobalCall(invocation);
    assert(
        nativeBehavior != null,
        failedAt(_elementMap.getSpannable(targetElement, invocation),
            "No NativeBehavior for $invocation"));

    AbstractValue ssaType =
        _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
    push(HForeignCode(expr, ssaType, const <HInstruction>[],
        nativeBehavior: nativeBehavior));
  }

  void _handleForeignJsBuiltin(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation, minPositional: 2)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    List<ir.Expression> arguments = invocation.arguments.positional;
    ir.Expression nameArgument = arguments[1];

    nameArgument.accept(this);
    HInstruction instruction = pop();

    js.Template template;
    if (instruction is HConstant) {
      template = _getJsBuiltinTemplate(instruction.constant, _emitter);
    }
    if (template == null) {
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, nameArgument),
          MessageKind.GENERIC,
          {'text': 'Error: Expected a JsBuiltin enum value.'});
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    List<HInstruction> inputs = [];
    for (ir.Expression argument in arguments.skip(2)) {
      argument.accept(this);
      inputs.add(pop());
    }

    NativeBehavior nativeBehavior =
        _elementMap.getNativeBehaviorForJsBuiltinCall(invocation);
    assert(
        nativeBehavior != null,
        failedAt(_elementMap.getSpannable(targetElement, invocation),
            "No NativeBehavior for $invocation"));

    AbstractValue ssaType =
        _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
    push(HForeignCode(template, ssaType, inputs,
        nativeBehavior: nativeBehavior));
  }

  /// Returns the [js.Template] for the `JsBuiltin` [constant] value.
  js.Template _getJsBuiltinTemplate(
      ConstantValue constant, ModularEmitter emitter) {
    int index = _extractEnumIndexFromConstantValue(
        constant, _commonElements.jsBuiltinEnum);
    if (index == null) return null;
    return _templateForBuiltin(JsBuiltin.values[index]);
  }

  /// Returns the JS template for the given [builtin].
  js.Template _templateForBuiltin(JsBuiltin builtin) {
    switch (builtin) {
      case JsBuiltin.dartObjectConstructor:
        ClassEntity objectClass = closedWorld.commonElements.objectClass;
        return js.js.expressionTemplateYielding(
            _emitter.constructorAccess(objectClass));

      case JsBuiltin.dartClosureConstructor:
        ClassEntity closureClass = closedWorld.commonElements.closureClass;
        // TODO(sra): Should add a dependency on the constructor used as a
        // token.
        registry
            // ignore:deprecated_member_use_from_same_package
            .registerInstantiatedClass(closureClass);
        return js.js.expressionTemplateYielding(
            _emitter.constructorAccess(closureClass));

      case JsBuiltin.getMetadata:
        String metadataAccess =
            _emitter.generateEmbeddedGlobalAccessString(METADATA);
        return js.js.expressionTemplateFor("$metadataAccess[#]");

      case JsBuiltin.getType:
        String typesAccess = _emitter.generateEmbeddedGlobalAccessString(TYPES);
        return js.js.expressionTemplateFor("$typesAccess[#]");

      default:
        reporter.internalError(
            NO_LOCATION_SPANNABLE, "Unhandled Builtin: $builtin");
        return null;
    }
  }

  void _handleForeignJsGetFlag(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 1, maxPositional: 1)) {
      stack.add(
          // Result expected on stack.
          graph.addConstantBool(false, closedWorld));
      return;
    }
    String name = _foreignConstantStringArgument(invocation, 0, 'JS_GET_FLAG');
    bool value = _getFlagValue(name);
    if (value == null) {
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, invocation),
          MessageKind.GENERIC,
          {'text': 'Error: Unknown internal flag "$name".'});
    } else {
      stack.add(graph.addConstantBool(value, closedWorld));
    }
  }

  void _handleJsInterceptorConstant(ir.StaticInvocation invocation) {
    // Single argument must be a TypeConstant which is converted into a
    // InterceptorConstant.
    if (_unexpectedForeignArguments(invocation,
        minPositional: 1, maxPositional: 1)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }
    ir.Expression argument = invocation.arguments.positional.single;
    argument.accept(this);
    HInstruction argumentInstruction = pop();
    if (argumentInstruction is HConstant) {
      ConstantValue argumentConstant = argumentInstruction.constant;
      if (argumentConstant is TypeConstantValue &&
          argumentConstant.representedType.withoutNullability
              is InterfaceType) {
        InterfaceType type =
            argumentConstant.representedType.withoutNullability;
        // TODO(sra): Check that type is a subclass of [Interceptor].
        ConstantValue constant = InterceptorConstantValue(type.element);
        HInstruction instruction = graph.addConstant(constant, closedWorld);
        stack.add(instruction);
        return;
      }
    }

    reporter.reportErrorMessage(
        _elementMap.getSpannable(targetElement, invocation),
        MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
    stack.add(graph.addConstantNull(closedWorld));
  }

  void _handleForeignGetInterceptor(ir.StaticInvocation invocation) {
    // Single argument is the intercepted object.
    if (_unexpectedForeignArguments(invocation,
        minPositional: 1, maxPositional: 1)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }
    ir.Expression argument = invocation.arguments.positional.single;
    argument.accept(this);
    HInstruction argumentInstruction = pop();

    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(invocation, invocation);
    HInstruction instruction =
        _interceptorFor(argumentInstruction, sourceInformation);
    stack.add(instruction);
  }

  void _handleForeignGetJSArrayInteropRti(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 0, maxPositional: 0)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }
    // TODO(sra): This should be JSArray<any>, created via
    // _elementEnvironment.getJsInteropType(_elementEnvironment.jsArrayClass);
    InterfaceType interopType = dartTypes
        .interfaceType(_commonElements.jsArrayClass, [dartTypes.dynamicType()]);
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(invocation, invocation);
    HInstruction rti =
        HLoadType.type(interopType, _abstractValueDomain.dynamicType)
          ..sourceInformation = sourceInformation;
    push(rti);
  }

  bool _equivalentToMissingRti(InterfaceType type) {
    assert(type.element == _commonElements.jsArrayClass);
    return dartTypes.isStrongTopType(type.typeArguments.single);
  }

  void _handleForeignJs(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 2, maxPositional: null, typeArgumentCount: 1)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    NativeBehavior nativeBehavior =
        _elementMap.getNativeBehaviorForJsCall(invocation);
    assert(
        nativeBehavior != null,
        failedAt(_elementMap.getSpannable(targetElement, invocation),
            "No NativeBehavior for $invocation"));

    List<HInstruction> inputs = [];
    for (ir.Expression argument in invocation.arguments.positional.skip(2)) {
      argument.accept(this);
      inputs.add(pop());
    }

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

    if (HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) {
      reporter.reportErrorMessage(
          _elementMap.getSpannable(targetElement, invocation),
          MessageKind.JS_PLACEHOLDER_CAPTURE);
    }

    AbstractValue ssaType =
        _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);

    SourceInformation sourceInformation = null;
    HInstruction code = HForeignCode(
        nativeBehavior.codeTemplate, ssaType, inputs,
        isStatement: !nativeBehavior.codeTemplate.isExpression,
        effects: nativeBehavior.sideEffects,
        nativeBehavior: nativeBehavior)
      ..sourceInformation = sourceInformation;
    push(code);

    DartType type = _getDartTypeIfValid(invocation.arguments.types.single);
    AbstractValue trustedMask = _typeBuilder.trustTypeMask(type);

    if (trustedMask != null) {
      // We only allow the type argument to narrow `dynamic`, which probably
      // comes from an unspecified return type in the NativeBehavior.
      if (_abstractValueDomain
          .containsAll(code.instructionType)
          .isPotentiallyTrue) {
        // Overwrite the type with the narrower type.
        code.instructionType = trustedMask;
      }
      // It is acceptable for the type parameter to be broader than the
      // specified type.
    }

    _maybeAddNullCheckOnJS(invocation);
  }

  /// If [invocation] is a `JS()` invocation in a web library and the static
  /// type is non-nullable, add a check to make sure it isn't null.
  void _maybeAddNullCheckOnJS(ir.StaticInvocation invocation) {
    if (options.nativeNullAssertions &&
        nodeIsInWebLibrary(invocation) &&
        closedWorld.dartTypes
            .isNonNullableIfSound(_getStaticType(invocation).type)) {
      HInstruction code = pop();
      push(HNullCheck(
          code, _abstractValueDomain.excludeNull(code.instructionType),
          sticky: true));
    }
  }

  void _handleJsStringConcat(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 2, maxPositional: 2)) {
      // Result expected on stack.
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }
    List<HInstruction> inputs = _visitPositionalArguments(invocation.arguments);
    push(HStringConcat(inputs[0], inputs[1], _abstractValueDomain.stringType));
  }

  void _handleForeignTypeRef(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 0, maxPositional: 0, typeArgumentCount: 1)) {
      stack.add(
          // Result expected on stack.
          graph.addConstantNull(closedWorld));
      return;
    }
    DartType type = _elementMap.getDartType(invocation.arguments.types.single);
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(invocation, invocation);
    push(HLoadType.type(type, _abstractValueDomain.dynamicType)
      ..sourceInformation = sourceInformation);
  }

  void _handleForeignLegacyTypeRef(ir.StaticInvocation invocation) {
    if (_unexpectedForeignArguments(invocation,
        minPositional: 0, maxPositional: 0, typeArgumentCount: 1)) {
      stack.add(
          // Result expected on stack.
          graph.addConstantNull(closedWorld));
      return;
    }
    DartType type = closedWorld.dartTypes
        .legacyType(_elementMap.getDartType(invocation.arguments.types.single));
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(invocation, invocation);
    push(HLoadType.type(type, _abstractValueDomain.dynamicType)
      ..sourceInformation = sourceInformation);
  }

  void _handleForeignCreateJsSentinel(ir.StaticInvocation invocation) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(invocation, invocation);
    stack.add(graph.addConstantLateSentinel(closedWorld,
        sourceInformation: sourceInformation));
  }

  void _handleForeignIsJsSentinel(ir.StaticInvocation invocation) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(invocation, invocation);
    HInstruction checkedExpression =
        _visitPositionalArguments(invocation.arguments).single;
    push(HIsLateSentinel(checkedExpression, _abstractValueDomain.boolType)
      ..sourceInformation = sourceInformation);
  }

  void _pushStaticInvocation(MemberEntity target, List<HInstruction> arguments,
      AbstractValue typeMask, List<DartType> typeArguments,
      {SourceInformation sourceInformation, InterfaceType instanceType}) {
    // TODO(redemption): Pass current node if needed.
    if (_tryInlineMethod(
        target, null, null, arguments, typeArguments, null, sourceInformation,
        instanceType: instanceType)) {
      return;
    }

    if (closedWorld.nativeData.isJsInteropMember(target)) {
      push(_invokeJsInteropFunction(target, arguments));
      return;
    }

    HInvokeStatic instruction = HInvokeStatic(
        target, arguments, typeMask, typeArguments,
        targetCanThrow: !_inferredData.getCannotThrow(target))
      ..sourceInformation = sourceInformation;

    if (_currentImplicitInstantiations.isNotEmpty) {
      instruction.instantiatedTypes =
          List<InterfaceType>.from(_currentImplicitInstantiations);
    }
    instruction.sideEffects = _inferredData.getSideEffectsOfElement(target);
    push(instruction);
  }

  void _pushDynamicInvocation(
      ir.Node node,
      StaticType staticReceiverType,
      AbstractValue receiverType,
      Selector selector,
      List<HInstruction> arguments,
      List<DartType> typeArguments,
      SourceInformation sourceInformation) {
    AbstractValue typeBound = _abstractValueDomain
        .createFromStaticType(staticReceiverType.type,
            classRelation: staticReceiverType.relation, nullable: true)
        .abstractValue;
    receiverType = receiverType == null
        ? typeBound
        : _abstractValueDomain.intersection(receiverType, typeBound);

    // 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, MemberEntity element) {
      bool isLength = selector.isGetter && selector.name == "length";
      if (isLength || selector.isIndex) {
        return closedWorld.classHierarchy.isSubtypeOf(
            element.enclosingClass, _commonElements.jsIndexableClass);
      } else if (selector.isIndexSet) {
        return closedWorld.classHierarchy.isSubtypeOf(
            element.enclosingClass, _commonElements.jsMutableIndexableClass);
      } else {
        return false;
      }
    }

    bool isOptimizableOperation(Selector selector, MemberEntity element) {
      ClassEntity 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 ||
          _commonElements.isJsStringSplit(element)) {
        return true;
      }
      return false;
    }

    MemberEntity element =
        closedWorld.locateSingleMember(selector, receiverType);
    if (element != null &&
        !element.isField &&
        !(element.isGetter && selector.isCall) &&
        !(element.isFunction && selector.isGetter) &&
        !isOptimizableOperation(selector, element)) {
      if (_tryInlineMethod(element, selector, receiverType, arguments,
          typeArguments, node, sourceInformation)) {
        return;
      }
    }

    HInstruction receiver = arguments.first;
    List<HInstruction> inputs = [];

    selector ??= _elementMap.getSelector(node);

    bool isIntercepted =
        closedWorld.interceptorData.isInterceptedSelector(selector);

    if (isIntercepted) {
      HInterceptor interceptor = _interceptorFor(receiver, sourceInformation);
      inputs.add(interceptor);
    }
    inputs.addAll(arguments);

    AbstractValue resultType =
        _typeInferenceMap.resultTypeOfSelector(selector, receiverType);
    HInvokeDynamic invoke;
    if (selector.isGetter) {
      invoke = HInvokeDynamicGetter(selector, receiverType, element, inputs,
          isIntercepted, resultType, sourceInformation);
    } else if (selector.isSetter) {
      invoke = HInvokeDynamicSetter(selector, receiverType, element, inputs,
          isIntercepted, resultType, sourceInformation);
    } else if (selector.isClosureCall) {
      assert(!isIntercepted);
      invoke = HInvokeClosure(
          selector, receiverType, inputs, resultType, typeArguments)
        ..sourceInformation = sourceInformation;
    } else {
      invoke = HInvokeDynamicMethod(selector, receiverType, inputs, resultType,
          typeArguments, sourceInformation,
          isIntercepted: isIntercepted);
    }
    invoke.instructionContext = _currentFrame.member;
    if (node is ir.InstanceInvocation) {
      invoke.isInvariant = node.isInvariant;
      invoke.isBoundsSafe = node.isBoundsSafe;
    }
    push(invoke);
  }

  HInstruction _invokeJsInteropFunction(
      FunctionEntity element, List<HInstruction> arguments) {
    assert(closedWorld.nativeData.isJsInteropMember(element));

    if (element is ConstructorEntity &&
        element.isFactoryConstructor &&
        _nativeData.isAnonymousJsInteropClass(element.enclosingClass)) {
      // Factory constructor that is syntactic sugar for creating a JavaScript
      // object literal.
      ConstructorEntity constructor = element;
      int i = 0;
      int positions = 0;
      List<HInstruction> filteredArguments = [];
      Map<String, js.Expression> parameterNameMap = {};

      // Note: we don't use `constructor.parameterStructure` here because
      // we don't elide parameters to js-interop external static targets
      // (including factory constructors.)
      // TODO(johnniwinther): can we elide those parameters? This should be
      // consistent with what we do with instance methods.
      ir.Procedure node = _elementMap.getMemberDefinition(constructor).node;
      List<ir.VariableDeclaration> namedParameters =
          node.function.namedParameters.toList();
      namedParameters.sort(nativeOrdering);
      for (ir.VariableDeclaration variable in namedParameters) {
        String parameterName = variable.name;
        // TODO(jacobr): consider throwing if parameter names do not match
        // names of properties in the class.
        HInstruction argument = arguments[i];
        if (argument != null) {
          filteredArguments.add(argument);
          var jsName = _nativeData.computeUnescapedJSInteropName(parameterName);
          parameterNameMap[jsName] = js.InterpolatedExpression(positions++);
        }
        i++;
      }
      var codeTemplate = js.Template(null, js.objectLiteral(parameterNameMap));

      var nativeBehavior = NativeBehavior()..codeTemplate = codeTemplate;
      registry.registerNativeMethod(element);
      // TODO(efortuna): Source information.
      return HForeignCode(
          codeTemplate, _abstractValueDomain.dynamicType, filteredArguments,
          nativeBehavior: nativeBehavior);
    }

    // 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.
    List<HInstruction> inputs = arguments.where((arg) => arg != null).toList();

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

    DartType type = element is ConstructorEntity
        ? _elementEnvironment.getThisType(element.enclosingClass)
        : _elementEnvironment.getFunctionType(element).returnType;
    // Native behavior effects here are similar to native/behavior.dart.
    // The return type is dynamic because we don't trust js-interop type
    // declarations.
    nativeBehavior.typesReturned.add(dartTypes.dynamicType());

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

    // It also includes any other JS interop type. Technically, a JS interop API
    // could return anything, so the sound thing to do would be to assume that
    // anything that may come from JS as instantiated. In order to prevent the
    // resulting code bloat (e.g. from `dart:html`), we unsoundly assume that
    // only JS interop types are returned.
    nativeBehavior.typesInstantiated.add(_elementEnvironment
        .getThisType(_commonElements.jsLegacyJavaScriptObjectClass));

    AbstractValue instructionType =
        _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);

    // TODO(efortuna): Add source information.
    return HInvokeExternal(element, inputs, instructionType, nativeBehavior,
        sourceInformation: null);
  }

  @override
  void visitFunctionNode(ir.FunctionNode node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCreate(node);
    ClosureRepresentationInfo closureInfo =
        _closureDataLookup.getClosureInfo(node.parent);
    ClassEntity closureClassEntity = closureInfo.closureClassEntity;

    List<HInstruction> capturedVariables = [];
    _elementEnvironment.forEachInstanceField(closureClassEntity,
        (_, FieldEntity field) {
      if (_fieldAnalysis.getFieldData(field).isElided) return;
      capturedVariables.add(localsHandler
          .readLocal(closureInfo.getLocalForField(_localsMap, field)));
    });

    AbstractValue type =
        _abstractValueDomain.createNonNullExact(closureClassEntity);
    // TODO(efortuna): Add source information here.
    push(HCreate(closureClassEntity, capturedVariables, type, sourceInformation,
        callMethod: closureInfo.callMethod));
  }

  @override
  void visitFunctionDeclaration(ir.FunctionDeclaration declaration) {
    assert(_isReachable);
    declaration.function.accept(this);
    Local local = _localsMap.getLocalVariable(declaration.variable);
    localsHandler.updateLocal(local, pop());
  }

  @override
  void visitFunctionExpression(ir.FunctionExpression funcExpression) {
    funcExpression.function.accept(this);
  }

  @override
  void visitInstantiation(ir.Instantiation node) {
    List<HInstruction> arguments = [];
    node.expression.accept(this);
    arguments.add(pop());

    // A generic function instantiation is created by calling a helper function
    // which takes the arguments.
    int typeArgumentCount = node.typeArguments.length;
    FunctionEntity target =
        _commonElements.getInstantiateFunction(typeArgumentCount);
    if (target == null) {
      reporter.internalError(
          _elementMap.getSpannable(targetElement, node),
          'Generic function instantiation not implemented for '
          '${typeArgumentCount} type arguments');
      stack.add(graph.addConstantNull(closedWorld));
      return;
    }

    StaticType expressionType = _getStaticType(node.expression);
    FunctionType functionType = expressionType.type.withoutNullability;
    bool typeArgumentsNeeded = _rtiNeed.methodNeedsTypeArguments(target);

    List<DartType> typeArguments = node.typeArguments
        .map((type) => typeArgumentsNeeded
            ? _elementMap.getDartType(type)
            : _commonElements.dynamicType)
        .toList();
    registry.registerGenericInstantiation(
        GenericInstantiation(functionType, typeArguments));

    // TODO(sra): Add instantiations to SourceInformationBuilder.
    SourceInformation sourceInformation = null;

    // TODO(47484): Allow callee to have different calling convention for type
    // arguments.
    if (typeArgumentsNeeded) {
      _addTypeArguments(arguments, typeArguments, sourceInformation);
    }

    bool targetCanThrow = false; // TODO(sra): Is this true?

    // TODO(sra): Use [_pushStaticInvocation] to allow inlining. We don't now
    // because inference can't tell that the call has no side-effects.
    HInstruction instruction = HInvokeStatic(
        target, arguments, _abstractValueDomain.functionType, <DartType>[],
        targetCanThrow: targetCanThrow);
    instruction.sourceInformation = sourceInformation;
    instruction.sideEffects
      ..clearAllDependencies()
      ..clearAllSideEffects();

    push(instruction);
  }

  void _handleMethodInvocation(
      ir.Expression node, ir.Expression receiver, ir.Arguments arguments) {
    receiver.accept(this);
    HInstruction receiverInstruction = pop();
    Selector selector = _elementMap.getSelector(node);
    List<DartType> typeArguments = [];
    selector = _fillDynamicTypeArguments(selector, arguments, typeArguments);
    _pushDynamicInvocation(
        node,
        _getStaticType(receiver),
        _typeInferenceMap.receiverTypeOfInvocation(node, _abstractValueDomain),
        selector,
        [
          receiverInstruction,
          ..._visitArgumentsForDynamicTarget(selector, arguments, typeArguments)
        ],
        typeArguments,
        _sourceInformationBuilder.buildCall(receiver, node));
  }

  @override
  void visitInstanceInvocation(ir.InstanceInvocation node) {
    _handleMethodInvocation(node, node.receiver, node.arguments);
  }

  @override
  void visitInstanceGetterInvocation(ir.InstanceGetterInvocation node) {
    _handleMethodInvocation(node, node.receiver, node.arguments);
  }

  @override
  void visitDynamicInvocation(ir.DynamicInvocation node) {
    _handleMethodInvocation(node, node.receiver, node.arguments);
  }

  @override
  void visitFunctionInvocation(ir.FunctionInvocation node) {
    _handleMethodInvocation(node, node.receiver, node.arguments);
  }

  @override
  void visitLocalFunctionInvocation(ir.LocalFunctionInvocation node) {
    Local local = _localsMap.getLocalVariable(node.variable);
    stack.add(localsHandler.readLocal(local,
        sourceInformation: _sourceInformationBuilder.buildGet(node)));
    HInstruction receiverInstruction = pop();
    Selector selector = _elementMap.getSelector(node);
    List<DartType> typeArguments = [];
    selector =
        _fillDynamicTypeArguments(selector, node.arguments, typeArguments);
    _pushDynamicInvocation(
        node,
        StaticType(_elementMap.getDartType(node.variable.type),
            computeClassRelationFromType(node.variable.type)),
        _typeInferenceMap.receiverTypeOfInvocation(node, _abstractValueDomain),
        selector,
        [
          receiverInstruction,
          ..._visitArgumentsForDynamicTarget(
              selector, node.arguments, typeArguments)
        ],
        typeArguments,
        _sourceInformationBuilder.buildCall(node, node));
  }

  void _handleEquals(ir.Expression node, ir.Expression left,
      HInstruction leftInstruction, HInstruction rightInstruction) {
    _pushDynamicInvocation(
        node,
        _getStaticType(left),
        _typeInferenceMap.receiverTypeOfInvocation(node, _abstractValueDomain),
        Selectors.equals,
        [leftInstruction, rightInstruction],
        const <DartType>[],
        _sourceInformationBuilder.buildCall(left, node));
  }

  @override
  void visitEqualsNull(ir.EqualsNull node) {
    node.expression.accept(this);
    HInstruction receiverInstruction = pop();
    _handleEquals(node, node.expression, receiverInstruction,
        graph.addConstantNull(closedWorld));
  }

  @override
  void visitEqualsCall(ir.EqualsCall node) {
    node.left.accept(this);
    HInstruction leftInstruction = pop();
    node.right.accept(this);
    HInstruction rightInstruction = pop();
    return _handleEquals(node, node.left, leftInstruction, rightInstruction);
  }

  HInterceptor _interceptorFor(
      HInstruction intercepted, SourceInformation sourceInformation) {
    HInterceptor interceptor =
        HInterceptor(intercepted, _abstractValueDomain.nonNullType)
          ..sourceInformation = sourceInformation;
    add(interceptor);
    return interceptor;
  }

  static ir.Class _containingClass(ir.TreeNode node) {
    while (node != null) {
      if (node is ir.Class) return node;
      node = node.parent;
    }
    return null;
  }

  void _generateSuperNoSuchMethod(
      ir.Expression invocation,
      String publicName,
      List<HInstruction> arguments,
      List<DartType> typeArguments,
      SourceInformation sourceInformation) {
    Selector selector = _elementMap.getSelector(invocation);
    ClassEntity containingClass =
        _elementMap.getClass(_containingClass(invocation));
    FunctionEntity noSuchMethod =
        _elementMap.getSuperNoSuchMethod(containingClass);

    ConstantValue nameConstant = constant_system.createString(publicName);

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

    var argumentsInstruction = _buildLiteralList(arguments);
    add(argumentsInstruction);

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

    ConstantValue kindConstant =
        constant_system.createIntFromInt(selector.invocationMirrorKind);

    _pushStaticInvocation(
        _commonElements.createInvocationMirror,
        [
          graph.addConstant(nameConstant, closedWorld),
          graph.addConstantStringFromName(internalName, closedWorld),
          graph.addConstant(kindConstant, closedWorld),
          argumentsInstruction,
          argumentNamesInstruction,
          graph.addConstantInt(typeArguments.length, closedWorld),
        ],
        _abstractValueDomain.dynamicType,
        typeArguments,
        sourceInformation: sourceInformation);

    _buildInvokeSuper(Selectors.noSuchMethod_, containingClass, noSuchMethod,
        [pop()], typeArguments, sourceInformation);
  }

  HInstruction _buildInvokeSuper(
      Selector selector,
      ClassEntity containingClass,
      MemberEntity target,
      List<HInstruction> arguments,
      List<DartType> typeArguments,
      SourceInformation sourceInformation) {
    HInstruction receiver =
        localsHandler.readThis(sourceInformation: sourceInformation);

    List<HInstruction> inputs = [];
    bool isIntercepted =
        closedWorld.interceptorData.isInterceptedSelector(selector);
    if (isIntercepted) {
      inputs.add(_interceptorFor(receiver, sourceInformation));
    }
    inputs.add(receiver);
    inputs.addAll(arguments);

    AbstractValue typeMask;
    if (selector.isGetter && target.isGetter ||
        !selector.isGetter && target is FunctionEntity) {
      typeMask = _typeInferenceMap.getReturnTypeOf(target);
    } else {
      typeMask = _abstractValueDomain.dynamicType;
    }
    HInstruction instruction = HInvokeSuper(target, containingClass, selector,
        inputs, isIntercepted, typeMask, typeArguments, sourceInformation,
        isSetter: selector.isSetter || selector.isIndexSet);
    instruction.sideEffects =
        _inferredData.getSideEffectsOfSelector(selector, null);
    push(instruction);
    return instruction;
  }

  @override
  void visitSuperPropertyGet(ir.SuperPropertyGet node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildGet(node);
    ir.Member target = getEffectiveSuperTarget(node.interfaceTarget);
    if (target == null) {
      // TODO(johnniwinther): Remove this when the CFE checks for missing
      //  concrete super targets.
      _generateSuperNoSuchMethod(node, _elementMap.getSelector(node).name,
          const <HInstruction>[], const <DartType>[], sourceInformation);
      return;
    }
    MemberEntity member = _elementMap.getMember(target);
    if (member.isField) {
      FieldAnalysisData fieldData = _fieldAnalysis.getFieldData(member);
      if (fieldData.isEffectivelyConstant) {
        ConstantValue value = fieldData.constantValue;
        stack.add(graph.addConstant(value, closedWorld,
            sourceInformation: sourceInformation));
        return;
      }
    }
    _buildInvokeSuper(
        _elementMap.getSelector(node),
        _elementMap.getClass(_containingClass(node)),
        member,
        const <HInstruction>[],
        const <DartType>[],
        sourceInformation);
  }

  @override
  void visitSuperMethodInvocation(ir.SuperMethodInvocation node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildCall(node, node);
    ir.Member superTarget = getEffectiveSuperTarget(node.interfaceTarget);
    if (superTarget == null) {
      // TODO(johnniwinther): Remove this when the CFE checks for missing
      //  concrete super targets.
      Selector selector = _elementMap.getSelector(node);
      List<DartType> typeArguments = <DartType>[];
      selector =
          _fillDynamicTypeArguments(selector, node.arguments, typeArguments);
      List<HInstruction> arguments = _visitArgumentsForDynamicTarget(
          selector, node.arguments, typeArguments);
      _generateSuperNoSuchMethod(
          node, selector.name, arguments, typeArguments, sourceInformation);
      return;
    }
    MemberEntity member = _elementMap.getMember(superTarget);
    List<DartType> typeArguments =
        _getStaticTypeArguments(member, node.arguments);

    MemberDefinition targetDefinition = _elementMap.getMemberDefinition(member);
    ir.Procedure target = targetDefinition.node;
    FunctionEntity function = member;
    List<HInstruction> arguments = _visitArgumentsForStaticTarget(
        target,
        target.function,
        function.parameterStructure,
        node.arguments,
        typeArguments,
        sourceInformation);
    _buildInvokeSuper(
        _elementMap.getSelector(node),
        _elementMap.getClass(_containingClass(node)),
        member,
        arguments,
        typeArguments,
        sourceInformation);
  }

  void _checkTypeBound(HInstruction typeInstruction, DartType bound,
      String variableName, String methodName) {
    HInstruction boundInstruction = _typeBuilder.analyzeTypeArgumentNewRti(
        localsHandler.substInContext(bound), sourceElement);

    HInstruction variableNameInstruction =
        graph.addConstantString(variableName, closedWorld);
    HInstruction methodNameInstruction =
        graph.addConstantString(methodName, closedWorld);
    FunctionEntity element = _commonElements.checkTypeBound;
    List<HInstruction> inputs = [
      typeInstruction,
      boundInstruction,
      variableNameInstruction,
      methodNameInstruction,
    ];
    HInstruction checkBound = HInvokeStatic(
        element, inputs, typeInstruction.instructionType, const <DartType>[]);
    add(checkBound);
  }

  @override
  void visitConstructorInvocation(ir.ConstructorInvocation node) {
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildNew(node);
    ir.Constructor target = node.target;
    if (node.isConst) {
      ConstantValue constant =
          _elementMap.getConstantValue(_memberContextNode, node);
      stack.add(graph.addConstant(constant, closedWorld,
          sourceInformation: sourceInformation));
      return;
    }

    ConstructorEntity constructor = _elementMap.getConstructor(target);
    ClassEntity cls = constructor.enclosingClass;
    AbstractValue typeMask = _abstractValueDomain.createNonNullExact(cls);
    InterfaceType instanceType = _elementMap.createInterfaceType(
        target.enclosingClass, node.arguments.types);
    instanceType = localsHandler.substInContext(instanceType);

    List<HInstruction> arguments = [];
    if (constructor.isGenerativeConstructor &&
        _nativeData.isNativeOrExtendsNative(constructor.enclosingClass) &&
        !_nativeData.isJsInteropMember(constructor)) {
      // Native class generative constructors take a pre-constructed object.
      arguments.add(graph.addConstantNull(closedWorld));
    }
    List<DartType> typeArguments =
        _getConstructorTypeArguments(constructor, node.arguments);
    arguments.addAll(closedWorld.nativeData.isJsInteropMember(constructor)
        ? _visitArgumentsForNativeStaticTarget(target.function, node.arguments)
        : _visitArgumentsForStaticTarget(
            target,
            target.function,
            constructor.parameterStructure,
            node.arguments,
            typeArguments,
            sourceInformation));
    // TODO(johnniwinther): Remove this when type arguments are passed to
    // constructors like calling a generic method.
    _addTypeArguments(arguments, _getClassTypeArguments(cls, node.arguments),
        sourceInformation);
    _addImplicitInstantiation(instanceType);
    _pushStaticInvocation(constructor, arguments, typeMask, typeArguments,
        sourceInformation: sourceInformation, instanceType: instanceType);
    _removeImplicitInstantiation(instanceType);
  }

  @override
  void visitIsExpression(ir.IsExpression node) {
    node.operand.accept(this);
    HInstruction expression = pop();
    _pushIsTest(node.type, expression, _sourceInformationBuilder.buildIs(node));
  }

  void _pushIsTest(ir.DartType type, HInstruction expression,
      SourceInformation sourceInformation) {
    // Note: The call to "unalias" this type like in the original SSA builder is
    // unnecessary in kernel because Kernel has no notion of typedef.
    // TODO(efortuna): Add test for this.

    if (type is ir.InvalidType) {
      // TODO(sra): Make InvalidType carry a message.
      _generateTypeError('invalid type', sourceInformation);
      pop();
      stack.add(graph.addConstantBool(true, closedWorld));
      return;
    }

    DartType typeValue =
        localsHandler.substInContext(_elementMap.getDartType(type));

    HInstruction rti =
        _typeBuilder.analyzeTypeArgumentNewRti(typeValue, sourceElement);
    AbstractValueWithPrecision checkedType =
        _abstractValueDomain.createFromStaticType(typeValue, nullable: false);

    push(HIsTest(
        typeValue, checkedType, expression, rti, _abstractValueDomain.boolType)
      ..sourceInformation = sourceInformation);
  }

  @override
  void visitThrow(ir.Throw node) {
    _visitThrowExpression(node.expression);
    if (_isReachable) {
      SourceInformation sourceInformation =
          _sourceInformationBuilder.buildThrow(node);
      _handleInTryStatement();
      push(HThrowExpression(_abstractValueDomain, pop(), sourceInformation));
      _isReachable = false;
    }
  }

  void _visitThrowExpression(ir.Expression expression) {
    bool old = _inExpressionOfThrow;
    try {
      _inExpressionOfThrow = true;
      expression.accept(this);
    } finally {
      _inExpressionOfThrow = old;
    }
  }

  @override
  void visitYieldStatement(ir.YieldStatement node) {
    node.expression.accept(this);
    add(HYield(_abstractValueDomain, pop(), node.isYieldStar,
        _sourceInformationBuilder.buildYield(node)));
  }

  @override
  void visitAwaitExpression(ir.AwaitExpression node) {
    node.operand.accept(this);
    HInstruction awaited = pop();
    // TODO(herhut): Improve this type.
    push(HAwait(awaited, _abstractValueDomain.dynamicType)
      ..sourceInformation = _sourceInformationBuilder.buildAwait(node));
  }

  @override
  void visitRethrow(ir.Rethrow node) {
    HInstruction exception = _rethrowableException;
    if (exception == null) {
      exception = graph.addConstantNull(closedWorld);
      reporter.internalError(_elementMap.getSpannable(targetElement, node),
          'rethrowableException should not be null.');
    }
    _handleInTryStatement();
    SourceInformation sourceInformation =
        _sourceInformationBuilder.buildThrow(node);
    _closeAndGotoExit(HThrow(_abstractValueDomain, exception, sourceInformation,
        isRethrow: true));
    // ir.Rethrow is an expression so we need to push a value - a constant with
    // no type.
    stack.add(graph.addConstantUnreachable(closedWorld));
  }

  @override
  void visitThisExpression(ir.ThisExpression node) {
    stack.add(localsHandler.readThis(
        sourceInformation: _sourceInformationBuilder.buildGet(node)));
  }

  @override
  void visitNot(ir.Not node) {
    node.operand.accept(this);
    push(HNot(popBoolified(), _abstractValueDomain.boolType)
      ..sourceInformation = _sourceInformationBuilder.buildUnary(node));
  }

  @override
  void visitStringConcatenation(ir.StringConcatenation stringConcat) {
    KernelStringBuilder stringBuilder = KernelStringBuilder(this);
    stringConcat.accept(stringBuilder);
    stack.add(stringBuilder.result);
  }

  @override
  void visitTryCatch(ir.TryCatch node) {
    TryCatchFinallyBuilder tryBuilder =
        TryCatchFinallyBuilder(this, _sourceInformationBuilder.buildTry(node));
    node.body.accept(this);
    tryBuilder
      ..closeTryBody()
      ..buildCatch(node)
      ..cleanUp();
  }

  /// `try { ... } catch { ... } finally { ... }` statements are a little funny
  /// because a try can have one or both of {catch|finally}. The way this is
  /// encoded in kernel AST are two separate classes with no common superclass
  /// aside from Statement. If a statement has both `catch` and `finally`
  /// clauses then it is encoded in kernel as so that the TryCatch is the body
  /// statement of the TryFinally. To produce more efficient code rather than
  /// nested try statements, the visitors avoid one potential level of
  /// recursion.
  @override
  void visitTryFinally(ir.TryFinally node) {
    TryCatchFinallyBuilder tryBuilder =
        TryCatchFinallyBuilder(this, _sourceInformationBuilder.buildTry(node));

    // We do these shenanigans to produce better looking code that doesn't
    // have nested try statements.
    if (node.body is ir.TryCatch) {
      ir.TryCatch tryCatch = node.body;
      tryCatch.body.accept(this);
      tryBuilder
        ..closeTryBody()
        ..buildCatch(tryCatch);
    } else {
      node.body.accept(this);
      tryBuilder.closeTryBody();
    }

    tryBuilder
      ..buildFinallyBlock(() {
        node.finalizer.accept(this);
      })
      ..cleanUp();
  }

  /// Try to inline [element] within the correct context of the builder. The
  /// insertion point is the state of the builder.
  bool _tryInlineMethod(
      FunctionEntity function,
      Selector selector,
      AbstractValue mask,
      List<HInstruction> providedArguments,
      List<DartType> typeArguments,
      ir.Node currentNode,
      SourceInformation sourceInformation,
      {InterfaceType instanceType}) {
    if (function.isExternal) {
      // Don't inline external methods; these should just fail at runtime.
      return false;
    }

    if (_nativeData.isJsInteropMember(function) &&
        !(function is ConstructorEntity && function.isFactoryConstructor)) {
      // We only inline factory JavaScript interop constructors.
      return false;
    }

    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).
    if (_inlineCache.markedAsNoInline(function)) return false;
    bool cachedCanBeInlined =
        _inlineCache.canInline(function, insideLoop: insideLoop);
    if (cachedCanBeInlined == false) return false;

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

      assert(
          selector != null ||
              function.isStatic ||
              function.isTopLevel ||
              function.isConstructor ||
              function is ConstructorBodyEntity,
          failedAt(function, "Missing selector for inlining of $function."));
      if (selector != null) {
        if (!selector.applies(function)) return false;
        if (mask != null &&
            _abstractValueDomain
                .isTargetingMember(mask, function, selector.memberName)
                .isDefinitelyFalse) {
          return false;
        }
      }

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

      // Don't inline operator== methods if the parameter can be null.
      if (function.name == '==') {
        if (providedArguments[1]
            .isNull(_abstractValueDomain)
            .isPotentiallyTrue) {
          return false;
        }
      }

      // Generative constructors of native classes should not be called directly
      // and have an extra argument that causes problems with inlining.
      if (function is ConstructorEntity &&
          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 is! ConstructorBodyEntity) {
        if (globalInferenceResults.resultOfMember(function).throwsAlways) {
          // TODO(johnniwinther): It seems wrong to set `isReachable` to `false`
          // since we are _not_ going to inline [function]. This has
          // implications in switch cases where we might need to insert a
          // `break` that was skipped due to `isReachable` being `false`.
          _isReachable = false;
          return false;
        }
      }

      return true;
    }

    bool doesNotContainCode(InlineData inlineData) {
      // A function with size 1 does not contain any code.
      return inlineData.canBeInlined(maxInliningNodes: 1);
    }

    bool reductiveHeuristic(InlineData inlineData) {
      // The call is on a path which is executed rarely, so inline only if it
      // does not make the program larger.
      if (_isCalledOnce(function)) {
        return inlineData.canBeInlined();
      }
      if (inlineData.canBeInlinedReductive(
          argumentCount: providedArguments.length)) {
        return true;
      }
      return doesNotContainCode(inlineData);
    }

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

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

      InlineData inlineData =
          _inlineDataCache.getInlineData(_elementMap, function);

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

      // Do not inline code that is rarely executed unless it reduces size.
      if (_inExpressionOfThrow || graph.isLazyInitializer) {
        return reductiveHeuristic(inlineData);
      }

      if (cachedCanBeInlined == true) {
        // We may have forced the inlining of some methods. Therefore check
        // if we can inline this method regardless of size.
        String reason;
        assert(
            (reason = inlineData.cannotBeInlinedReason(allowLoops: true)) ==
                null,
            failedAt(function, "Cannot inline $function: $reason"));
        return true;
      }

      int numParameters = function.parameterStructure.totalParameters;
      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;
      }

      bool markedTryInline = _inlineCache.markedAsTryInline(function);
      bool calledOnce = _isCalledOnce(function);
      // 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 (markedTryInline || calledOnce) {
        maxInliningNodes = null;
      }
      bool allowLoops = false;
      if (markedTryInline) {
        allowLoops = true;
      }

      bool canInline = inlineData.canBeInlined(
          maxInliningNodes: maxInliningNodes, allowLoops: allowLoops);
      if (markedTryInline) {
        if (canInline) {
          _inlineCache.markAsInlinable(function, insideLoop: true);
          _inlineCache.markAsInlinable(function, insideLoop: false);
        } else {
          _inlineCache.markAsNonInlinable(function, insideLoop: true);
          _inlineCache.markAsNonInlinable(function, insideLoop: false);
        }
      } else if (calledOnce) {
        // TODO(34203): We can't update the decision due to imprecision in the
        // calledOnce data, described in Issue 34203.
      } else {
        if (canInline) {
          _inlineCache.markAsInlinable(function, insideLoop: insideLoop);
        } else {
          if (_isFunctionCalledOnce(function)) {
            // TODO(34203): We can't update the decision due to imprecision in
            // the calledOnce data, described in Issue 34203.
          } else {
            _inlineCache.markAsNonInlinable(function, insideLoop: insideLoop);
          }
        }
      }
      return canInline;
    }

    void doInlining() {
      if (function.isConstructor) {
        registry.registerStaticUse(
            StaticUse.constructorInlining(function, instanceType));
      } else {
        assert(instanceType == null,
            "Unexpected instance type for $function: $instanceType");
        registry.registerStaticUse(
            StaticUse.methodInlining(function, typeArguments));
      }

      // Add an explicit null check on the receiver before doing the inlining.
      if (function.isInstanceMember &&
          function is! ConstructorBodyEntity &&
          (mask == null ||
              _abstractValueDomain.isNull(mask).isPotentiallyTrue)) {
        HNullCheck guard =
            HNullCheck(providedArguments[0], _abstractValueDomain.dynamicType)
              ..selector = selector
              ..sourceInformation = sourceInformation;
        add(guard);
        providedArguments[0] = guard;
      }
      List<HInstruction> compiledArguments = _completeCallArgumentsList(
          function, selector, providedArguments, currentNode);
      _enterInlinedMethod(function, compiledArguments, instanceType);
      _inlinedFrom(function, sourceInformation, () {
        if (!_isReachable) {
          _emitReturn(
              graph.addConstantUnreachable(closedWorld), sourceInformation);
        } else {
          _doInline(function);
        }
      });
      _leaveInlinedMethod();
    }

    if (meetsHardConstraints() && heuristicSayGoodToGo()) {
      doInlining();
      _infoReporter?.reportInlined(
          function,
          _inliningStack.isEmpty
              ? targetElement
              : _inliningStack.last.function);
      return true;
    }

    return false;
  }

  /// Returns a complete argument list for a call of [function].
  List<HInstruction> _completeCallArgumentsList(
      FunctionEntity function,
      Selector selector,
      List<HInstruction> providedArguments,
      ir.Node currentNode) {
    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 is ConstructorBodyEntity ||
        selector.isGetter) {
      // For these cases, the provided argument list is known to be complete.
      return providedArguments;
    } else {
      return _completeDynamicCallArgumentsList(
          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> _completeDynamicCallArgumentsList(Selector selector,
      FunctionEntity function, List<HInstruction> providedArguments) {
    assert(selector.applies(function));
    CallStructure callStructure = selector.callStructure;
    ParameterStructure parameterStructure = function.parameterStructure;
    List<String> selectorArgumentNames =
        selector.callStructure.getOrderedNamedArguments();
    List<HInstruction> compiledArguments = List<HInstruction>.filled(
        parameterStructure.totalParameters +
            parameterStructure.typeParameters +
            1,
        null); // Plus one for receiver.

    int compiledArgumentIndex = 0;

    // Copy receiver.
    compiledArguments[compiledArgumentIndex++] = providedArguments[0];

    /// Offset of positional arguments in [providedArguments].
    int positionalArgumentOffset = 1;

    /// Offset of named arguments in [providedArguments].
    int namedArgumentOffset = callStructure.positionalArgumentCount + 1;

    int positionalArgumentIndex = 0;
    int namedArgumentIndex = 0;

    _elementEnvironment.forEachParameter(function,
        (DartType type, String name, ConstantValue defaultValue) {
      if (positionalArgumentIndex < parameterStructure.positionalParameters) {
        if (positionalArgumentIndex < callStructure.positionalArgumentCount) {
          compiledArguments[compiledArgumentIndex++] = providedArguments[
              positionalArgumentOffset + positionalArgumentIndex++];
        } else {
          assert(defaultValue != null,
              failedAt(function, 'No constant computed for parameter $name'));
          compiledArguments[compiledArgumentIndex++] =
              graph.addConstant(defaultValue, closedWorld);
        }
      } else {
        // Example:
        //     void foo(a, {b, d, c})
        //     foo(0, d = 1, b = 2)
        //
        // providedArguments = [0, 2, 1]
        // selectorArgumentNames = [b, d]
        // parameterStructure.namedParameters = [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.
        if (namedArgumentIndex < selectorArgumentNames.length &&
            name == selectorArgumentNames[namedArgumentIndex]) {
          // The named argument was provided in the function invocation.
          compiledArguments[compiledArgumentIndex++] =
              providedArguments[namedArgumentOffset + namedArgumentIndex++];
        } else {
          assert(defaultValue != null,
              failedAt(function, 'No constant computed for parameter $name'));
          compiledArguments[compiledArgumentIndex++] =
              graph.addConstant(defaultValue, closedWorld);
        }
      }
    });
    if (_rtiNeed.methodNeedsTypeArguments(function)) {
      if (callStructure.typeArgumentCount ==
          parameterStructure.typeParameters) {
        /// Offset of type arguments in [providedArguments].
        int typeArgumentOffset = callStructure.argumentCount + 1;
        // Pass explicit type arguments.
        for (int typeArgumentIndex = 0;
            typeArgumentIndex < callStructure.typeArgumentCount;
            typeArgumentIndex++) {
          compiledArguments[compiledArgumentIndex++] =
              providedArguments[typeArgumentOffset + typeArgumentIndex];
        }
      } else {
        assert(callStructure.typeArgumentCount == 0);
        // Pass type variable bounds as type arguments.
        for (TypeVariableType typeVariable
            in _elementEnvironment.getFunctionTypeVariables(function)) {
          compiledArguments[compiledArgumentIndex++] =
              _computeTypeArgumentDefaultValue(function, typeVariable);
        }
      }
    }
    return compiledArguments;
  }

  HInstruction _computeTypeArgumentDefaultValue(
      FunctionEntity function, TypeVariableType typeVariable) {
    DartType bound =
        _elementEnvironment.getTypeVariableDefaultType(typeVariable.element);
    return _typeBuilder.analyzeTypeArgument(bound, function);
  }

  /// This method is invoked before inlining the body of [function] into this
  /// [SsaGraphBuilder].
  void _enterInlinedMethod(FunctionEntity function,
      List<HInstruction> compiledArguments, InterfaceType instanceType) {
    KernelInliningState state = KernelInliningState(
        function,
        _returnLocal,
        _returnType,
        stack,
        localsHandler,
        _inTryStatement,
        _isCalledOnce(function));
    _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);
  }

  /// 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(FunctionEntity function,
      List<HInstruction> compiledArguments, InterfaceType instanceType) {
    localsHandler = LocalsHandler(
        this,
        function,
        function,
        instanceType ?? _elementMap.getMemberThisType(function),
        _nativeData,
        _interceptorData);
    localsHandler.setupScope(function);

    CapturedScope scopeData = _closureDataLookup.getCapturedScope(function);
    bool forGenerativeConstructorBody = function is ConstructorBodyEntity;

    _returnLocal = SyntheticLocal("result", function, function);
    localsHandler.updateLocal(_returnLocal, graph.addConstantNull(closedWorld));

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

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

    ir.Member memberContextNode = _elementMap.getMemberContextNode(function);
    KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(function);
    forEachOrderedParameter(_elementMap, function,
        (ir.VariableDeclaration variable, {bool isElided}) {
      Local local = localsMap.getLocalVariable(variable);
      if (isElided) {
        localsHandler.updateLocal(
            local, _defaultValueForParameter(memberContextNode, variable));
        return;
      }
      if (forGenerativeConstructorBody &&
          scopeData.isBoxedVariable(_localsMap, local)) {
        // The parameter will be a field in the box passed as the last
        // parameter. So no need to have it.
        return;
      }
      HInstruction argument = compiledArguments[argumentIndex++];
      localsHandler.updateLocal(local, argument);
    });

    if (forGenerativeConstructorBody && scopeData.requiresContextBox) {
      HInstruction box = compiledArguments[argumentIndex++];
      assert(box is HCreateBox);
      // TODO(sra): Make inlining of closures work. We should always call
      // enterScope, and pass in the inlined 'this' as well as the 'box'.
      localsHandler.enterScope(scopeData, null,
          inlinedBox: box,
          forGenerativeConstructorBody: forGenerativeConstructorBody);
    }

    ClassEntity enclosing = function.enclosingClass;
    if ((function.isConstructor || function is ConstructorBodyEntity) &&
        _rtiNeed.classNeedsTypeArguments(enclosing)) {
      InterfaceType thisType = _elementEnvironment.getThisType(enclosing);
      thisType.typeArguments.forEach((_typeVariable) {
        TypeVariableType typeVariable = _typeVariable;
        HInstruction argument = compiledArguments[argumentIndex++];
        localsHandler.updateLocal(
            localsHandler.getTypeVariableAsLocal(typeVariable), argument);
      });
    }
    if (_rtiNeed.methodNeedsTypeArguments(function)) {
      bool inlineTypeParameters =
          function.parameterStructure.typeParameters == 0;
      for (TypeVariableType typeVariable
          in _elementEnvironment.getFunctionTypeVariables(function)) {
        HInstruction argument;
        if (inlineTypeParameters) {
          // Add inlined type parameters.
          argument = _computeTypeArgumentDefaultValue(function, typeVariable);
        } else {
          argument = compiledArguments[argumentIndex++];
        }
        localsHandler.updateLocal(
            localsHandler.getTypeVariableAsLocal(typeVariable), argument);
      }
    }
    assert(
        argumentIndex == compiledArguments.length ||
            !_rtiNeed.methodNeedsTypeArguments(function) &&
                compiledArguments.length - argumentIndex ==
                    function.parameterStructure.typeParameters,
        failedAt(
            function,
            "Only ${argumentIndex} of ${compiledArguments.length} "
            "arguments have been read from: ${compiledArguments} passed to "
            "$function."));

    _returnType = _elementEnvironment.getFunctionType(function).returnType;
    stack = <HInstruction>[];

    _insertCoverageCall(function);
  }

  void _leaveInlinedMethod() {
    HInstruction result = localsHandler.readLocal(_returnLocal);
    KernelInliningState state = _inliningStack.removeLast();
    _restoreState(state);
    stack.add(result);
  }

  void _restoreState(KernelInliningState state) {
    localsHandler = state.oldLocalsHandler;
    _returnLocal = state.oldReturnLocal;
    _inTryStatement = state.inTryStatement;
    _returnType = state.oldReturnType;
    assert(stack.isEmpty);
    stack = state.oldStack;
  }

  bool _providedArgumentsKnownToBeComplete(ir.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].
     */
    // TODO(redemption): Is this valid here?
    return currentNode is ir.ForInStatement;
  }

  void _emitReturn(
      HInstruction /*?*/ value, SourceInformation sourceInformation) {
    if (_inliningStack.isEmpty) {
      _closeAndGotoExit(
          HReturn(_abstractValueDomain, value, sourceInformation));
    } else {
      value ??= graph.addConstantNull(closedWorld);
      localsHandler.updateLocal(_returnLocal, value);
    }
  }

  void _doInline(FunctionEntity function) {
    _visitInlinedFunction(function);
  }

  /// Run this builder on the body of the [function] to be inlined.
  void _visitInlinedFunction(FunctionEntity function) {
    _potentiallyCheckInlinedParameterTypes(function);

    MemberDefinition definition = _elementMap.getMemberDefinition(function);
    switch (definition.kind) {
      case MemberKind.constructor:
        _buildConstructor(function, definition.node);
        return;
      case MemberKind.constructorBody:
        ir.Constructor constructor = definition.node;
        constructor.function.body.accept(this);
        return;
      case MemberKind.regular:
        ir.Node node = definition.node;
        if (node is ir.Constructor) {
          node.function.body.accept(this);
          return;
        } else if (node is ir.Procedure) {
          node.function.body.accept(this);
          return;
        }
        break;
      case MemberKind.closureCall:
        ir.LocalFunction node = definition.node;
        node.function.body.accept(this);
        return;
      default:
        break;
    }
    failedAt(function, "Unexpected inlined function: $definition");
  }

  /// Generates type tests for the parameters of the inlined function.
  void _potentiallyCheckInlinedParameterTypes(FunctionEntity function) {
    // TODO(sra): Incorporate properties of call site to help determine which
    // type parameters and value parameters need to be checked.
    bool trusted = false;
    if (function.isStatic ||
        function.isTopLevel ||
        function.isConstructor ||
        function is ConstructorBodyEntity) {
      // We inline static methods, top-level methods, constructors and
      // constructor bodies only from direct call sites.
      trusted = true;
    }

    if (!trusted) {
      _checkTypeVariableBounds(function);
    }

    KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(function);
    forEachOrderedParameter(_elementMap, function,
        (ir.VariableDeclaration variable, {bool isElided}) {
      Local parameter = localsMap.getLocalVariable(variable);
      HInstruction argument = localsHandler.readLocal(parameter);
      DartType type = localsMap.getLocalType(_elementMap, parameter);
      HInstruction checkedOrTrusted;
      if (trusted) {
        checkedOrTrusted =
            _typeBuilder.trustTypeOfParameter(function, argument, type);
      } else {
        checkedOrTrusted = _typeBuilder.potentiallyCheckOrTrustTypeOfParameter(
            function, argument, type);
      }
      checkedOrTrusted =
          _potentiallyAssertNotNull(function, variable, checkedOrTrusted, type);
      localsHandler.updateLocal(parameter, checkedOrTrusted);
    });
  }

  bool get _allInlinedFunctionsCalledOnce {
    return _inliningStack.isEmpty || _inliningStack.last.allFunctionsCalledOnce;
  }

  bool _isFunctionCalledOnce(FunctionEntity element) {
    // ConstructorBodyElements are not in the type inference graph.
    if (element is ConstructorBodyEntity) {
      // If there are no subclasses with constructors that have this constructor
      // as a superconstructor, it is called once by the generative
      // constructor's factory.  A simplified version is to check this is a
      // constructor body for a leaf class.
      ClassEntity class_ = element.enclosingClass;
      if (closedWorld.classHierarchy.isDirectlyInstantiated(class_)) {
        return !closedWorld.classHierarchy.isIndirectlyInstantiated(class_);
      }
      return false;
    }
    return globalInferenceResults.resultOfMember(element).isCalledOnce;
  }

  bool _isCalledOnce(FunctionEntity element) {
    return _allInlinedFunctionsCalledOnce && _isFunctionCalledOnce(element);
  }

  void _insertCoverageCall(MemberEntity element) {
    if (!options.experimentCallInstrumentation) return;
    if (element == _commonElements.traceHelper) return;
    // TODO(sigmund): create a better uuid for elements.
    HConstant idConstant = graph.addConstantInt(element.hashCode, closedWorld);
    n(e) => e == null ? '' : e.name;
    String name = "${n(element.library)}:${n(element.enclosingClass)}."
        "${n(element)}";
    HConstant nameConstant = graph.addConstantString(name, closedWorld);
    add(HInvokeStatic(_commonElements.traceHelper, [idConstant, nameConstant],
        _abstractValueDomain.dynamicType, const <DartType>[]));
  }
}

/// Data collected to create a constructor.
class ConstructorData {
  /// Inlined (super) constructors.
  final List<ir.Constructor> constructorChain = [];

  /// Initial values for all instance fields.
  final Map<FieldEntity, HInstruction> fieldValues = {};

  /// Classes for which type variables have been prepared.
  final Set<ClassEntity> includedClasses = {};
}

class KernelInliningState {
  final FunctionEntity function;
  final Local oldReturnLocal;
  final DartType oldReturnType;
  final List<HInstruction> oldStack;
  final LocalsHandler oldLocalsHandler;
  final bool inTryStatement;
  final bool allFunctionsCalledOnce;

  KernelInliningState(
      this.function,
      this.oldReturnLocal,
      this.oldReturnType,
      this.oldStack,
      this.oldLocalsHandler,
      this.inTryStatement,
      this.allFunctionsCalledOnce);

  @override
  String toString() => 'KernelInliningState($function,'
      'allFunctionsCalledOnce=$allFunctionsCalledOnce)';
}

/// Class in charge of building try, catch and/or finally blocks. This handles
/// the instructions that need to be output and the dominator calculation of
/// this sequence of code.
class TryCatchFinallyBuilder {
  final KernelSsaGraphBuilder kernelBuilder;
  final SourceInformation trySourceInformation;

  HBasicBlock enterBlock;
  HBasicBlock startTryBlock;
  HBasicBlock endTryBlock;
  HBasicBlock startCatchBlock;
  HBasicBlock endCatchBlock;
  HBasicBlock startFinallyBlock;
  HBasicBlock endFinallyBlock;
  HBasicBlock exitBlock;
  HTry tryInstruction;
  HLocalValue exception;

  /// True if the code surrounding this try statement was also part of a
  /// try/catch/finally statement.
  bool previouslyInTryStatement;

  SubGraph bodyGraph;
  SubGraph catchGraph;
  SubGraph finallyGraph;

  // The original set of locals that were defined before this try block.
  // 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 originalSavedLocals;

  TryCatchFinallyBuilder(this.kernelBuilder, this.trySourceInformation) {
    tryInstruction = HTry(kernelBuilder._abstractValueDomain);
    originalSavedLocals = LocalsHandler.from(kernelBuilder.localsHandler);
    enterBlock = kernelBuilder.openNewBlock();
    kernelBuilder.close(tryInstruction);
    previouslyInTryStatement = kernelBuilder._inTryStatement;
    kernelBuilder._inTryStatement = true;

    startTryBlock = kernelBuilder.graph.addNewBlock();
    kernelBuilder.open(startTryBlock);
  }

  void _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 = kernelBuilder.graph.blocks[i];
      var last = block.last;
      if (last is HExitTry) {
        block.addSuccessor(successor);
      }
    }
  }

  void _addOptionalSuccessor(block1, block2) {
    if (block2 != null) block1.addSuccessor(block2);
  }

  /// Helper function to set up basic block successors for try-catch-finally
  /// sequences.
  void _setBlockSuccessors() {
    // 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 ?? startFinallyBlock);
      endTryBlock.addSuccessor(exitBlock);
    }

    // The catch block has either the finally or the exit block as
    // successor.
    endCatchBlock?.addSuccessor(startFinallyBlock ?? 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(startCatchBlock);
    _addExitTrySuccessor(startFinallyBlock);
  }

  /// Build the finally{} clause of a try/{catch}/finally statement. Note this
  /// does not examine the body of the try clause, only the finally portion.
  void buildFinallyBlock(void buildFinalizer()) {
    kernelBuilder.localsHandler = LocalsHandler.from(originalSavedLocals);
    startFinallyBlock = kernelBuilder.graph.addNewBlock();
    kernelBuilder.open(startFinallyBlock);
    buildFinalizer();
    if (!kernelBuilder.isAborted()) {
      endFinallyBlock =
          kernelBuilder.close(HGoto(kernelBuilder._abstractValueDomain));
    }
    tryInstruction.finallyBlock = startFinallyBlock;
    finallyGraph = SubGraph(startFinallyBlock, kernelBuilder.lastOpenedBlock);
  }

  void closeTryBody() {
    // 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 (!kernelBuilder.isAborted()) {
      endTryBlock =
          kernelBuilder.close(HExitTry(kernelBuilder._abstractValueDomain));
    }
    bodyGraph = SubGraph(startTryBlock, kernelBuilder.lastOpenedBlock);
  }

  void buildCatch(ir.TryCatch tryCatch) {
    kernelBuilder.localsHandler = LocalsHandler.from(originalSavedLocals);
    startCatchBlock = kernelBuilder.graph.addNewBlock();
    kernelBuilder.open(startCatchBlock);
    // Note that the name of this local is irrelevant.
    SyntheticLocal local = kernelBuilder.localsHandler.createLocal('exception');
    exception =
        HLocalValue(local, kernelBuilder._abstractValueDomain.nonNullType)
          ..sourceInformation = trySourceInformation;
    kernelBuilder.add(exception);
    HInstruction oldRethrowableException = kernelBuilder._rethrowableException;
    kernelBuilder._rethrowableException = exception;

    AbstractValue unwrappedType = kernelBuilder._typeInferenceMap
        .getReturnTypeOf(kernelBuilder._commonElements.exceptionUnwrapper);
    // Global type analysis does not currently understand that strong mode
    // `Object` is not nullable, so is imprecise in the return type of the
    // unwrapper, which leads to unnecessary checks for 'on Object'.
    unwrappedType =
        kernelBuilder._abstractValueDomain.excludeNull(unwrappedType);
    kernelBuilder._pushStaticInvocation(
        kernelBuilder._commonElements.exceptionUnwrapper,
        [exception],
        unwrappedType,
        const <DartType>[],
        sourceInformation: trySourceInformation);
    HInvokeStatic unwrappedException = kernelBuilder.pop();
    unwrappedException.sideEffects
      ..clearAllDependencies()
      ..clearAllSideEffects();
    unwrappedException.targetCanThrow = false;
    tryInstruction.exception = exception;
    int catchesIndex = 0;

    void pushCondition(ir.Catch catchBlock) {
      kernelBuilder._pushIsTest(catchBlock.guard, unwrappedException,
          kernelBuilder._sourceInformationBuilder.buildCatch(catchBlock));
    }

    void visitThen() {
      ir.Catch catchBlock = tryCatch.catches[catchesIndex];
      catchesIndex++;
      if (catchBlock.exception != null) {
        Local exceptionVariable =
            kernelBuilder._localsMap.getLocalVariable(catchBlock.exception);
        kernelBuilder.localsHandler.updateLocal(
            exceptionVariable, unwrappedException,
            sourceInformation:
                kernelBuilder._sourceInformationBuilder.buildCatch(catchBlock));
      }
      if (catchBlock.stackTrace != null) {
        kernelBuilder._pushStaticInvocation(
            kernelBuilder._commonElements.traceFromException,
            [exception],
            kernelBuilder._typeInferenceMap.getReturnTypeOf(
                kernelBuilder._commonElements.traceFromException),
            const <DartType>[],
            sourceInformation:
                kernelBuilder._sourceInformationBuilder.buildCatch(catchBlock));
        HInstruction traceInstruction = kernelBuilder.pop();
        Local traceVariable =
            kernelBuilder._localsMap.getLocalVariable(catchBlock.stackTrace);
        kernelBuilder.localsHandler.updateLocal(traceVariable, traceInstruction,
            sourceInformation:
                kernelBuilder._sourceInformationBuilder.buildCatch(catchBlock));
      }
      catchBlock.body.accept(kernelBuilder);
    }

    void visitElse() {
      if (catchesIndex >= tryCatch.catches.length) {
        kernelBuilder._closeAndGotoExit(HThrow(
            kernelBuilder._abstractValueDomain,
            exception,
            exception.sourceInformation,
            isRethrow: true));
      } else {
        ir.Catch nextCatch = tryCatch.catches[catchesIndex];
        kernelBuilder._handleIf(
            visitCondition: () {
              pushCondition(nextCatch);
            },
            visitThen: visitThen,
            visitElse: visitElse,
            sourceInformation:
                kernelBuilder._sourceInformationBuilder.buildCatch(nextCatch));
      }
    }

    ir.Catch firstBlock = tryCatch.catches[catchesIndex];
    kernelBuilder._handleIf(
        visitCondition: () {
          pushCondition(firstBlock);
        },
        visitThen: visitThen,
        visitElse: visitElse,
        sourceInformation:
            kernelBuilder._sourceInformationBuilder.buildCatch(firstBlock));
    if (!kernelBuilder.isAborted()) {
      endCatchBlock =
          kernelBuilder.close(HGoto(kernelBuilder._abstractValueDomain));
    }

    kernelBuilder._rethrowableException = oldRethrowableException;
    tryInstruction.catchBlock = startCatchBlock;
    catchGraph = SubGraph(startCatchBlock, kernelBuilder.lastOpenedBlock);
  }

  void cleanUp() {
    exitBlock = kernelBuilder.graph.addNewBlock();
    _setBlockSuccessors();

    // Use the locals handler not altered by the catch and finally
    // blocks.
    kernelBuilder.localsHandler = originalSavedLocals;
    kernelBuilder.open(exitBlock);
    enterBlock.setBlockFlow(
        HTryBlockInformation(
            kernelBuilder.wrapStatementGraph(bodyGraph),
            exception,
            kernelBuilder.wrapStatementGraph(catchGraph),
            kernelBuilder.wrapStatementGraph(finallyGraph)),
        exitBlock);
    kernelBuilder._inTryStatement = previouslyInTryStatement;
  }
}

class KernelTypeBuilder extends TypeBuilder {
  final JsToElementMap _elementMap;

  KernelTypeBuilder(KernelSsaGraphBuilder builder, this._elementMap)
      : super(builder);

  @override
  KernelSsaGraphBuilder get builder => super.builder;

  @override
  ClassTypeVariableAccess computeTypeVariableAccess(MemberEntity member) {
    return _elementMap.getClassTypeVariableAccessForMember(member);
  }
}

class _ErroneousInitializerVisitor extends ir.Visitor<bool>
    with ir.VisitorDefaultValueMixin<bool> {
  _ErroneousInitializerVisitor();

  // TODO(30809): Use const constructor.
  static bool check(ir.Initializer initializer) =>
      initializer.accept(_ErroneousInitializerVisitor());

  @override
  bool defaultInitializer(ir.Node node) => false;

  @override
  bool visitInvalidInitializer(ir.InvalidInitializer node) => true;

  @override
  bool visitLocalInitializer(ir.LocalInitializer node) {
    return node.variable.initializer?.accept(this) ?? false;
  }

  // Expressions: Does the expression always throw?
  @override
  bool get defaultValue => false;

  @override
  bool visitThrow(ir.Throw node) => true;

  // TODO(sra): We might need to match other expressions that always throw but
  // in a subexpression.
}

/// Special [JumpHandler] implementation used to handle continue statements
/// targeting switch cases.
class KernelSwitchCaseJumpHandler extends SwitchCaseJumpHandler {
  KernelSwitchCaseJumpHandler(KernelSsaGraphBuilder builder, JumpTarget target,
      ir.SwitchStatement switchStatement, KernelToLocalsMap localsMap)
      : super(builder, target) {
    // The switch case indices must match those computed in
    // [KernelSsaBuilder.buildSwitchCaseConstants].
    // Switch indices are 1-based so we can bypass the synthetic loop when no
    // cases match simply by branching on the index (which defaults to null).
    // TODO
    int switchIndex = 1;
    for (ir.SwitchCase switchCase in switchStatement.cases) {
      JumpTarget continueTarget =
          localsMap.getJumpTargetForSwitchCase(switchCase);
      if (continueTarget != null) {
        targetIndexMap[continueTarget] = switchIndex;
        assert(builder.jumpTargets[continueTarget] == null);
        builder.jumpTargets[continueTarget] = this;
      }
      switchIndex++;
    }
  }
}

class StaticType {
  final DartType type;
  final ClassRelation relation;

  StaticType(this.type, this.relation);

  @override
  int get hashCode => type.hashCode * 13 + relation.hashCode * 19;

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    return other is StaticType &&
        type == other.type &&
        relation == other.relation;
  }

  @override
  String toString() => 'StaticType($type,$relation)';
}

class InlineData {
  bool isConstructor = false;
  bool codeAfterReturn = false;
  bool hasLoop = false;
  bool hasClosure = false;
  bool hasTry = false;
  bool hasAsyncAwait = false;
  bool hasThrow = false;
  bool hasLongString = false;
  bool hasExternalConstantConstructorCall = false;
  bool hasTypeArguments = false;
  bool hasArgumentDefaulting = false;
  bool hasCast = false;
  bool hasIf = false;
  List<int> argumentCounts = [];
  int regularNodeCount = 0;
  int callCount = 0;
  int reductiveNodeCount = 0;

  InlineData();

  InlineData.internal(
      {this.codeAfterReturn,
      this.hasLoop,
      this.hasClosure,
      this.hasTry,
      this.hasAsyncAwait,
      this.hasThrow,
      this.hasLongString,
      this.regularNodeCount,
      this.callCount});

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

  String cannotBeInlinedReason(
      {int maxInliningNodes, bool allowLoops = false}) {
    if (hasLoop && !allowLoops) {
      return 'loop';
    } else if (hasTry) {
      return 'try';
    } else if (hasClosure) {
      return 'closure';
    } else if (codeAfterReturn) {
      return 'code after return';
    } else if (hasAsyncAwait) {
      return 'async/await';
    } else if (maxInliningNodes != null &&
        regularNodeCount - 1 > maxInliningNodes) {
      return 'too many nodes (${regularNodeCount - 1}>$maxInliningNodes)';
    }
    return null;
  }

  bool canBeInlinedReductive({int argumentCount}) {
    return cannotBeInlinedReductiveReason(argumentCount: argumentCount) == null;
  }

  String cannotBeInlinedReductiveReason({int argumentCount}) {
    if (hasTry) {
      return 'try';
    } else if (hasClosure) {
      return 'closure';
    } else if (codeAfterReturn) {
      return 'code after return';
    } else if (hasAsyncAwait) {
      return 'async/await';
    } else if (callCount > 1) {
      return 'too many calls';
    } else if (hasThrow) {
      return 'throw';
    } else if (hasLongString) {
      return 'long string';
    } else if (hasExternalConstantConstructorCall) {
      return 'external const constructor';
    } else if (hasTypeArguments) {
      return 'type arguments';
    } else if (hasArgumentDefaulting) {
      return 'argument defaulting';
    } else if (hasCast) {
      return 'cast';
    } else if (hasIf) {
      return 'if';
    } else if (isConstructor) {
      return 'constructor';
    }
    for (int count in argumentCounts) {
      if (count > argumentCount) {
        return 'increasing arguments';
      }
    }
    // Node budget that covers one call and the passed-in arguments.
    // The +1 also allows a top-level zero-argument to be inlined if it
    // returns a constant.
    int maxInliningNodes = argumentCount + 1;
    if (reductiveNodeCount > maxInliningNodes) {
      return 'too many nodes (${reductiveNodeCount}>$maxInliningNodes)';
    }

    return null;
  }

  @override
  String toString() {
    StringBuffer sb = StringBuffer();
    sb.write('InlineData(');
    String comma = '';
    if (isConstructor) {
      sb.write('isConstructor');
      comma = ',';
    }
    if (codeAfterReturn) {
      sb.write(comma);
      sb.write('codeAfterReturn');
      comma = ',';
    }
    if (hasLoop) {
      sb.write(comma);
      sb.write('hasLoop');
      comma = ',';
    }
    if (hasClosure) {
      sb.write(comma);
      sb.write('hasClosure');
      comma = ',';
    }
    if (hasTry) {
      sb.write(comma);
      sb.write('hasTry');
      comma = ',';
    }
    if (hasAsyncAwait) {
      sb.write(comma);
      sb.write('hasAsyncAwait');
      comma = ',';
    }
    if (hasThrow) {
      sb.write(comma);
      sb.write('hasThrow');
      comma = ',';
    }
    if (hasLongString) {
      sb.write(comma);
      sb.write('hasLongString');
      comma = ',';
    }
    if (hasExternalConstantConstructorCall) {
      sb.write(comma);
      sb.write('hasExternalConstantConstructorCall');
      comma = ',';
    }
    if (hasTypeArguments) {
      sb.write(comma);
      sb.write('hasTypeArguments');
      comma = ',';
    }
    if (hasArgumentDefaulting) {
      sb.write(comma);
      sb.write('hasArgumentDefaulting');
      comma = ',';
    }
    if (hasCast) {
      sb.write(comma);
      sb.write('hasCast');
      comma = ',';
    }
    if (hasIf) {
      sb.write(comma);
      sb.write('hasIf');
      comma = ',';
    }
    if (argumentCounts.isNotEmpty) {
      sb.write(comma);
      sb.write('argumentCounts={${argumentCounts.join(',')}}');
      comma = ',';
    }
    sb.write(comma);
    sb.write('regularNodeCount=$regularNodeCount,');
    sb.write('callCount=$callCount,');
    sb.write('reductiveNodeCount=$reductiveNodeCount');
    sb.write(')');
    return sb.toString();
  }
}

class InlineDataCache {
  final bool enableUserAssertions;
  final bool omitImplicitCasts;

  InlineDataCache(
      {this.enableUserAssertions = false, this.omitImplicitCasts = false});

  final Map<FunctionEntity, InlineData> _cache = {};

  InlineData getInlineData(JsToElementMap elementMap, FunctionEntity function) {
    return _cache[function] ??= InlineWeeder.computeInlineData(
        elementMap, function,
        enableUserAssertions: enableUserAssertions,
        omitImplicitCasts: omitImplicitCasts);
  }
}

class InlineWeeder extends ir.Visitor<void> with ir.VisitorVoidMixin {
  // Invariant: *INSIDE_LOOP* > *OUTSIDE_LOOP*
  static const INLINING_NODES_OUTSIDE_LOOP = 15;
  static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 3;
  static const INLINING_NODES_INSIDE_LOOP = 34;
  static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4;

  final bool enableUserAssertions;
  final bool omitImplicitCasts;

  final InlineData data = InlineData();
  bool seenReturn = false;

  /// Whether node-count is collector to determine if a function can be
  /// inlined.
  bool countRegularNode = true;

  /// Whether node-count is collected to determine if inlining a function is
  /// very likely to reduce code size.
  ///
  /// For the reductive analysis:
  /// We allow the body to be a single function call that does not have any more
  /// inputs than the inlinee.
  ///
  /// We allow the body to be the return of an 'eligible' constant. A constant
  /// is 'eligible' if it is not large (e.g. a long string).
  ///
  /// We skip 'e as{TypeError} T' when the checks are omitted.
  //
  // TODO(sra): Consider slightly expansive simple constructors where all we
  // gain is a 'new' keyword, e.g. `new X.Foo(a)` vs `X.Foo$(a)`.
  //
  // TODO(25231): Make larger string constants eligible by sharing references.
  bool countReductiveNode = true;

  // When handling a generative constructor factory, the super constructor calls
  // are 'inlined', so tend to reuse the same parameters. [discountParameters]
  // is true to avoid double-counting these parameters.
  bool discountParameters = false;

  InlineWeeder(
      {this.enableUserAssertions = false, this.omitImplicitCasts = false});

  static InlineData computeInlineData(
      JsToElementMap elementMap, FunctionEntity function,
      {bool enableUserAssertions = false, bool omitImplicitCasts = false}) {
    InlineWeeder visitor = InlineWeeder(
        enableUserAssertions: enableUserAssertions,
        omitImplicitCasts: omitImplicitCasts);
    ir.FunctionNode node = getFunctionNode(elementMap, function);
    if (function.isConstructor) {
      visitor.data.isConstructor = true;
      MemberDefinition definition = elementMap.getMemberDefinition(function);
      ir.Node node = definition.node;
      if (node is ir.Constructor) {
        visitor.skipReductiveNodes(() {
          visitor.handleGenerativeConstructorFactory(node);
        });
        return visitor.data;
      }
    }
    node.accept(visitor);
    return visitor.data;
  }

  void skipRegularNodes(void f()) {
    bool oldCountRegularNode = countRegularNode;
    countRegularNode = false;
    f();
    countRegularNode = oldCountRegularNode;
  }

  void skipReductiveNodes(void f()) {
    bool oldCountReductiveNode = countReductiveNode;
    countReductiveNode = false;
    f();
    countReductiveNode = oldCountReductiveNode;
  }

  void registerRegularNode([int count = 1]) {
    if (countRegularNode) {
      data.regularNodeCount += count;
      if (seenReturn) {
        data.codeAfterReturn = true;
      }
    }
  }

  void registerReductiveNode() {
    if (countReductiveNode) {
      data.reductiveNodeCount++;
      if (seenReturn) {
        data.codeAfterReturn = true;
      }
    }
  }

  void unregisterReductiveNode() {
    if (countReductiveNode) {
      data.reductiveNodeCount--;
    }
  }

  void visit(ir.Node node) => node?.accept(this);

  void visitList(List<ir.Node> nodes) {
    for (ir.Node node in nodes) {
      visit(node);
    }
  }

  @override
  defaultNode(ir.Node node) {
    registerRegularNode();
    registerReductiveNode();
    node.visitChildren(this);
  }

  @override
  visitConstantExpression(ir.ConstantExpression node) {
    registerRegularNode();
    registerReductiveNode();
    ir.Constant constant = node.constant;
    // Avoid copying long strings into call site.
    if (constant is ir.StringConstant && isLongString(constant.value)) {
      data.hasLongString = true;
    }
  }

  @override
  visitReturnStatement(ir.ReturnStatement node) {
    registerRegularNode();
    node.visitChildren(this);
    seenReturn = true;
  }

  @override
  visitThrow(ir.Throw node) {
    registerRegularNode();
    data.hasThrow = true;
    node.visitChildren(this);
  }

  _handleLoop(ir.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.
    data.hasLoop = true;
    node.visitChildren(this);
  }

  @override
  visitForStatement(ir.ForStatement node) {
    _handleLoop(node);
  }

  @override
  visitForInStatement(ir.ForInStatement node) {
    _handleLoop(node);
  }

  @override
  visitWhileStatement(ir.WhileStatement node) {
    _handleLoop(node);
  }

  @override
  visitDoStatement(ir.DoStatement node) {
    _handleLoop(node);
  }

  @override
  visitTryCatch(ir.TryCatch node) {
    data.hasTry = true;
  }

  @override
  visitTryFinally(ir.TryFinally node) {
    data.hasTry = true;
  }

  @override
  visitFunctionExpression(ir.FunctionExpression node) {
    registerRegularNode();
    data.hasClosure = true;
  }

  @override
  visitFunctionDeclaration(ir.FunctionDeclaration node) {
    registerRegularNode();
    data.hasClosure = true;
  }

  @override
  visitFunctionNode(ir.FunctionNode node) {
    if (node.asyncMarker != ir.AsyncMarker.Sync) {
      data.hasAsyncAwait = true;
    }
    // TODO(sra): Cost of parameter checking?
    skipReductiveNodes(() {
      visitList(node.typeParameters);
      visitList(node.positionalParameters);
      visitList(node.namedParameters);
      visit(node.returnType);
    });
    visit(node.body);
  }

  @override
  visitConditionalExpression(ir.ConditionalExpression 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.
    ir.Expression condition = node.condition;
    visit(condition);
    int commonPrefixCount = data.regularNodeCount;

    visit(node.then);
    int thenCount = data.regularNodeCount - commonPrefixCount;

    data.regularNodeCount = commonPrefixCount;
    visit(node.otherwise);
    int elseCount = data.regularNodeCount - commonPrefixCount;

    data.regularNodeCount = commonPrefixCount + thenCount + elseCount;
    if (condition is ir.VariableGet &&
        condition.variable.parent is ir.FunctionNode) {
      data.regularNodeCount =
          commonPrefixCount + (thenCount > elseCount ? thenCount : elseCount);
    }
    // This is last so that [tooDifficult] is always updated.
    registerRegularNode();
    registerReductiveNode();
    skipRegularNodes(() => visit(node.staticType));
  }

  @override
  visitAssertInitializer(ir.AssertInitializer node) {
    if (!enableUserAssertions) return;
    node.visitChildren(this);
  }

  @override
  visitAssertStatement(ir.AssertStatement node) {
    if (!enableUserAssertions) return;
    defaultNode(node);
  }

  void registerCall() {
    ++data.callCount;
  }

  @override
  visitEmptyStatement(ir.EmptyStatement node) {
    registerRegularNode();
  }

  @override
  visitExpressionStatement(ir.ExpressionStatement node) {
    registerRegularNode();
    node.visitChildren(this);
  }

  @override
  visitBlock(ir.Block node) {
    registerRegularNode();
    node.visitChildren(this);
  }

  /// Returns `true` if [value] is considered a long string for which copying
  /// should be avoided.
  bool isLongString(String value) => value.length > 14;

  @override
  visitStringLiteral(ir.StringLiteral node) {
    registerRegularNode();
    registerReductiveNode();
    // Avoid copying long strings into call site.
    if (isLongString(node.value)) {
      data.hasLongString = true;
    }
  }

  @override
  visitInstanceGet(ir.InstanceGet node) {
    registerCall();
    registerRegularNode();
    registerReductiveNode();
    skipReductiveNodes(() => visit(node.name));
    visit(node.receiver);
  }

  @override
  visitInstanceTearOff(ir.InstanceTearOff node) {
    registerCall();
    registerRegularNode();
    registerReductiveNode();
    skipReductiveNodes(() => visit(node.name));
    visit(node.receiver);
  }

  @override
  visitDynamicGet(ir.DynamicGet node) {
    registerCall();
    registerRegularNode();
    registerReductiveNode();
    skipReductiveNodes(() => visit(node.name));
    visit(node.receiver);
  }

  @override
  visitInstanceSet(ir.InstanceSet node) {
    registerCall();
    registerRegularNode();
    registerReductiveNode();
    skipReductiveNodes(() => visit(node.name));
    visit(node.receiver);
    visit(node.value);
  }

  @override
  visitDynamicSet(ir.DynamicSet node) {
    registerCall();
    registerRegularNode();
    registerReductiveNode();
    skipReductiveNodes(() => visit(node.name));
    visit(node.receiver);
    visit(node.value);
  }

  @override
  visitVariableGet(ir.VariableGet node) {
    if (discountParameters && node.variable.parent is ir.FunctionNode) return;
    registerRegularNode();
    registerReductiveNode();
    skipReductiveNodes(() => visit(node.promotedType));
  }

  @override
  visitThisExpression(ir.ThisExpression node) {
    registerRegularNode();
    registerReductiveNode();
  }

  @override
  visitStaticGet(ir.StaticGet node) {
    // Assume lazy-init static, loaded via a call: `$.$get$foo()`.
    registerCall();
    registerRegularNode();
    registerReductiveNode();
  }

  @override
  visitConstructorInvocation(ir.ConstructorInvocation node) {
    registerRegularNode();
    registerReductiveNode();
    if (node.isConst) {
      // A const constructor call compiles to a constant pool reference.
      skipReductiveNodes(() => node.visitChildren(this));
    } else {
      registerCall();
      _processArguments(node.arguments, node.target?.function);
    }
  }

  @override
  visitStaticInvocation(ir.StaticInvocation node) {
    registerRegularNode();
    if (node.isConst) {
      data.hasExternalConstantConstructorCall = true;
      skipReductiveNodes(() => node.visitChildren(this));
    } else {
      registerCall();
      registerReductiveNode();
      _processArguments(node.arguments, node.target?.function);
    }
  }

  @override
  visitInstanceInvocation(ir.InstanceInvocation node) {
    registerRegularNode();
    registerReductiveNode();
    registerCall();
    visit(node.receiver);
    skipReductiveNodes(() => visit(node.name));
    _processArguments(node.arguments, null);
  }

  @override
  visitInstanceGetterInvocation(ir.InstanceGetterInvocation node) {
    registerRegularNode();
    registerReductiveNode();
    registerCall();
    visit(node.receiver);
    skipReductiveNodes(() => visit(node.name));
    _processArguments(node.arguments, null);
  }

  @override
  visitDynamicInvocation(ir.DynamicInvocation node) {
    registerRegularNode();
    registerReductiveNode();
    registerCall();
    visit(node.receiver);
    skipReductiveNodes(() => visit(node.name));
    _processArguments(node.arguments, null);
  }

  @override
  visitFunctionInvocation(ir.FunctionInvocation node) {
    registerRegularNode();
    registerReductiveNode();
    registerCall();
    visit(node.receiver);
    skipReductiveNodes(() => visit(node.name));
    _processArguments(node.arguments, null);
  }

  @override
  visitLocalFunctionInvocation(ir.LocalFunctionInvocation node) {
    registerRegularNode();
    registerReductiveNode();
    registerCall();
    _processArguments(node.arguments, null);
    // Account for the implicit access to the local variable:
    registerRegularNode();
    registerReductiveNode();
  }

  @override
  visitEqualsNull(ir.EqualsNull node) {
    registerRegularNode();
    registerReductiveNode();
    visit(node.expression);
  }

  @override
  visitEqualsCall(ir.EqualsCall node) {
    registerRegularNode();
    registerReductiveNode();
    registerCall();
    visit(node.left);
    visit(node.right);
  }

  _processArguments(ir.Arguments arguments, ir.FunctionNode target) {
    registerRegularNode();
    if (arguments.types.isNotEmpty) {
      data.hasTypeArguments = true;
      skipReductiveNodes(() => visitList(arguments.types));
    }
    int count = arguments.positional.length + arguments.named.length;
    data.argumentCounts.add(count);

    if (target != null) {
      // Disallow defaulted optional arguments since they will be passed
      // explicitly.
      if (target.positionalParameters.length + target.namedParameters.length >
          count) {
        data.hasArgumentDefaulting = true;
      }
    }

    visitList(arguments.positional);
    for (ir.NamedExpression expression in arguments.named) {
      registerRegularNode();
      expression.value.accept(this);
    }
  }

  @override
  visitAsExpression(ir.AsExpression node) {
    registerRegularNode();
    visit(node.operand);
    skipReductiveNodes(() => visit(node.type));
    if (!(node.isTypeError && omitImplicitCasts)) {
      data.hasCast = true;
    }
  }

  @override
  visitVariableDeclaration(ir.VariableDeclaration node) {
    registerRegularNode();
    skipReductiveNodes(() {
      visitList(node.annotations);
      visit(node.type);
    });
    visit(node.initializer);

    // A local variable is an alias for the initializer expression.
    if (node.initializer != null) {
      unregisterReductiveNode(); // discount one reference to the variable.
    }
  }

  @override
  visitIfStatement(ir.IfStatement node) {
    registerRegularNode();
    node.visitChildren(this);
    data.hasIf = true;
  }

  void handleGenerativeConstructorFactory(ir.Constructor node) {
    // Generative constructors are compiled to a factory constructor which
    // contains inlined all the initializations up the inheritance chain and
    // then call each of the constructor bodies down the inheritance chain.
    ir.Constructor constructor = node;

    Set<ir.Field> initializedFields = {};
    bool hasCallToSomeConstructorBody = false;

    inheritance_loop:
    while (constructor != null) {
      ir.Constructor superConstructor;
      for (var initializer in constructor.initializers) {
        if (initializer is ir.RedirectingInitializer) {
          // Discount the size of the arguments by references that are
          // pass-through.
          // TODO(sra): Need to add size of defaulted arguments.
          var discountParametersOld = discountParameters;
          discountParameters = true;
          initializer.arguments.accept(this);
          discountParameters = discountParametersOld;
          constructor = initializer.target;
          continue inheritance_loop;
        } else if (initializer is ir.SuperInitializer) {
          superConstructor = initializer.target;
          // Discount the size of the arguments by references that are
          // pass-through.
          // TODO(sra): Need to add size of defaulted arguments.
          var discountParametersOld = discountParameters;
          discountParameters = true;
          initializer.arguments.accept(this);
          discountParameters = discountParametersOld;
        } else if (initializer is ir.FieldInitializer) {
          initializedFields.add(initializer.field);
          initializer.value.accept(this);
        } else if (initializer is ir.AssertInitializer) {
          if (enableUserAssertions) {
            initializer.accept(this);
          }
        } else {
          initializer.accept(this);
        }
      }

      _handleFields(constructor.enclosingClass, initializedFields);

      // There will be a call to the constructor's body, which might be empty
      // and inlined away.
      var function = constructor.function;
      var body = function.body;
      if (!isEmptyBody(body)) {
        // All of the parameters are passed to the body.
        int parameterCount = function.positionalParameters.length +
            function.namedParameters.length +
            function.typeParameters.length;

        hasCallToSomeConstructorBody = true;
        registerCall();
        // A body call looks like "t.Body$(arguments);", i.e. an expression
        // statement with an instance member call, but the receiver is not
        // counted in the arguments. I'm guessing about 6 nodes for this.
        registerRegularNode(
            6 + parameterCount * INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR);

        // We can't inline a generative constructor factory when one of the
        // bodies rewrites the environment to put locals or parameters into a
        // box. The box is created in the generative constructor factory since
        // the box may be shared between closures in the initializer list and
        // closures in the constructor body.
        var bodyVisitor = InlineWeederBodyClosure();
        body.accept(bodyVisitor);
        if (bodyVisitor.tooDifficult) {
          data.hasClosure = true;
        }
      }

      if (superConstructor != null) {
        // The class of the super-constructor may not be the supertype class. In
        // this case, we must go up the class hierarchy until we reach the class
        // containing the super-constructor.
        ir.Supertype supertype = constructor.enclosingClass.supertype;
        while (supertype.classNode != superConstructor.enclosingClass) {
          _handleFields(supertype.classNode, initializedFields);
          supertype = supertype.classNode.supertype;
        }
      }
      constructor = superConstructor;
    }

    // In addition to the initializer expressions and body calls, there is an
    // allocator call.
    if (hasCallToSomeConstructorBody) {
      // A temporary is requried so we have
      //
      //     t=new ...;
      //     ...;
      //     use(t);
      //
      // I'm guessing it takes about 4 nodes to introduce the temporary and
      // assign it.
      registerRegularNode(4); // A temporary is requried.
    }
    // The initial field values are passed to the allocator.
    registerRegularNode(
        initializedFields.length * INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR);
  }

  void _handleFields(ir.Class cls, Set<ir.Field> initializedFields) {
    for (ir.Field field in cls.fields) {
      if (!field.isInstanceMember) continue;
      ir.Expression initializer = field.initializer;
      if (initializer == null ||
          initializer is ir.ConstantExpression &&
              initializer.constant is ir.PrimitiveConstant ||
          initializer is ir.BasicLiteral) {
        // Simple field initializers happen in the allocator, so do not
        // contribute to the size of the generative constructor factory.
        // TODO(sra): Use FieldInfo which tells us if the field is elided or
        // initialized in the allocator.
        continue;
      }
      if (!initializedFields.add(field)) continue;
      initializer.accept(this);
    }
    // If [cls] is a mixin application, include fields from mixed in class.
    if (cls.mixedInType != null) {
      _handleFields(cls.mixedInType.classNode, initializedFields);
    }
  }

  bool isEmptyBody(ir.Statement body) {
    if (body is ir.EmptyStatement) return true;
    if (body is ir.Block) return body.statements.every(isEmptyBody);
    if (body is ir.AssertStatement && !enableUserAssertions) return true;
    return false;
  }
}

/// Visitor to detect environment-rewriting that prevents inlining
/// (e.g. closures).
class InlineWeederBodyClosure extends ir.Visitor<void>
    with ir.VisitorVoidMixin {
  bool tooDifficult = false;

  InlineWeederBodyClosure();

  @override
  defaultNode(ir.Node node) {
    if (tooDifficult) return;
    node.visitChildren(this);
  }

  @override
  void visitFunctionExpression(ir.FunctionExpression node) {
    tooDifficult = true;
  }

  @override
  void visitFunctionDeclaration(ir.FunctionDeclaration node) {
    tooDifficult = true;
  }

  @override
  void visitFunctionNode(ir.FunctionNode node) {
    assert(false);
    if (node.asyncMarker != ir.AsyncMarker.Sync) {
      tooDifficult = true;
      return;
    }
    node.visitChildren(this);
  }
}
