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

import 'dart:collection' show Queue;

// ignore: implementation_imports
import 'package:front_end/src/api_unstable/dart2js.dart' show Link;

import '../common.dart';
import '../common/elements.dart' show JCommonElements;
import '../common/metrics.dart';
import '../common/names.dart';
import '../common/codegen.dart' show CodegenRegistry;
import '../common/tasks.dart' show CompilerTask;
import '../constants/constant_system.dart' as constant_system;
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/jumps.dart';
import '../elements/types.dart';
import '../inferrer/abstract_value_domain.dart';
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/interceptor_data.dart';
import '../js_backend/codegen_inputs.dart' show CodegenInputs;
import '../js_backend/native_data.dart';
import '../js_backend/namer.dart' show ModularNamer;
import '../js_backend/runtime_types_codegen.dart';
import '../js_backend/runtime_types_new.dart'
    show RecipeEncoder, RecipeEncoding, indexTypeVariable;
import '../js_backend/specialized_checks.dart';
import '../js_backend/type_reference.dart' show TypeReference;
import '../js_emitter/js_emitter.dart' show ModularEmitter;
import '../js_model/elements.dart' show JGeneratorBody;
import '../js_model/js_world.dart' show JClosedWorld;
import '../js_model/records.dart' show JRecordClass;
import '../js_model/type_recipe.dart';
import '../native/behavior.dart';
import '../options.dart';
import '../tracer.dart' show Tracer;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/resource_identifier.dart';
import '../universe/selector.dart' show Selector;
import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse;
import 'codegen_helpers.dart';
import 'nodes.dart';
import 'variable_allocator.dart';

mixin CodegenPhase {
  String get name;
  void visitGraph(HGraph graph);
}

class SsaCodeGeneratorTask extends CompilerTask {
  final CompilerOptions _options;
  final SourceInformationStrategy sourceInformationStrategy;
  CodegenMetrics? _codegenMetrics;
  CodegenMetrics get codegenMetrics => _codegenMetrics ??= CodegenMetrics();

  SsaCodeGeneratorTask(
    super.measurer,
    this._options,
    this.sourceInformationStrategy,
  );

  @override
  String get name => 'SSA code generator';

  @override
  Metrics get metrics => _codegenMetrics ?? Metrics.none();

  js.Fun buildJavaScriptFunction(
    bool needsAsyncRewrite,
    FunctionEntity element,
    List<js.Parameter> parameters,
    js.Block body,
  ) {
    js.Fun finish(js.AsyncModifier asyncModifier) {
      return js.Fun(
            parameters,
            body,
            asyncModifier: asyncModifier,
          ).withSourceInformation(
            sourceInformationStrategy
                .createBuilderForContext(element)
                .buildDeclaration(element),
          )
          as js.Fun;
    }

    if (needsAsyncRewrite) {
      return finish(
        element.asyncMarker.isAsync
            ? (element.asyncMarker.isYielding
                ? js.AsyncModifier.asyncStar
                : js.AsyncModifier.async)
            : (element.asyncMarker.isYielding
                ? js.AsyncModifier.syncStar
                : js.AsyncModifier.sync),
      );
    } else {
      return finish(js.AsyncModifier.sync);
    }
  }

  js.Expression generateCode(
    MemberEntity member,
    HGraph graph,
    CodegenInputs codegen,
    JClosedWorld closedWorld,
    CodegenRegistry registry,
    ModularNamer namer,
    ModularEmitter emitter,
  ) {
    js.Expression code;
    if (member is FieldEntity) {
      code = generateLazyInitializer(
        member,
        graph,
        codegen,
        closedWorld,
        registry,
        namer,
        emitter,
      );
    } else if (member is FunctionEntity) {
      code = generateMethod(
        member,
        graph,
        codegen,
        closedWorld,
        registry,
        namer,
        emitter,
      );
    } else {
      failedAt(member, 'Cannot generate JavaScript for $member');
    }
    codegen.tracer.traceJavaScriptText('JavaScript', code.debugPrint);
    return code;
  }

  js.Expression generateLazyInitializer(
    FieldEntity field,
    HGraph graph,
    CodegenInputs codegen,
    JClosedWorld closedWorld,
    CodegenRegistry registry,
    ModularNamer namer,
    ModularEmitter emitter,
  ) {
    return measure(() {
      SourceInformation? sourceInformation = sourceInformationStrategy
          .createBuilderForContext(field)
          .buildDeclaration(field);
      SsaCodeGenerator codeGenerator = SsaCodeGenerator(
        this,
        _options,
        codegenMetrics,
        emitter,
        codegen.rtiSubstitutions,
        codegen.rtiRecipeEncoder,
        namer,
        codegen.tracer,
        closedWorld,
        registry,
      );
      codeGenerator.visitGraph(graph);
      codegen.tracer.traceGraph("codegen", graph);
      return js.Fun(
        codeGenerator.parameters,
        codeGenerator.body,
      ).withSourceInformation(sourceInformation);
    });
  }

  js.Expression generateMethod(
    FunctionEntity method,
    HGraph graph,
    CodegenInputs codegen,
    JClosedWorld closedWorld,
    CodegenRegistry registry,
    ModularNamer namer,
    ModularEmitter emitter,
  ) {
    return measure(() {
      if (method.asyncMarker != AsyncMarker.sync) {
        registry.registerAsyncMarker(method.asyncMarker);
      }
      SsaCodeGenerator codeGenerator = SsaCodeGenerator(
        this,
        _options,
        codegenMetrics,
        emitter,
        codegen.rtiSubstitutions,
        codegen.rtiRecipeEncoder,
        namer,
        codegen.tracer,
        closedWorld,
        registry,
      );
      codeGenerator.visitGraph(graph);
      codegen.tracer.traceGraph("codegen", graph);
      return buildJavaScriptFunction(
        graph.needsAsyncRewrite,
        method,
        codeGenerator.parameters,
        codeGenerator.body,
      );
    });
  }
}

class CodegenMetrics extends MetricsBase {
  int countHIf = 0;
  int countHIfConstant = 0;
  int countHIsTest = 0;
  int countHIsTestSimple = 0;
  int countHIsLateSentinel = 0;
  int countHGetLength = 0;
  int countHIndex = 0;
  int countHFieldGet = 0;
  int countSingleTargetInstanceCalls = 0;
  final countHInterceptor = CountMetric('count.HInterceptor');
  final countHInterceptorGet = CountMetric('count.HInterceptor.getInterceptor');
  final countHInterceptorOneshot = CountMetric('count.HInterceptor.oneShot');
  final countHInterceptorConditionalConstant = CountMetric(
    'count.HInterceptor.conditionalConstant',
  );

  CodegenMetrics();

  @override
  String get namespace => 'codegen';

  @override
  Iterable<Metric> get primary => [];

  @override
  Iterable<Metric> get secondary => [
    CountMetric('count.HIf')..add(countHIf),
    CountMetric('count.HIf.constant')..add(countHIfConstant),
    CountMetric('count.HIsTest')..add(countHIsTest),
    CountMetric('count.HIsTestSimple')..add(countHIsTestSimple),
    CountMetric('count.HIsLateSentinel')..add(countHIsLateSentinel),
    CountMetric('count.HGetLength')..add(countHGetLength),
    CountMetric('count.HIndex')..add(countHIndex),
    CountMetric('count.HFieldGet')..add(countHFieldGet),
    CountMetric('count.SingleTargetInstance')
      ..add(countSingleTargetInstanceCalls),
    countHInterceptor,
    countHInterceptorGet,
    countHInterceptorConditionalConstant,
    countHInterceptorOneshot,
  ];
}

/// Returned by [_expressionType] to tell how code can be generated for
/// a subgraph.
enum _ExpressionCodegenType {
  /// The graph must be generated as a statement, which is always possible.
  statement,

  /// The graph can be generated as an expression, or possibly several
  /// comma-separated expressions.
  expression,

  /// The graph can be generated as an expression, and it only generates
  /// expressions of the form
  ///   variable = expression
  /// which are also valid as parts of a "var" declaration.
  declaration,
}

class SsaCodeGenerator implements HVisitor<void>, HBlockInformationVisitor {
  /// Whether we are currently generating expressions instead of statements.
  /// This includes declarations, which are generated as expressions.
  bool isGeneratingExpression = false;

  final CompilerTask _codegenTask;
  final CompilerOptions _options;
  final ModularEmitter _emitter;
  final RuntimeTypesSubstitutions _rtiSubstitutions;
  final RecipeEncoder _rtiRecipeEncoder;
  final ModularNamer _namer;
  final Tracer _tracer;
  final JClosedWorld _closedWorld;
  final CodegenRegistry _registry;
  final CodegenMetrics _metrics;

  final Set<HInstruction> generateAtUseSite = {};
  final Set<HIf> controlFlowOperators = {};
  final Set<JumpTarget> breakAction = {};
  final Set<LabelDefinition> continueAction = {};
  final Set<JumpTarget> implicitContinueAction = {};
  final List<js.Parameter> parameters = [];

  // Using a Block as the current container allows a statement tree to be
  // constructed that contains the block, and then have the block filled in
  // later.
  // TODO(sra): It would be cleaner if the [js.Block] could be unmodifiable but
  // that would require deferring the construction of the containing AST.
  js.Block currentContainer = js.Block.empty();
  js.Block get body => currentContainer;
  List<js.Expression> expressionStack = [];
  List<js.Block> oldContainerStack = [];

  /// Contains the names of the instructions, as well as the parallel
  /// copies to perform on block transitioning.
  late VariableNames variableNames;

  /// `true` when we need to generate a `var` declaration at function entry,
  /// `false` if we can generate a `var` declaration at first assignment in the
  /// middle of the function.
  bool shouldGroupVarDeclarations = false;

  /// While generating expressions, we can't insert variable declarations.
  /// Instead we declare them at the start of the function.  When minifying
  /// we do this most of the time, because it reduces the size unless there
  /// is only one variable.
  final Set<String> collectedVariableDeclarations = {};

  /// Set of variables and parameters that have already been declared.
  final Set<String> declaredLocals = {};

  late HGraph currentGraph;

  // Records a block-information that is being handled specially.
  // Used to break bad recursion.
  HBlockInformation? currentBlockInformation;
  // The subgraph is used to delimit traversal for some constructions, e.g.,
  // if branches.
  SubGraph? subGraph;

  // Pending blocks than need to be visited as part of current subgraph.
  Queue<HBasicBlock>? blockQueue;

  SsaCodeGenerator(
    this._codegenTask,
    this._options,
    this._metrics,
    this._emitter,
    this._rtiSubstitutions,
    this._rtiRecipeEncoder,
    this._namer,
    this._tracer,
    this._closedWorld,
    this._registry,
  );

  JCommonElements get _commonElements => _closedWorld.commonElements;

  NativeData get _nativeData => _closedWorld.nativeData;

  InterceptorData get _interceptorData => _closedWorld.interceptorData;

  AbstractValueDomain get _abstractValueDomain =>
      _closedWorld.abstractValueDomain;

  bool isGenerateAtUseSite(HInstruction instruction) {
    return generateAtUseSite.contains(instruction);
  }

  /// If the [instruction] is not `null` it will be used to attach the position
  /// to the [statement].
  void pushStatement(js.Statement statement) {
    assert(expressionStack.isEmpty);
    currentContainer.statements.add(statement);
  }

  void insertStatementAtStart(js.Statement statement) {
    currentContainer.statements.insert(0, statement);
  }

  /// If the [instruction] is not `null` it will be used to attach the position
  /// to the [expression].
  void pushExpressionAsStatement(
    js.Expression expression,
    SourceInformation? sourceInformation,
  ) {
    pushStatement(
      js.ExpressionStatement(
        expression,
      ).withSourceInformation(sourceInformation),
    );
  }

  /// If the [instruction] is not `null` it will be used to attach the position
  /// to the [expression].
  void push(js.Expression expression) {
    expressionStack.add(expression);
  }

  js.Expression pop() {
    return expressionStack.removeLast();
  }

  void preGenerateMethod(HGraph graph) {
    void runPhase(CodegenPhase phase, {bool traceGraph = true}) {
      _codegenTask.measureSubtask(phase.name, () => phase.visitGraph(graph));
      if (traceGraph) {
        _tracer.traceGraph(phase.name, graph);
      }
      assert(graph.isValid(), 'Graph not valid after ${phase.name}');
    }

    // Remove trusted late checks first to uncover read-modify-write patterns in
    // instruction selection.
    runPhase(SsaTrustedLateCheckRemover(_abstractValueDomain));
    runPhase(SsaInstructionSelection(_options, _closedWorld));
    runPhase(SsaTypeKnownRemover());
    runPhase(SsaTrustedPrimitiveCheckRemover(_options));
    runPhase(SsaAssignmentChaining(_closedWorld));
    runPhase(SsaInstructionMerger(_abstractValueDomain, generateAtUseSite));
    runPhase(SsaConditionMerger(generateAtUseSite, controlFlowOperators));
    runPhase(SsaPhiConditioning(generateAtUseSite, controlFlowOperators));
    runPhase(SsaShareRegionConstants());

    SsaLiveIntervalBuilder intervalBuilder = SsaLiveIntervalBuilder(
      generateAtUseSite,
      controlFlowOperators,
    );
    runPhase(intervalBuilder, traceGraph: false);
    SsaVariableAllocator allocator = SsaVariableAllocator(
      _namer,
      intervalBuilder.liveInstructions,
      intervalBuilder.liveIntervals,
      generateAtUseSite,
    );
    runPhase(allocator, traceGraph: false);
    variableNames = allocator.names;
    shouldGroupVarDeclarations = allocator.names.numberOfVariables > 1;
  }

  void handleDelayedVariableDeclarations(SourceInformation? sourceInformation) {
    // Create 'var' list at the start of function.  Move assignment statements
    // from the top of the body into the variable initializers.
    if (collectedVariableDeclarations.isEmpty) return;

    List<js.VariableInitialization> declarations = [];
    List<js.Statement> statements = currentContainer.statements;
    int nextStatement = 0;

    while (nextStatement < statements.length) {
      if (collectedVariableDeclarations.isEmpty) break;
      js.Statement statement = statements[nextStatement];
      if (statement is js.ExpressionStatement) {
        js.Expression expression = statement.expression;
        if (expression is js.Assignment && !expression.isCompound) {
          js.Expression left = expression.leftHandSide;
          if (left is js.VariableReference) {
            String name = left.name;
            js.Expression value = expression.value;
            if (_safeInInitializer(value) &&
                collectedVariableDeclarations.remove(name)) {
              var initialization = js.VariableInitialization(
                js.VariableDeclaration(name),
                value,
                sourceInformation: expression.sourceInformation,
              );
              declarations.add(initialization);
              ++nextStatement;
              continue;
            }
          }
        }
      }
      break;
    }

    List<js.VariableInitialization> uninitialized = [];
    for (String name in collectedVariableDeclarations) {
      uninitialized.add(
        js.VariableInitialization(js.VariableDeclaration(name), null),
      );
    }
    var declarationList = js.VariableDeclarationList(
      uninitialized + declarations,
    ).withSourceInformation(sourceInformation);
    statements.replaceRange(0, nextStatement, [
      js.ExpressionStatement(declarationList),
    ]);
  }

  // An expression is safe to be pulled into a 'var' initializer if it does not
  // contain assignments to locals. We don't generate assignments to locals
  // inside expressions.
  bool _safeInInitializer(js.Expression node) => true;

  void visitGraph(HGraph graph) {
    preGenerateMethod(graph);
    currentGraph = graph;
    visitSubGraph(SubGraph(graph.entry, graph.exit));
    handleDelayedVariableDeclarations(graph.sourceInformation);
  }

  void visitSubGraph(SubGraph? newSubGraph) {
    final oldSubGraph = subGraph;
    final oldBlockQueue = blockQueue;

    subGraph = newSubGraph;
    blockQueue = Queue();
    enterSubGraph(subGraph!.start);

    blockQueue = oldBlockQueue;
    subGraph = oldSubGraph;
  }

  /// Check whether a sub-graph can be generated as an expression, or even
  /// as a declaration, or if it has to fall back to being generated as
  /// a statement.
  /// Expressions are anything that doesn't generate control flow constructs.
  /// Declarations must only generate assignments on the form "id = expression",
  /// and not, e.g., expressions where the value isn't assigned, or where it's
  /// assigned to something that's not a simple variable.
  _ExpressionCodegenType _expressionType(HExpressionInformation info) {
    // The only HExpressionInformation used as part of a HBlockInformation is
    // current HSubExpressionBlockInformation, so it's the only one reaching
    // here. If we start using the other HExpressionInformation types too,
    // this code should be generalized.
    assert(info is HSubExpressionBlockInformation);
    info as HSubExpressionBlockInformation;
    HSubExpressionBlockInformation expressionInfo = info;
    SubGraph limits = expressionInfo.subExpression!;

    // Start assuming that we can generate declarations for simple local
    // variables. If we find a counter-example, we degrade our assumption to
    // either expression or statement, and in the latter case, we can return
    // immediately since it can't get any worse. E.g., a function call where the
    // return value isn't used can't be in a declaration.
    var result = _ExpressionCodegenType.declaration;
    HBasicBlock basicBlock = limits.start;
    do {
      HInstruction current = basicBlock.first!;
      while (current != basicBlock.last) {
        // E.g, bounds check.
        if (current.isJsStatement()) {
          return _ExpressionCodegenType.statement;
        }
        // HFieldSet generates code on the form "x.y = ...", which isn't valid
        // in a declaration.
        if (current.usedBy.isEmpty || current is HFieldSet) {
          result = _ExpressionCodegenType.expression;
        }
        current = current.next!;
      }
      if (current is HGoto) {
        basicBlock = basicBlock.successors[0];
      } else if (current is HConditionalBranch) {
        if (generateAtUseSite.contains(current)) {
          // Short-circuit control flow operator trickery.
          // Check the second half, which will continue into the join.
          // (The first half is [inputs[0]], the second half is [successors[0]],
          // and [successors[1]] is the join-block).
          basicBlock = basicBlock.successors[0];
        } else {
          // We allow an expression to end on an HIf (a condition expression).
          return identical(basicBlock, limits.end)
              ? result
              : _ExpressionCodegenType.statement;
        }
      } else {
        // Expression-incompatible control flow.
        return _ExpressionCodegenType.statement;
      }
    } while (limits.contains(basicBlock));
    return result;
  }

  bool isJSExpression(HExpressionInformation info) {
    return !identical(_expressionType(info), _ExpressionCodegenType.statement);
  }

  bool isJSCondition(HExpressionInformation? info) {
    // Currently we only handle sub-expression graphs.
    info as HSubExpressionBlockInformation;

    SubExpression? limits = info.subExpression;
    return !identical(
          _expressionType(info),
          _ExpressionCodegenType.statement,
        ) &&
        (limits!.end.last is HConditionalBranch);
  }

  /// Generate statements from block information.
  /// If the block information contains expressions, generate only
  /// assignments, and if it ends in a conditional branch, don't generate
  /// the condition.
  void generateStatements(HBlockInformation? block) {
    if (block is HStatementInformation) {
      block.accept(this);
    } else if (block is HSubExpressionBlockInformation) {
      visitSubGraph(block.subExpression);
    } else {
      failedAt(currentElementSpannable, 'Unexpected block: $block');
    }
  }

  js.Block generateStatementsInNewBlock(HBlockInformation? block) {
    js.Block result = js.Block.empty();
    js.Block oldContainer = currentContainer;
    currentContainer = result;
    generateStatements(block);
    currentContainer = oldContainer;
    return result;
  }

  /// If the [block] only contains one statement returns that statement. If the
  /// that statement itself is a block, recursively calls this method.
  ///
  /// If the block is empty, returns a new instance of [js.NOP].
  js.Statement unwrapStatement(js.Block block) {
    int len = block.statements.length;
    if (len == 0) return js.EmptyStatement();
    if (len == 1) {
      js.Statement result = block.statements[0];
      if (result is js.Block) return unwrapStatement(result);
      return result;
    }
    return block;
  }

  /// Generate expressions from block information.
  js.Expression? generateExpression(HExpressionInformation expression) {
    // Currently we only handle sub-expression graphs.
    expression as HSubExpressionBlockInformation;

    bool oldIsGeneratingExpression = isGeneratingExpression;
    isGeneratingExpression = true;
    List<js.Expression> oldExpressionStack = expressionStack;
    List<js.Expression> sequenceElements = [];
    expressionStack = sequenceElements;
    HSubExpressionBlockInformation expressionSubGraph = expression;
    visitSubGraph(expressionSubGraph.subExpression);
    expressionStack = oldExpressionStack;
    isGeneratingExpression = oldIsGeneratingExpression;
    if (sequenceElements.isEmpty) {
      // Happens when the initializer, condition or update of a loop is empty.
      return null;
    } else if (sequenceElements.length == 1) {
      return sequenceElements[0];
    } else {
      js.Expression result = sequenceElements.removeLast();
      while (sequenceElements.isNotEmpty) {
        result = js.Binary(',', sequenceElements.removeLast(), result);
      }
      return result;
    }
  }

  /// Only visits the arguments starting at inputs[HInvoke.argumentsOffset].
  List<js.Expression> visitArguments(
    List<HInstruction> inputs, {
    int start = HInvoke.argumentsOffset,
  }) {
    assert(inputs.length >= start);
    return List.generate(inputs.length - start, (i) {
      use(inputs[i + start]);
      return pop();
    }, growable: false);
  }

  bool isVariableDeclared(String variableName) {
    return declaredLocals.contains(variableName) ||
        collectedVariableDeclarations.contains(variableName);
  }

  js.Expression generateExpressionAssignment(
    String variableName,
    js.Expression value,
    SourceInformation? sourceInformation,
  ) {
    // TODO(johnniwinther): Introduce a DeferredVariableUse to handle this
    // in the SSA codegen or let the JS printer handle it fully and remove it
    // here.
    if (value is js.Binary) {
      js.Binary binary = value;
      String op = binary.op;
      if (op == '+' ||
          op == '-' ||
          op == '/' ||
          op == '*' ||
          op == '%' ||
          op == '^' ||
          op == '&' ||
          op == '|') {
        js.Expression left = binary.left;
        if (left is js.VariableUse && left.name == variableName) {
          // We know now, that we can shorten x = x + y into x += y.
          // Also check for the shortcut where y equals 1: x++ and x--.
          js.Expression right = binary.right;
          if ((op == '+' || op == '-') &&
              right is js.LiteralNumber &&
              right.value == "1") {
            return js.Prefix(op == '+' ? '++' : '--', left);
          }
          return js.Assignment.compound(binary.left, op, binary.right);
        }
      }
    }
    return js.Assignment(
      js.VariableUse(variableName),
      value,
    ).withSourceInformation(value.sourceInformation ?? sourceInformation);
  }

  void assignVariable(
    String variableName,
    js.Expression value,
    SourceInformation? sourceInformation,
  ) {
    if (isGeneratingExpression) {
      // If we are in an expression then we can't declare the variable here.
      // We have no choice, but to use it and then declare it separately.
      if (!isVariableDeclared(variableName)) {
        collectedVariableDeclarations.add(variableName);
      }
      push(
        generateExpressionAssignment(variableName, value, sourceInformation),
      );
      // Otherwise if we are trying to declare inline and we are in a statement
      // then we declare (unless it was already declared).
    } else if (!shouldGroupVarDeclarations &&
        !declaredLocals.contains(variableName)) {
      // It may be necessary to remove it from the ones to be declared later.
      collectedVariableDeclarations.remove(variableName);
      declaredLocals.add(variableName);
      js.VariableDeclaration decl = js.VariableDeclaration(variableName);
      js.VariableInitialization initialization = js.VariableInitialization(
        decl,
        value,
      );

      pushExpressionAsStatement(
        js.VariableDeclarationList([initialization]),
        sourceInformation,
      );
    } else {
      // Otherwise we are just going to use it.  If we have not already declared
      // it then we make sure we will declare it later.
      if (!declaredLocals.contains(variableName)) {
        collectedVariableDeclarations.add(variableName);
      }
      pushExpressionAsStatement(
        generateExpressionAssignment(variableName, value, sourceInformation),
        sourceInformation,
      );
    }
  }

  void define(HInstruction instruction) {
    // For simple type checks like i = intTypeCheck(i), we don't have to
    // emit an assignment, because the intTypeCheck just returns its
    // argument.
    bool needsAssignment = true;
    if (instruction is HOutputConstrainedToAnInput) {
      if (instruction is HPrimitiveCheck ||
          instruction is HAsCheck ||
          instruction is HAsCheckSimple ||
          instruction is HNullCheck ||
          instruction is HLateReadCheck ||
          instruction is HArrayFlagsSet) {
        String? inputName = variableNames.getName(instruction.constrainedInput);
        if (variableNames.getName(instruction) == inputName) {
          needsAssignment = false;
        }
      }
    }
    if (instruction is HLocalValue) {
      needsAssignment = false;
    }

    if (needsAssignment &&
        !instruction.isJsStatement() &&
        variableNames.hasName(instruction)) {
      visitExpression(instruction);
      assignVariable(
        variableNames.getName(instruction)!,
        pop(),
        instruction.sourceInformation,
      );
      return;
    }

    if (isGeneratingExpression) {
      visitExpression(instruction);
    } else {
      visitStatement(instruction);
    }
  }

  HInstruction skipGenerateAtUseCheckInputs(HOutputConstrainedToAnInput check) {
    HInstruction input = check.constrainedInput;
    if (input is HOutputConstrainedToAnInput && isGenerateAtUseSite(input)) {
      return skipGenerateAtUseCheckInputs(input);
    }
    return input;
  }

  void use(HInstruction argument) {
    if (isGenerateAtUseSite(argument)) {
      visitExpression(argument);
    } else if (argument is HOutputConstrainedToAnInput &&
        !variableNames.hasName(argument)) {
      // We have a check that is not generate-at-use and has no name, yet is a
      // subexpression (we are in 'use'). This happens when we have a chain of
      // checks on an available unnamed value (e.g. a constant). The checks are
      // generated as a statement, so we need to skip the generate-at-use check
      // tree to find the underlying value.

      // TODO(sra): We should ensure that this invariant holds: "every
      // instruction has a name or is generate-at-use". This would require
      // naming the input or output of the chain-of-checks.

      // This can only happen if the checked node also does not have a name.
      assert(!variableNames.hasName(argument.constrainedInput));

      use(skipGenerateAtUseCheckInputs(argument));
    } else {
      assert(variableNames.hasName(argument));
      push(js.VariableUse(variableNames.getName(argument)!));
    }
  }

  void visit(HInstruction node) {
    node.accept(this);
  }

  void visitExpression(HInstruction node) {
    bool oldIsGeneratingExpression = isGeneratingExpression;
    isGeneratingExpression = true;
    visit(node);
    isGeneratingExpression = oldIsGeneratingExpression;
  }

  void visitStatement(HInstruction node) {
    assert(!isGeneratingExpression);
    visit(node);
    if (expressionStack.isNotEmpty) {
      assert(expressionStack.length == 1);
      js.Expression expression = pop();
      pushExpressionAsStatement(expression, node.sourceInformation);
    }
  }

  void continueAsBreak(LabelDefinition target) {
    pushStatement(js.Break(_namer.continueLabelName(target)));
  }

  void implicitContinueAsBreak(JumpTarget target) {
    pushStatement(js.Break(_namer.implicitContinueLabelName(target)));
  }

  void implicitBreakWithLabel(JumpTarget target) {
    pushStatement(js.Break(_namer.implicitBreakLabelName(target)));
  }

  js.Statement wrapIntoLabels(
    js.Statement result,
    List<LabelDefinition> labels,
  ) {
    for (LabelDefinition label in labels) {
      if (label.isTarget) {
        String breakLabelString = _namer.breakLabelName(label);
        result = js.LabeledStatement(breakLabelString, result);
      }
    }
    return result;
  }

  // The regular [visitIf] method implements the needed logic.
  @override
  bool visitIfInfo(HIfBlockInformation info) => false;

  @override
  bool visitSwitchInfo(HSwitchBlockInformation info) {
    bool isExpression = isJSExpression(info.expression);
    if (!isExpression) {
      generateStatements(info.expression);
    }

    if (isExpression) {
      push(generateExpression(info.expression)!);
    } else {
      use(info.expression.conditionExpression!);
    }
    js.Expression key = pop();
    bool handledDefault = false;
    List<js.SwitchClause> cases = [];
    HSwitch switchInstruction = info.expression.end.last as HSwitch;
    List<HInstruction> inputs = switchInstruction.inputs;
    List<HBasicBlock> successors = switchInstruction.block!.successors;

    js.Block oldContainer = currentContainer;
    for (
      int inputIndex = 1, statementIndex = 0;
      inputIndex < inputs.length;
      statementIndex++
    ) {
      HBasicBlock successor = successors[inputIndex - 1];
      // If liveness analysis has figured out that this case is dead,
      // omit the code for it.
      if (successor.isLive) {
        do {
          final input = inputs[inputIndex];
          visit(input);
          currentContainer = js.Block.empty();
          cases.add(js.Case(pop(), currentContainer));
          if (input is HConstant && input.constant is NullConstantValue) {
            // JavaScript case expressions match on `===`, which means that the
            // just emitted `case null:` will not catch `undefined`.
            // Add `case void 0:` to catch `undefined`.
            currentContainer = js.Block.empty();
            cases.add(
              js.Case(js.Prefix('void', js.number(0)), currentContainer),
            );
          }
          inputIndex++;
        } while ((successors[inputIndex - 1] == successor) &&
            (inputIndex < inputs.length));

        // If this is the last statement, then these cases also belong to the
        // default block.
        if (statementIndex == info.statements.length - 1) {
          currentContainer = js.Block.empty();
          cases.add(js.Default(currentContainer));
          handledDefault = true;
        }

        generateStatements(info.statements[statementIndex]);
      } else {
        // Skip all the case statements that belong to this
        // block.
        while ((successors[inputIndex - 1] == successor) &&
            (inputIndex < inputs.length)) {
          ++inputIndex;
        }
      }
    }

    // If the default case is dead, we omit it. Likewise, if it is an
    // empty block, we omit it, too.
    if (info.statements.last.start.isLive && !handledDefault) {
      currentContainer = js.Block.empty();
      generateStatements(info.statements.last);
      if (currentContainer.statements.isNotEmpty) {
        cases.add(js.Default(currentContainer));
      }
    }

    currentContainer = oldContainer;

    js.Statement result = js.Switch(
      key,
      cases,
    ).withSourceInformation(info.sourceInformation);
    pushStatement(wrapIntoLabels(result, info.labels));
    return true;
  }

  @override
  bool visitSequenceInfo(HStatementSequenceInformation info) {
    return false;
  }

  @override
  bool visitSubGraphInfo(HSubGraphBlockInformation info) {
    visitSubGraph(info.subGraph);
    return true;
  }

  @override
  bool visitSubExpressionInfo(HSubExpressionBlockInformation info) {
    return false;
  }

  @override
  bool visitTryInfo(HTryBlockInformation info) {
    js.Block body = generateStatementsInNewBlock(info.body);
    js.Catch? catchPart;
    js.Block? finallyPart;
    if (info.catchBlock != null) {
      void register(ClassEntity classElement) {
        _registry
        // ignore:deprecated_member_use_from_same_package
        .registerInstantiatedClass(classElement);
      }

      register(_commonElements.jsPlainJavaScriptObjectClass);
      register(_commonElements.jsUnknownJavaScriptObjectClass);

      HLocalValue? exception = info.catchVariable;
      String name = variableNames.getName(exception)!;
      js.VariableDeclaration decl = js.VariableDeclaration(name);
      js.Block catchBlock = generateStatementsInNewBlock(info.catchBlock);
      catchPart = js.Catch(decl, catchBlock);
    }
    if (info.finallyBlock != null) {
      finallyPart = generateStatementsInNewBlock(info.finallyBlock);
    }
    pushStatement(js.Try(body, catchPart, finallyPart));
    return true;
  }

  void visitBodyIgnoreLabels(HLoopBlockInformation info) {
    if (info.body!.start.isLabeledBlock()) {
      HBlockInformation? oldInfo = currentBlockInformation;
      currentBlockInformation = info.body!.start.blockFlow!.body;
      generateStatements(info.body);
      currentBlockInformation = oldInfo;
    } else {
      generateStatements(info.body);
    }
  }

  @override
  bool visitLoopInfo(HLoopBlockInformation info) {
    HExpressionInformation? condition = info.condition;
    bool isConditionExpression = isJSCondition(condition);

    late js.Loop loop;

    switch (info.kind) {
      // Treat all three "test-first" loops the same way.
      case LoopBlockInformationKind.forLoop:
      case LoopBlockInformationKind.whileLoop:
      case LoopBlockInformationKind.forInLoop:
      case LoopBlockInformationKind.switchContinueLoop:
        HExpressionInformation? initialization = info.initializer;
        var initializationType = _ExpressionCodegenType.statement;
        if (initialization != null) {
          initializationType = _expressionType(initialization);
          if (initializationType == _ExpressionCodegenType.statement) {
            generateStatements(initialization);
            initialization = null;
          }
        }

        // We inserted a basic block to avoid critical edges. This block is
        // part of the LoopBlockInformation and must therefore be handled here.
        js.Block oldContainer = currentContainer;
        js.Block avoidContainer = js.Block.empty();
        currentContainer = avoidContainer;
        assignPhisOfSuccessors(condition!.end.successors.last);
        bool hasPhiUpdates = avoidContainer.statements.isNotEmpty;
        currentContainer = oldContainer;

        if (isConditionExpression &&
            !hasPhiUpdates &&
            info.updates != null &&
            isJSExpression(info.updates!)) {
          // If we have an updates graph, and it's expressible as an
          // expression, generate a for-loop.
          js.Expression? jsInitialization;
          if (initialization != null) {
            int delayedVariablesCount = collectedVariableDeclarations.length;
            jsInitialization = generateExpression(initialization);
            if (!shouldGroupVarDeclarations &&
                delayedVariablesCount < collectedVariableDeclarations.length) {
              // We just added a new delayed variable-declaration. See if we can
              // put in a 'var' in front of the initialization to make it go
              // away. We walk the 'tree' of comma-operators to find the
              // expressions and see if they are all assignments that can be
              // converted into declarations.

              List<js.Assignment>? assignments;

              bool allSimpleAssignments(js.Expression expression) {
                if (expression is js.Assignment) {
                  js.Assignment assignment = expression;
                  if (assignment.leftHandSide is js.VariableUse &&
                      !assignment.isCompound) {
                    (assignments ??= []).add(expression);
                    return true;
                  }
                } else if (expression is js.Binary &&
                    expression.isCommaOperator) {
                  return allSimpleAssignments(expression.left) &&
                      allSimpleAssignments(expression.right);
                }
                return false;
              }

              if (jsInitialization != null &&
                  allSimpleAssignments(jsInitialization)) {
                List<js.VariableInitialization> inits = [];
                for (js.Assignment assignment in assignments!) {
                  final id = (assignment.leftHandSide as js.VariableUse).name;
                  final declaration = js.VariableDeclaration(id);
                  inits.add(
                    js.VariableInitialization(declaration, assignment.value),
                  );
                  collectedVariableDeclarations.remove(id);
                  declaredLocals.add(id);
                }
                jsInitialization = js.VariableDeclarationList(inits);
              }
            }
          }
          js.Expression? jsCondition = generateExpression(condition);
          js.Expression? jsUpdates = generateExpression(info.updates!);
          // The body might be labeled. Ignore this when recursing on the
          // subgraph.
          // TODO(lrn): Remove this extra labeling when handling all loops
          // using subgraphs.
          oldContainer = currentContainer;
          js.Block body = js.Block.empty();
          currentContainer = body;
          visitBodyIgnoreLabels(info);
          currentContainer = oldContainer;
          loop = js.For(
            jsInitialization,
            jsCondition,
            jsUpdates,
            unwrapStatement(body),
            sourceInformation: info.sourceInformation,
          );
        } else {
          // We have either no update graph, or it's too complex to
          // put in an expression.
          if (initialization != null) {
            generateStatements(initialization);
          }
          js.Expression? jsCondition;
          js.Block oldContainer = currentContainer;
          js.Block body = js.Block.empty();
          if (isConditionExpression && !hasPhiUpdates) {
            jsCondition = generateExpression(condition);
            currentContainer = body;
          } else {
            jsCondition = newLiteralBool(true, info.sourceInformation);
            currentContainer = body;
            generateStatements(condition);
            use(condition.conditionExpression!);
            js.Expression ifTest = js.Prefix("!", pop());
            js.Statement jsBreak = js.Break(null);
            js.Statement exitLoop;
            if (avoidContainer.statements.isEmpty) {
              exitLoop = jsBreak;
            } else {
              avoidContainer.statements.add(jsBreak);
              exitLoop = avoidContainer;
            }
            pushStatement(js.If.noElse(ifTest, exitLoop));
          }
          if (info.updates != null) {
            wrapLoopBodyForContinue(info);
            generateStatements(info.updates);
          } else {
            visitBodyIgnoreLabels(info);
          }
          currentContainer = oldContainer;
          loop = js.While(
            jsCondition!,
            unwrapStatement(body),
            sourceInformation: info.sourceInformation,
          );
        }
        break;
      case LoopBlockInformationKind.doWhileLoop:
        if (info.initializer != null) {
          generateStatements(info.initializer);
        }
        // We inserted a basic block to avoid critical edges. This block is
        // part of the LoopBlockInformation and must therefore be handled here.
        js.Block oldContainer = currentContainer;
        js.Block exitAvoidContainer = js.Block.empty();
        currentContainer = exitAvoidContainer;
        assignPhisOfSuccessors(condition!.end.successors.last);
        bool hasExitPhiUpdates = exitAvoidContainer.statements.isNotEmpty;
        currentContainer = oldContainer;

        oldContainer = currentContainer;
        js.Block body = js.Block.empty();
        // If there are phi copies in the block that jumps to the
        // loop entry, we must emit the condition like this:
        // do {
        //   body;
        //   if (condition) {
        //     phi updates;
        //     continue;
        //   } else {
        //     break;
        //   }
        // } while (true);
        HBasicBlock avoidEdge = info.end.successors[0];
        js.Block updateBody = js.Block.empty();
        currentContainer = updateBody;
        assignPhisOfSuccessors(avoidEdge);
        bool hasPhiUpdates = updateBody.statements.isNotEmpty;
        currentContainer = body;
        visitBodyIgnoreLabels(info);
        if (info.updates != null) {
          generateStatements(info.updates);
        }
        js.Expression? jsCondition;
        if (isConditionExpression) {
          jsCondition = generateExpression(condition);
        } else {
          generateStatements(condition);
          use(condition.conditionExpression!);
          jsCondition = pop();
        }
        if (jsCondition == null) {
          // If the condition is dead code, we turn the do-while into
          // a simpler while because we will never reach the condition
          // at the end of the loop anyway.
          loop = js.While(
            newLiteralBool(true, info.sourceInformation),
            unwrapStatement(body),
            sourceInformation: info.sourceInformation,
          );
        } else {
          if (hasPhiUpdates || hasExitPhiUpdates) {
            updateBody.statements.add(js.Continue(null));
            js.Statement jsBreak = js.Break(null);
            js.Statement exitLoop;
            if (exitAvoidContainer.statements.isEmpty) {
              exitLoop = jsBreak;
            } else {
              exitAvoidContainer.statements.add(jsBreak);
              exitLoop = exitAvoidContainer;
            }
            body.statements.add(js.If(jsCondition, updateBody, exitLoop));
            jsCondition = newLiteralBool(true, info.sourceInformation);
          }
          loop = js.Do(
            unwrapStatement(body),
            jsCondition,
            sourceInformation: info.sourceInformation,
          );
        }
        currentContainer = oldContainer;
        break;
      case LoopBlockInformationKind.notALoop:
        failedAt(
          condition!.conditionExpression!,
          'Unexpected loop kind: ${info.kind}.',
        );
    }
    js.Statement result = loop;
    if (info.kind == LoopBlockInformationKind.switchContinueLoop) {
      String continueLabelString = _namer.implicitContinueLabelName(
        info.target!,
      );
      result = js.LabeledStatement(continueLabelString, result);
    }
    pushStatement(wrapIntoLabels(result, info.labels));
    return true;
  }

  @override
  bool visitLabeledBlockInfo(HLabeledBlockInformation labeledBlockInfo) {
    Link<Entity> continueOverrides = const Link<Entity>();

    js.Block oldContainer = currentContainer;
    js.Block body = js.Block.empty();
    js.Statement result = body;

    currentContainer = body;

    // If [labeledBlockInfo.isContinue], the block is an artificial
    // block around the body of a loop with an update block, so that
    // continues of the loop can be written as breaks of the body
    // block.
    if (labeledBlockInfo.isContinue) {
      for (LabelDefinition label in labeledBlockInfo.labels) {
        if (label.isContinueTarget) {
          String labelName = _namer.continueLabelName(label);
          result = js.LabeledStatement(labelName, result);
          continueAction.add(label);
          continueOverrides = continueOverrides.prepend(label);
        }
      }
      // For handling unlabeled continues from the body of a loop.
      // TODO(lrn): Consider recording whether the target is in fact
      // a target of an unlabeled continue, and not generate this if it isn't.
      JumpTarget target = labeledBlockInfo.target!;
      String labelName = _namer.implicitContinueLabelName(target);
      result = js.LabeledStatement(labelName, result);
      implicitContinueAction.add(target);
      continueOverrides = continueOverrides.prepend(target);
    } else {
      for (LabelDefinition label in labeledBlockInfo.labels) {
        if (label.isBreakTarget) {
          String labelName = _namer.breakLabelName(label);
          result = js.LabeledStatement(labelName, result);
        }
      }
    }
    JumpTarget target = labeledBlockInfo.target!;
    if (target.isSwitch) {
      // This is an extra block around a switch that is generated
      // as a nested if/else chain. We add an extra break target
      // so that case code can break.
      String labelName = _namer.implicitBreakLabelName(target);
      result = js.LabeledStatement(labelName, result);
      breakAction.add(target);
    }

    currentContainer = body;
    generateStatements(labeledBlockInfo.body);

    if (labeledBlockInfo.isContinue) {
      while (continueOverrides.isNotEmpty) {
        continueAction.remove(continueOverrides.head);
        implicitContinueAction.remove(continueOverrides.head);
        continueOverrides = continueOverrides.tail!;
      }
    } else {
      breakAction.remove(labeledBlockInfo.target);
    }

    currentContainer = oldContainer;
    pushStatement(result);
    return true;
  }

  // Wraps a loop body in a block to make continues have a target to break
  // to (if necessary).
  void wrapLoopBodyForContinue(HLoopBlockInformation info) {
    JumpTarget? target = info.target;
    if (target != null && target.isContinueTarget) {
      js.Block oldContainer = currentContainer;
      js.Block body = js.Block.empty();
      currentContainer = body;
      js.Statement result = body;
      for (LabelDefinition label in info.labels) {
        if (label.isContinueTarget) {
          String labelName = _namer.continueLabelName(label);
          result = js.LabeledStatement(labelName, result);
          continueAction.add(label);
        }
      }
      String labelName = _namer.implicitContinueLabelName(target);
      result = js.LabeledStatement(labelName, result);
      implicitContinueAction.add(target);
      visitBodyIgnoreLabels(info);
      implicitContinueAction.remove(target);
      for (LabelDefinition label in info.labels) {
        if (label.isContinueTarget) {
          continueAction.remove(label);
        }
      }
      currentContainer = oldContainer;
      pushStatement(result);
    } else {
      // Loop body contains no continues, so we don't need a break target.
      generateStatements(info.body);
    }
  }

  bool handleBlockFlow(HBlockFlow block) {
    HBlockInformation info = block.body;
    // If we reach here again while handling the attached information,
    // e.g., because we call visitSubGraph on a subgraph starting on
    // the same block, don't handle it again.
    // When the structure graph is complete, we will be able to have
    // different structures starting on the same basic block (e.g., an
    // "if" and its condition).
    if (identical(info, currentBlockInformation)) return false;

    HBlockInformation? oldBlockInformation = currentBlockInformation;
    currentBlockInformation = info;
    bool success = info.accept(this);
    currentBlockInformation = oldBlockInformation;

    if (success) {
      HBasicBlock? continuation = block.continuation;
      if (continuation != null) {
        continueSubGraph(continuation);
      }
    }
    return success;
  }

  void enterSubGraph(HBasicBlock node) {
    assert(blockQueue!.isEmpty);
    continueSubGraph(node);
    while (blockQueue!.isNotEmpty) {
      node = blockQueue!.removeFirst();
      assert(node.isLive);
      assert(subGraph!.contains(node));

      // If this node has block-structure based information attached,
      // try using that to traverse from here.
      if (node.blockFlow != null && handleBlockFlow(node.blockFlow!)) {
        continue;
      }

      iterateBasicBlock(node);
    }
  }

  void continueSubGraph(HBasicBlock node) {
    if (!node.isLive) return;
    // Don't follow edges out of the current sub-graph.
    if (!subGraph!.contains(node)) return;
    blockQueue!.add(node);
  }

  void emitAssignment(
    String destination,
    String source,
    SourceInformation? sourceInformation,
  ) {
    assignVariable(destination, js.VariableUse(source), sourceInformation);
  }

  /// Sequentialize a list of conceptually parallel copies. Parallel
  /// copies may contain cycles, that this method breaks.
  void sequentializeCopies(
    Iterable<Copy<HInstruction>> instructionCopies,
    String tempName,
    void Function(
      String target,
      String source,
      SourceInformation? sourceInformation,
    )
    doAssignment,
  ) {
    Map<String, SourceInformation?> sourceInformationMap = {};

    // Map the instructions to strings.
    Iterable<Copy<String>> copies = instructionCopies.map((
      Copy<HInstruction> copy,
    ) {
      String sourceName = variableNames.getName(copy.source)!;
      sourceInformationMap[sourceName] = copy.source.sourceInformation;
      String destinationName = variableNames.getName(copy.destination)!;
      sourceInformationMap[sourceName] = copy.destination.sourceInformation;
      return Copy<String>(sourceName, destinationName);
    });

    // Map to keep track of the current location (ie the variable that
    // holds the initial value) of a variable.
    Map<String, String> currentLocation = {};

    // Map to keep track of the initial value of a variable.
    Map<String, String> initialValue = {};

    // List of variables to assign a value.
    List<String> worklist = [];

    // List of variables that we can assign a value to (ie are not
    // being used anymore).
    List<String> ready = [];

    // Prune [copies] by removing self-copies.
    List<Copy<String>> prunedCopies = [];
    for (Copy<String> copy in copies) {
      if (copy.source != copy.destination) {
        prunedCopies.add(copy);
      }
    }
    copies = prunedCopies;

    // For each copy, set the current location of the source to
    // itself, and the initial value of the destination to the source.
    // Add the destination to the list of copies to make.
    for (Copy<String> copy in copies) {
      currentLocation[copy.source] = copy.source;
      initialValue[copy.destination] = copy.source;
      worklist.add(copy.destination);
    }

    // For each copy, if the destination does not have a current
    // location, then we can safely assign to it.
    for (Copy<String> copy in copies) {
      if (currentLocation[copy.destination] == null) {
        ready.add(copy.destination);
      }
    }

    while (worklist.isNotEmpty) {
      while (ready.isNotEmpty) {
        String destination = ready.removeLast();
        String source = initialValue[destination]!;
        // Since [source] might have been updated, use the current
        // location of [source]
        String copy = currentLocation[source]!;
        doAssignment(
          destination,
          copy,
          sourceInformationMap[copy] ?? sourceInformationMap[destination],
        );
        // Now [destination] is the current location of [source].
        currentLocation[source] = destination;
        // If [source] hasn't been updated and needs to have a value,
        // add it to the list of variables that can be updated. Copies
        // of [source] will now use [destination].
        if (source == copy && initialValue[source] != null) {
          ready.add(source);
        }
      }

      // Check if we have a cycle.
      String current = worklist.removeLast();
      // If [current] is used as a source, and the assignment has been
      // done, we are done with this variable. Otherwise there is a
      // cycle that we break by using a temporary name.
      if (currentLocation[current] != null &&
          current != currentLocation[initialValue[current]]) {
        doAssignment(tempName, current, sourceInformationMap[current]);
        currentLocation[current] = tempName;
        // [current] can now be safely updated. Copies of [current]
        // will now use [tempName].
        ready.add(current);
      }
    }
  }

  void assignPhisOfSuccessors(HBasicBlock node) {
    CopyHandler? handler = variableNames.getCopyHandler(node);
    if (handler == null) return;

    sequentializeCopies(
      handler.copies,
      variableNames.getSwapTemp(),
      emitAssignment,
    );

    for (Copy<HInstruction> copy in handler.assignments) {
      String name = variableNames.getName(copy.destination)!;
      use(copy.source);
      assignVariable(
        name,
        pop(),
        copy.source.sourceInformation ?? copy.destination.sourceInformation,
      );
    }
  }

  void iterateBasicBlock(HBasicBlock node) {
    HInstruction instruction = node.first!;
    while (!identical(instruction, node.last)) {
      if (!isGenerateAtUseSite(instruction)) {
        define(instruction);
      }
      instruction = instruction.next!;
    }
    assignPhisOfSuccessors(node);
    visit(instruction);
  }

  void handleInvokeBinary(
    HInvokeBinary node,
    String op,
    SourceInformation? sourceInformation,
  ) {
    use(node.left);
    js.Expression jsLeft = pop();
    use(node.right);
    push(js.Binary(op, jsLeft, pop()).withSourceInformation(sourceInformation));
  }

  @override
  void visitLateValue(HLateValue node) {
    use(node.target);
  }

  void visitInvokeBinary(HInvokeBinary node, String op) {
    handleInvokeBinary(node, op, node.sourceInformation);
  }

  void visitRelational(HRelational node, String op) {
    handleInvokeBinary(node, op, node.sourceInformation);
  }

  // We want the outcome of bit-operations to be positive. We use the unsigned
  // shift operator to achieve this.
  void convertBitOpResultToUnsigned(HInstruction node) {
    push(
      js.Binary(
        ">>>",
        pop(),
        js.LiteralNumber("0"),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  void visitBitInvokeBinary(HBinaryBitOp node, String op) {
    visitInvokeBinary(node, op);
    if (node.requiresUintConversion) convertBitOpResultToUnsigned(node);
  }

  void visitInvokeUnary(HInvokeUnary node, String op) {
    use(node.operand);
    push(js.Prefix(op, pop()).withSourceInformation(node.sourceInformation));
  }

  void emitIdentityComparison(
    HIdentity instruction,
    SourceInformation? sourceInformation, {
    bool inverse = false,
  }) {
    String? op = instruction.singleComparisonOp;
    HInstruction left = instruction.left;
    HInstruction right = instruction.right;
    if (op != null) {
      use(left);
      js.Expression jsLeft = pop();
      use(right);
      push(
        js.Binary(
          mapRelationalOperator(op, inverse),
          jsLeft,
          pop(),
        ).withSourceInformation(sourceInformation),
      );
    } else {
      assert(NullConstantValue.jsNull == 'null');
      use(left);
      js.Binary leftEqualsNull = js.Binary("==", pop(), js.LiteralNull());
      use(right);
      js.Binary rightEqualsNull = js.Binary(
        mapRelationalOperator("==", inverse),
        pop(),
        js.LiteralNull(),
      );
      use(right);
      use(left);
      js.Binary tripleEq = js.Binary(
        mapRelationalOperator("===", inverse),
        pop(),
        pop(),
      );

      push(
        js.Conditional(
          leftEqualsNull,
          rightEqualsNull,
          tripleEq,
        ).withSourceInformation(sourceInformation),
      );
    }
  }

  @override
  void visitIdentity(HIdentity node) {
    emitIdentityComparison(node, node.sourceInformation, inverse: false);
  }

  @override
  void visitAdd(HAdd node) => visitInvokeBinary(node, '+');
  @override
  void visitDivide(HDivide node) => visitInvokeBinary(node, '/');
  @override
  void visitMultiply(HMultiply node) => visitInvokeBinary(node, '*');
  @override
  void visitSubtract(HSubtract node) => visitInvokeBinary(node, '-');
  @override
  void visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&');

  @override
  void visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|');
  @override
  void visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^');
  @override
  void visitShiftLeft(HShiftLeft node) => visitBitInvokeBinary(node, '<<');
  @override
  void visitShiftRight(HShiftRight node) => visitBitInvokeBinary(node, '>>>');

  @override
  void visitBitNot(HBitNot node) {
    visitInvokeUnary(node, '~');
    if (node.requiresUintConversion) convertBitOpResultToUnsigned(node);
  }

  @override
  void visitTruncatingDivide(HTruncatingDivide node) {
    assert(node.isUInt31(_abstractValueDomain).isDefinitelyTrue);
    // TODO(karlklose): Enable this assertion again when type propagation is
    // fixed. Issue 23555.
    //    assert(node.left.isUInt32(compiler));
    assert(node.right.isPositiveInteger(_abstractValueDomain).isDefinitelyTrue);
    use(node.left);
    js.Expression jsLeft = pop();
    use(node.right);
    push(
      js.Binary(
        '/',
        jsLeft,
        pop(),
      ).withSourceInformation(node.sourceInformation),
    );
    push(
      js.Binary(
        '|',
        pop(),
        js.LiteralNumber("0"),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitRemainder(HRemainder node) {
    return visitInvokeBinary(node, '%');
  }

  @override
  void visitNegate(HNegate node) => visitInvokeUnary(node, '-');

  @override
  void visitAbs(HAbs node) {
    use(node.operand);
    push(
      js.js('Math.abs(#)', pop()).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitLess(HLess node) => visitRelational(node, '<');
  @override
  void visitLessEqual(HLessEqual node) => visitRelational(node, '<=');
  @override
  void visitGreater(HGreater node) => visitRelational(node, '>');
  @override
  void visitGreaterEqual(HGreaterEqual node) => visitRelational(node, '>=');

  @override
  void visitExit(HExit node) {
    // Don't do anything.
  }

  @override
  void visitGoto(HGoto node) {
    HBasicBlock block = node.block!;
    assert(block.successors.length == 1);
    List<HBasicBlock> dominated = block.dominatedBlocks;
    // With the exception of the entry-node which dominates its successor
    // and the exit node, no block finishing with a 'goto' can have more than
    // one dominated block (since it has only one successor).
    // If the successor is dominated by another block, then the other block
    // is responsible for visiting the successor.
    if (dominated.isEmpty) return;
    if (dominated.length > 2) {
      failedAt(node, 'dominated.length = ${dominated.length}');
    }
    if (dominated.length == 2 && block != currentGraph.entry) {
      failedAt(node, 'node.block != currentGraph.entry');
    }
    assert(dominated[0] == block.successors[0]);
    continueSubGraph(dominated.first);
  }

  @override
  void visitLoopBranch(HLoopBranch node) {
    assert(node.block == subGraph!.end);
    // We are generating code for a loop condition.
    // If we are generating the subgraph as an expression, the
    // condition will be generated as the expression.
    // Otherwise, we don't generate the expression, and leave that
    // to the code that called [visitSubGraph].
    if (isGeneratingExpression) {
      use(node.inputs[0]);
    }
  }

  @override
  void visitBreak(HBreak node) {
    assert(node.block!.successors.length == 1);
    if (node.label != null) {
      LabelDefinition label = node.label!;
      if (breakAction.contains(label.target)) {
        implicitBreakWithLabel(label.target);
      } else {
        pushStatement(
          js.Break(
            _namer.breakLabelName(label),
          ).withSourceInformation(node.sourceInformation),
        );
      }
    } else {
      JumpTarget target = node.target;
      if (breakAction.contains(target)) {
        implicitBreakWithLabel(target);
      } else {
        if (node.breakSwitchContinueLoop) {
          pushStatement(
            js.Break(
              _namer.implicitContinueLabelName(target),
            ).withSourceInformation(node.sourceInformation),
          );
        } else {
          pushStatement(
            js.Break(null).withSourceInformation(node.sourceInformation),
          );
        }
      }
    }
  }

  @override
  void visitContinue(HContinue node) {
    assert(node.block!.successors.length == 1);
    if (node.label != null) {
      LabelDefinition label = node.label!;
      if (continueAction.contains(label)) {
        continueAsBreak(label);
      } else {
        // TODO(floitsch): should this really be the breakLabelName?
        pushStatement(
          js.Continue(
            _namer.breakLabelName(label),
          ).withSourceInformation(node.sourceInformation),
        );
      }
    } else {
      JumpTarget target = node.target;
      if (implicitContinueAction.contains(target)) {
        implicitContinueAsBreak(target);
      } else {
        if (target.isSwitch) {
          pushStatement(
            js.Continue(
              _namer.implicitContinueLabelName(target),
            ).withSourceInformation(node.sourceInformation),
          );
        } else {
          pushStatement(
            js.Continue(null).withSourceInformation(node.sourceInformation),
          );
        }
      }
    }
  }

  @override
  void visitExitTry(HExitTry node) {
    // An [HExitTry] is used to represent the control flow graph of a
    // try/catch block, ie the try body is always a predecessor
    // of the catch and finally. Here, we continue visiting the try
    // body by visiting the block that contains the user-level control
    // flow instruction.
    continueSubGraph(node.bodyTrySuccessor);
  }

  @override
  void visitTry(HTry node) {
    // We should never get here. Try/catch/finally is always handled using block
    // information in [visitTryInfo].
    failedAt(node, 'visitTry should not be called.');
  }

  bool tryControlFlowOperation(HIf node) {
    if (!controlFlowOperators.contains(node)) return false;
    final phi = node.joinBlock!.phis.first!;
    bool atUseSite = isGenerateAtUseSite(phi);
    // Don't generate a conditional operator in this situation:
    // i = condition ? bar() : i;
    // But generate this instead:
    // if (condition) i = bar();
    // Usually, the variable name is longer than 'if' and it takes up
    // more space to duplicate the name.
    if (!atUseSite &&
        variableNames.getName(phi) == variableNames.getName(phi.inputs[1])) {
      return false;
    }
    if (!atUseSite) define(phi);
    continueSubGraph(node.joinBlock!);
    return true;
  }

  void generateIf(HIf node, HIfBlockInformation info) {
    HStatementInformation? thenGraph = info.thenGraph;
    HStatementInformation? elseGraph = info.elseGraph;
    HInstruction condition = node.inputs.single;

    js.Expression test;
    js.Statement thenPart;
    js.Statement elsePart;

    HBasicBlock thenBlock = node.block!.successors[0];
    // If we believe we will generate S1 as empty, instead of
    //
    //     if (e) S1; else S2;
    //
    // try to generate
    //
    //     if (!e) S2; else S1;
    //
    // It is better to generate `!e` rather than try and negate it later.
    // Recognize a single then-block with no code and no controlled phis.
    if (isGenerateAtUseSite(condition) &&
        thenBlock.successors.length == 1 &&
        thenBlock.successors.single == node.joinBlock &&
        node.joinBlock!.phis.isEmpty &&
        thenBlock.first is HGoto) {
      generateNot(condition, condition.sourceInformation);
      test = pop();
      // Swap branches but visit in same order as register allocator.
      elsePart = unwrapStatement(generateStatementsInNewBlock(thenGraph));
      thenPart = unwrapStatement(generateStatementsInNewBlock(elseGraph));
      assert(elsePart is js.EmptyStatement);
    } else {
      use(condition);
      test = pop();
      thenPart = unwrapStatement(generateStatementsInNewBlock(thenGraph));
      elsePart = unwrapStatement(generateStatementsInNewBlock(elseGraph));
    }

    js.Statement code = _assembleIfThenElse(test, thenPart, elsePart);
    pushStatement(code.withSourceInformation(node.sourceInformation));
  }

  js.Statement _assembleIfThenElse(
    js.Expression test,
    js.Statement thenPart,
    js.Statement elsePart,
  ) {
    // Peephole rewrites:
    //
    //     if (e); else S;   -->   if (!e) S;
    //
    //     if (e);   -->   e;
    //
    // TODO(sra): We might be able to do better with reshaping the CFG.
    if (thenPart is js.EmptyStatement) {
      if (elsePart is js.EmptyStatement) {
        return js.ExpressionStatement(test);
      }
      test = js.Prefix('!', test);
      js.Statement temp = thenPart;
      thenPart = elsePart;
      elsePart = temp;
    }

    if (_options.experimentToBoolean) {
      if (elsePart is js.EmptyStatement &&
          thenPart is js.ExpressionStatement &&
          thenPart.expression is js.Call) {
        return js.ExpressionStatement(
          js.Binary('&&', test, thenPart.expression),
        );
      }
    }

    return js.If(test, thenPart, elsePart);
  }

  @override
  void visitIf(HIf node) {
    _metrics.countHIf++;
    HInstruction condition = node.inputs[0];
    if (condition is HConstant) _metrics.countHIfConstant++;

    if (tryControlFlowOperation(node)) return;

    HIfBlockInformation info =
        node.blockInformation!.body as HIfBlockInformation;

    if (condition is HConstant) {
      if (condition.constant is TrueConstantValue) {
        generateStatements(info.thenGraph);
      } else {
        generateStatements(info.elseGraph);
      }
    } else {
      generateIf(node, info);
    }

    HBasicBlock? joinBlock = node.joinBlock;
    if (joinBlock != null && !identical(joinBlock.dominator, node.block)) {
      // The join block is dominated by a block in one of the branches.
      // The subgraph traversal never reached it, so we visit it here
      // instead.
      continueSubGraph(joinBlock);
    }

    // Visit all the dominated blocks that are not part of the then or else
    // branches, and is not the join block.
    // Depending on how the then/else branches terminate
    // (e.g., return/throw/break) there can be any number of these.
    List<HBasicBlock> dominated = node.block!.dominatedBlocks;
    for (int i = 2; i < dominated.length; i++) {
      continueSubGraph(dominated[i]);
    }
  }

  @override
  void visitInterceptor(HInterceptor node) {
    _metrics.countHInterceptor.add();
    if (node.isConditionalConstantInterceptor) {
      _metrics.countHInterceptorConditionalConstant.add();
      assert(node.inputs.length == 2);
      use(node.receiver);
      js.Expression receiverExpression = pop();
      use(node.conditionalConstantInterceptor);
      js.Expression constant = pop();
      push(js.js('# && #', [receiverExpression, constant]));
    } else {
      _metrics.countHInterceptorGet.add();
      assert(node.inputs.length == 1);
      _registry.registerSpecializedGetInterceptor(node.interceptedClasses!);
      js.Name name = _namer.nameForGetInterceptor(node.interceptedClasses!);
      js.Expression isolate = _namer.readGlobalObjectForInterceptors();
      use(node.receiver);
      List<js.Expression> arguments = [pop()];
      push(
        js
            .propertyCall(isolate, name, arguments)
            .withSourceInformation(node.sourceInformation),
      );
      _registry.registerUseInterceptor();
    }
  }

  @override
  void visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
    _updateInvokeMetrics(node);
    use(node.receiver);
    js.Expression object = pop();
    String? methodName;
    List<js.Expression> arguments = visitArguments(node.inputs);
    MemberEntity? target = node.element;

    // TODO(herhut): The namer should return the appropriate backend name here.
    if (target != null && !node.isInterceptedCall) {
      if (target == _commonElements.jsArrayAdd) {
        methodName = 'push';
      } else if (target == _commonElements.jsArrayRemoveLast) {
        methodName = 'pop';
      } else if (_commonElements.isJsStringSplit(target)) {
        methodName = 'split';
        // Split returns a List, so we make sure the backend knows the
        // list class is instantiated.
        _registry
        // ignore:deprecated_member_use_from_same_package
        .registerInstantiatedClass(_commonElements.listClass);
      }
    }

    js.Name methodLiteral;
    if (methodName == null) {
      methodLiteral = _namer.invocationName(node.selector);
      registerMethodInvoke(node);
    } else {
      methodLiteral = _namer.asName(methodName);
    }
    push(
      js
          .propertyCall(object, methodLiteral, arguments)
          .withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitInvokeConstructorBody(HInvokeConstructorBody node) {
    final element = node.element as ConstructorBodyEntity;
    use(node.inputs[0]);
    js.Expression object = pop();
    js.Name methodName = _namer.instanceMethodName(element);
    List<js.Expression> arguments = visitArguments(node.inputs);
    push(
      js
          .propertyCall(object, methodName, arguments)
          .withSourceInformation(node.sourceInformation),
    );
    _registry.registerStaticUse(
      StaticUse.constructorBodyInvoke(
        element,
        CallStructure.unnamed(arguments.length),
      ),
    );
  }

  @override
  void visitInvokeGeneratorBody(HInvokeGeneratorBody node) {
    // TODO(sra): Refactor HInvokeGeneratorBody so that `node.element` has this
    // type.
    JGeneratorBody element = node.element as JGeneratorBody;
    if (element.isInstanceMember) {
      use(node.inputs[0]);
      js.Expression object = pop();
      List<js.Expression> arguments = visitArguments(node.inputs);
      js.Name methodName = _namer.instanceMethodName(element);
      push(
        js
            .propertyCall(object, methodName, arguments)
            .withSourceInformation(node.sourceInformation),
      );
    } else {
      push(_emitter.staticFunctionAccess(element));
      List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
      push(
        js.Call(pop(), arguments, sourceInformation: node.sourceInformation),
      );
    }

    _registry.registerStaticUse(StaticUse.generatorBodyInvoke(element));
  }

  @override
  void visitOneShotInterceptor(HOneShotInterceptor node) {
    _metrics.countHInterceptor.add();
    _metrics.countHInterceptorOneshot.add();
    List<js.Expression> arguments = visitArguments(node.inputs);
    js.Expression isolate = _namer.readGlobalObjectForInterceptors();
    Selector selector = node.selector;
    Set<ClassEntity> classes = _interceptorData.getInterceptedClassesOn(
      selector.name,
      _closedWorld,
    );
    _registry.registerOneShotInterceptor(selector);
    js.Name methodName = _namer.nameForOneShotInterceptor(selector, classes);
    push(
      js
          .propertyCall(isolate, methodName, arguments)
          .withSourceInformation(node.sourceInformation),
    );
    if (selector.isGetter) {
      registerGetter(node);
    } else if (selector.isSetter) {
      registerSetter(node);
    } else {
      registerMethodInvoke(node);
    }
    _registry.registerUseInterceptor();
  }

  AbstractValue getOptimizedSelectorFor(
    HInvokeDynamic node,
    Selector selector,
    AbstractValue mask,
  ) {
    if (node.element != null) {
      // Create an artificial type mask to make sure only
      // [node.element] will be enqueued. We're not using the receiver
      // type because our optimizations might end up in a state where the
      // invoke dynamic knows more than the receiver.
      ClassEntity enclosing = node.element!.enclosingClass!;
      if (_closedWorld.classHierarchy.isInstantiated(enclosing)) {
        return _abstractValueDomain.createNonNullExact(enclosing);
      } else {
        // The element is mixed in so a non-null subtype mask is the most
        // precise we have.
        assert(
          _closedWorld.isUsedAsMixin(enclosing),
          failedAt(
            node,
            "Element ${node.element} from $enclosing expected "
            "to be mixed in.",
          ),
        );
        return _abstractValueDomain.createNonNullSubtype(enclosing);
      }
    }
    return mask;
  }

  void registerMethodInvoke(HInvokeDynamic node) {
    Selector selector = node.selector;

    // If we don't know what we're calling or if we are calling a getter,
    // we need to register that fact that we may be calling a closure
    // with the same arguments.
    MemberEntity? target = node.element;
    if ((target == null || target.isGetter) &&
        // TODO(johnniwinther): Remove this when kernel adds an `isFunctionCall`
        // flag to [ir.MethodInvocation]. Currently we can't tell the difference
        // between a dynamic call and a function call, but we at least know that
        // toString is not a getter (a potential function call should otherwise
        // have been register for string concatenation).
        selector != Selectors.toString_) {
      // TODO(kasperl): If we have a typed selector for the call, we
      // may know something about the types of closures that need
      // the specific closure call method.
      Selector call = Selector.callClosureFrom(selector);
      _registry.registerDynamicUse(DynamicUse(call, null, node.typeArguments));
    }
    if (target != null) {
      // This is a dynamic invocation which we have found to have a single
      // target but for some reason haven't inlined. We are _still_ accessing
      // the target dynamically but we don't need to enqueue more than target
      // for this to work.
      assert(
        selector.applies(target),
        failedAt(node, '$selector does not apply to $target'),
      );
      assert(
        !selector.isGetter && !selector.isSetter,
        "Unexpected direct invocation selector: $selector.",
      );
      target as FunctionEntity; // TODO(sra): Make node.element have this type.
      _registry.registerStaticUse(
        StaticUse.directInvoke(
          target,
          selector.callStructure,
          node.typeArguments,
        ),
      );
    } else {
      AbstractValue mask = getOptimizedSelectorFor(
        node,
        selector,
        node.receiverType,
      );
      _registry.registerDynamicUse(
        DynamicUse(selector, mask, node.typeArguments),
      );
    }
  }

  void registerSetter(HInvokeDynamic node, {bool needsCheck = false}) {
    final element = node.element;
    if (element is FieldEntity && !needsCheck) {
      // This is a dynamic update which we have found to have a single
      // target but for some reason haven't inlined. We are _still_ accessing
      // the target dynamically but we don't need to enqueue more than target
      // for this to work.
      _registry.registerStaticUse(StaticUse.directSet(element));
    } else {
      Selector selector = node.selector;
      AbstractValue mask = getOptimizedSelectorFor(
        node,
        selector,
        node.receiverType,
      );
      _registry.registerDynamicUse(
        DynamicUse(selector, mask, node.typeArguments),
      );
    }
  }

  void registerGetter(HInvokeDynamic node) {
    final element = node.element;
    if (element != null && (element.isGetter || element is FieldEntity)) {
      // This is a dynamic read which we have found to have a single target but
      // for some reason haven't inlined. We are _still_ accessing the target
      // dynamically but we don't need to enqueue more than target for this to
      // work. The test above excludes non-getter functions since the element
      // represents two targets - a tearoff getter and the torn-off method.
      _registry.registerStaticUse(StaticUse.directGet(element));
    } else {
      Selector selector = node.selector;
      AbstractValue mask = getOptimizedSelectorFor(
        node,
        selector,
        node.receiverType,
      );
      _registry.registerDynamicUse(
        DynamicUse(selector, mask, node.typeArguments),
      );
    }
  }

  void _updateInvokeMetrics(HInvokeDynamic node) {
    if (node.element != null) _metrics.countSingleTargetInstanceCalls++;
  }

  @override
  void visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
    _updateInvokeMetrics(node);
    use(node.receiver);
    js.Name name = _namer.invocationName(node.selector);
    push(
      js
          .propertyCall(pop(), name, visitArguments(node.inputs))
          .withSourceInformation(node.sourceInformation),
    );
    registerSetter(node, needsCheck: node.needsCheck);
  }

  @override
  void visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
    _updateInvokeMetrics(node);
    use(node.receiver);
    js.Name name = _namer.invocationName(node.selector);
    push(
      js
          .propertyCall(pop(), name, visitArguments(node.inputs))
          .withSourceInformation(node.sourceInformation),
    );
    registerGetter(node);
  }

  @override
  void visitInvokeClosure(HInvokeClosure node) {
    Selector call = Selector.callClosureFrom(node.selector);
    use(node.receiver);
    push(
      js
          .propertyCall(
            pop(),
            _namer.invocationName(call),
            visitArguments(node.inputs),
          )
          .withSourceInformation(node.sourceInformation),
    );
    // TODO(kasperl): If we have a typed selector for the call, we
    // may know something about the types of closures that need
    // the specific closure call method.
    _registry.registerDynamicUse(DynamicUse(call, null, node.typeArguments));
  }

  @override
  void visitInvokeStatic(HInvokeStatic node) {
    // TODO(48820): Refactor HInvokeStatic so that the element has static type
    // FunctionEntity (`element` can be a FieldEntity in subclass HInvokeSuper,
    // so possibly make HInvokeSuper and HInvokeStatic extend a common
    // superclass, or have a different node for super-field accesses).
    FunctionEntity element = node.element as FunctionEntity;
    node.instantiatedTypes?.forEach(_registry.registerInstantiation);

    List<js.Expression> arguments = visitArguments(node.inputs, start: 0);

    if (element == _commonElements.jsAllowInterop) {
      _nativeData.registerAllowInterop();
    }

    if (_commonElements.isCheckConcurrentModificationError(element)) {
      // Manually inline the [checkConcurrentModificationError] function.  This
      // function is only called from a for-loop update.  Ideally we would just
      // generate the conditional control flow in the builder but it adds basic
      // blocks in the loop update that interfere with other optimizations and
      // confuses loop recognition.

      assert(arguments.length == 2);
      FunctionEntity throwFunction =
          _commonElements.throwConcurrentModificationError;
      _registry.registerStaticUse(
        StaticUse.staticInvoke(throwFunction, CallStructure.oneArg),
      );

      // Calling using `(0, #)(#)` instead of `#(#)` separates the property load
      // of the static function access from the call.  For some reason this
      // helps V8 see that the call never happens so V8 makes the call a
      // deoptimization. This removes the call from the optimized loop, making
      // more optimizations available to the loop.  This form is 50% faster on
      // some small loop, almost as fast as loops with no concurrent
      // modification check.

      // Create [right] as a separate JS node to give the call a source
      // location.
      js.Expression right = js
          .js('(0, #)(#)', [
            _emitter.staticFunctionAccess(throwFunction),
            arguments[1],
          ])
          .withSourceInformation(node.sourceInformation);
      push(
        js
            .js('# || #', [arguments[0], right])
            .withSourceInformation(node.sourceInformation),
      );
    } else {
      StaticUse staticUse;
      Object? resourceIdentifierAnnotation;
      if (element is ConstructorEntity) {
        CallStructure callStructure = CallStructure.unnamed(
          arguments.length,
          node.typeArguments.length,
        );
        staticUse = StaticUse.constructorInvoke(element, callStructure);
      } else if (element.isGetter) {
        staticUse = StaticUse.staticGet(element);
      } else if (element.isSetter) {
        staticUse = StaticUse.staticSet(element);
      } else {
        assert(element.isFunction);
        CallStructure callStructure = CallStructure.unnamed(
          arguments.length,
          node.typeArguments.length,
        );
        staticUse = StaticUse.staticInvoke(
          element,
          callStructure,
          node.typeArguments,
        );
        if (_closedWorld.annotationsData.methodIsResourceIdentifier(element)) {
          resourceIdentifierAnnotation = _methodResourceIdentifier(
            element,
            callStructure,
            node.inputs,
            node.sourceInformation,
          );
        }
      }
      _registry.registerStaticUse(staticUse);
      push(_emitter.staticFunctionAccess(element));
      push(
        js.Call(pop(), arguments, sourceInformation: node.sourceInformation),
      );
      if (resourceIdentifierAnnotation != null) {
        push(pop().withAnnotation(resourceIdentifierAnnotation));
      }
    }
  }

  ResourceIdentifier _methodResourceIdentifier(
    FunctionEntity element,
    CallStructure callStructure,
    List<HInstruction> arguments,
    SourceInformation? sourceInformation,
  ) {
    ConstantValue? findConstant(HInstruction node) {
      while (node is HLateValue) {
        node = node.target;
      }
      return node is HConstant ? node.constant : null;
    }

    final definition = _closedWorld.elementMap.getMemberDefinition(element);
    final uri = definition.location.uri;

    final builder = ResourceIdentifierBuilder(element.name!, uri);

    if (sourceInformation != null) {
      _addSourceInformationToResourceIdentiferBuilder(
        builder,
        sourceInformation,
      );
    }
    for (int i = 0; i < arguments.length; i++) {
      builder.add('${i + 1}', findConstant(arguments[i]));
    }

    return builder.finish();
  }

  void _addSourceInformationToResourceIdentiferBuilder(
    ResourceIdentifierBuilder builder,
    SourceInformation sourceInformation,
  ) {
    SourceLocation? location =
        sourceInformation.startPosition ??
        sourceInformation.innerPosition ??
        sourceInformation.endPosition;
    if (location != null) {
      final sourceUri = location.sourceUri;
      if (sourceUri != null) {
        // Is [sourceUri] normalized in some way or does that need to be done
        // here?
        builder.addLocation(sourceUri, location.line, location.column);
      }
    }
  }

  @override
  void visitInvokeSuper(HInvokeSuper node) {
    MemberEntity superElement = node.element;
    Selector selector = node.selector;
    bool useAliasedSuper = canUseAliasedSuperMember(superElement, selector);
    if (selector.isGetter) {
      if (superElement is FieldEntity || superElement.isGetter) {
        _registry.registerStaticUse(StaticUse.superGet(superElement));
      } else {
        superElement as FunctionEntity; // Not a field so must be a function.
        _registry.registerStaticUse(StaticUse.superTearOff(superElement));
      }
    } else if (selector.isSetter) {
      if (superElement is FieldEntity) {
        _registry.registerStaticUse(StaticUse.superFieldSet(superElement));
      } else {
        assert(superElement.isSetter);
        superElement as FunctionEntity; // Not a field so must be a function.
        _registry.registerStaticUse(StaticUse.superSetterSet(superElement));
      }
    } else {
      superElement as FunctionEntity; // Not a field so must be a function.
      if (useAliasedSuper) {
        _registry.registerStaticUse(
          StaticUse.superInvoke(
            superElement,
            CallStructure.unnamed(node.inputs.length),
          ),
        );
      } else {
        _registry.registerStaticUse(
          StaticUse.superInvoke(
            superElement,
            CallStructure.unnamed(node.inputs.length - 1),
          ),
        );
      }
    }

    if (superElement is FieldEntity) {
      // TODO(sra): We can lower these in the simplifier.
      js.Name fieldName = _namer.instanceFieldPropertyName(superElement);
      use(node.getDartReceiver(_closedWorld));
      js.PropertyAccess access =
          js.PropertyAccess(
                pop(),
                fieldName,
              ).withSourceInformation(node.sourceInformation)
              as js.PropertyAccess;
      if (node.isSetter) {
        use(node.value);
        push(
          js.Assignment(
            access,
            pop(),
          ).withSourceInformation(node.sourceInformation),
        );
      } else {
        push(access);
      }
    } else if (superElement is FunctionEntity) {
      if (!useAliasedSuper) {
        js.Name methodName;
        if (selector.isGetter && !superElement.isGetter) {
          // If this is a tear-off, register the fact that a tear-off closure
          // will be created, and that this tear-off must bypass ordinary
          // dispatch to ensure the super method is invoked.
          FunctionEntity helper = _commonElements.closureFromTearOff;
          _registry.registerStaticUse(
            StaticUse.staticInvoke(
              helper,
              CallStructure.unnamed(
                node.inputs.length,
                node.typeArguments.length,
              ),
              node.typeArguments,
            ),
          );
          methodName = _namer.invocationName(selector);
        } else {
          methodName = _namer.instanceMethodName(superElement);
        }

        ClassEntity superClass = superElement.enclosingClass!;
        push(
          js
              .js('#.#.call(#)', [
                _emitter.prototypeAccess(superClass),
                methodName,
                visitArguments(node.inputs, start: 0),
              ])
              .withSourceInformation(node.sourceInformation),
        );
      } else {
        use(node.receiver);
        push(
          js
              .js('#.#(#)', [
                pop(),
                _namer.aliasedSuperMemberPropertyName(superElement),
                visitArguments(node.inputs, start: 1),
              ]) // Skip receiver argument.
              .withSourceInformation(node.sourceInformation),
        );
      }
    } else {
      failedAt(node, 'node.element must be FieldEntity or FunctionEntity');
    }
  }

  js.Expression _loadField(
    js.Expression receiver,
    FieldEntity field,
    SourceInformation? sourceInformation,
  ) {
    _registry.registerStaticUse(StaticUse.fieldGet(field));
    js.Name name = _namer.instanceFieldPropertyName(field);
    return js.PropertyAccess(
      receiver,
      name,
    ).withSourceInformation(sourceInformation);
  }

  @override
  void visitFieldGet(HFieldGet node) {
    _metrics.countHFieldGet++;
    use(node.receiver);
    push(_loadField(pop(), node.element, node.sourceInformation));
  }

  @override
  void visitFieldSet(HFieldSet node) {
    FieldEntity element = node.element;
    _registry.registerStaticUse(StaticUse.fieldSet(element));
    js.Name name = _namer.instanceFieldPropertyName(element);
    use(node.receiver);
    js.Expression receiver = pop();
    use(node.value);
    push(
      js.Assignment(
        js.PropertyAccess(
          receiver,
          name,
        ).withSourceInformation(node.sourceInformation),
        pop(),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitGetLength(HGetLength node) {
    _metrics.countHGetLength++;
    use(node.receiver);
    push(
      js.PropertyAccess.field(
        pop(),
        'length',
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitReadModifyWrite(HReadModifyWrite node) {
    FieldEntity element = node.element;
    _registry.registerStaticUse(StaticUse.fieldGet(element));
    _registry.registerStaticUse(StaticUse.fieldSet(element));
    js.Name name = _namer.instanceFieldPropertyName(element);
    use(node.receiver);
    js.Expression fieldReference = js.PropertyAccess(pop(), name);
    switch (node.opKind) {
      case ReadModifyWriteKind.prefix:
        push(
          js.Prefix(
            node.jsOp,
            fieldReference,
          ).withSourceInformation(node.sourceInformation),
        );
      case ReadModifyWriteKind.postfix:
        push(
          js.Postfix(
            node.jsOp,
            fieldReference,
          ).withSourceInformation(node.sourceInformation),
        );
      case ReadModifyWriteKind.assign:
        use(node.value);
        push(
          js.Assignment.compound(
            fieldReference,
            node.jsOp,
            pop(),
          ).withSourceInformation(node.sourceInformation),
        );
    }
  }

  @override
  void visitFunctionReference(HFunctionReference node) {
    FunctionEntity element = node.element;
    _registry.registerStaticUse(StaticUse.implicitInvoke(element));
    push(_emitter.staticFunctionAccess(element));
  }

  @override
  void visitLocalGet(HLocalGet node) {
    use(node.receiver);
  }

  @override
  void visitLocalSet(HLocalSet node) {
    use(node.value);
    assignVariable(
      variableNames.getName(node.receiver)!,
      pop(),
      node.sourceInformation,
    );
  }

  @override
  void visitInvokeExternal(HInvokeExternal node) {
    FunctionEntity target = node.element;
    List<HInstruction> inputs = node.inputs;

    assert(_nativeData.isNativeMember(target), 'non-native target: $node');

    String? targetName =
        _nativeData.hasFixedBackendName(target)
            ? _nativeData.getFixedBackendName(target)
            : target.name;

    void invokeWithJavaScriptReceiver(js.Expression receiverExpression) {
      // JS-interop target names can be paths ("a.b"), so we parse them to
      // re-associate the property accesses ("#.a.b" is `dot(dot(#,'a'),'b')`).
      //
      // Native target names are simple identifiers, so re-parsing is not
      // necessary, but it is simpler to use the same code.
      String template;
      List<Object> templateInputs;
      if (target.isGetter) {
        template = '#.$targetName';
        templateInputs = [receiverExpression];
      } else if (target.isSetter) {
        assert(inputs.length == (target.isInstanceMember ? 2 : 1));
        use(inputs.last);
        template = '#.$targetName = #';
        templateInputs = [receiverExpression, pop()];
      } else {
        var arguments = visitArguments(
          inputs,
          start: target.isInstanceMember ? 1 : 0,
        );
        template =
            target is ConstructorEntity
                ? 'new #.$targetName(#)'
                : '#.$targetName(#)';
        templateInputs = [receiverExpression, arguments];
      }
      js.Expression expression = js.js
          .uncachedExpressionTemplate(template)
          .instantiateExpression(templateInputs);
      push(expression.withSourceInformation(node.sourceInformation));
      _registry.registerNativeMethod(target);
    }

    if (_nativeData.isJsInteropMember(target)) {
      if (target.isStatic || target.isTopLevel || target is ConstructorEntity) {
        String path = _nativeData.getFixedBackendMethodPath(target)!;
        js.Expression pathExpression = js.js
            .uncachedExpressionTemplate(path)
            .instantiateExpression([]);
        invokeWithJavaScriptReceiver(pathExpression);
        return;
      }
    }

    if (_nativeData.isNativeMember(target)) {
      _registry.registerNativeBehavior(node.nativeBehavior!);
      if (target.isInstanceMember) {
        HInstruction receiver = inputs.first;
        use(receiver);
        invokeWithJavaScriptReceiver(pop());
        return;
      }
      if (target.isStatic || target.isTopLevel) {
        var arguments = visitArguments(inputs, start: 0);
        js.Expression targetExpression = js.js
            .uncachedExpressionTemplate(targetName!)
            .instantiateExpression([]);
        js.Expression expression;
        if (target.isGetter) {
          expression = targetExpression;
        } else if (target.isSetter) {
          expression = js.js('# = #', [targetExpression, inputs.single]);
        } else {
          assert(target.isFunction);
          expression = js.js('#(#)', [targetExpression, arguments]);
        }
        push(expression.withSourceInformation(node.sourceInformation));
        _registry.registerNativeMethod(target);
        return;
      }

      failedAt(node, 'codegen not implemented (non-instance-member): $node');
    }
    failedAt(node, 'unexpected target: $node');
  }

  void registerForeignTypes(HForeign node) {
    NativeBehavior? nativeBehavior = node.nativeBehavior;
    if (nativeBehavior == null) return;
    _registry.registerNativeBehavior(nativeBehavior);
  }

  @override
  void visitForeignCode(HForeignCode node) {
    List<HInstruction> inputs = node.inputs;
    if (node.isJsStatement()) {
      List<js.Expression> interpolatedExpressions = [];
      for (int i = 0; i < inputs.length; i++) {
        use(inputs[i]);
        interpolatedExpressions.add(pop());
      }
      pushStatement(
        node.codeTemplate
            .instantiateStatement(interpolatedExpressions)
            .withSourceInformation(node.sourceInformation),
      );
    } else {
      List<js.Expression> interpolatedExpressions = [];
      for (int i = 0; i < inputs.length; i++) {
        use(inputs[i]);
        interpolatedExpressions.add(pop());
      }
      push(
        node.codeTemplate
            .instantiateExpression(interpolatedExpressions)
            .withSourceInformation(node.sourceInformation),
      );
    }

    // TODO(sra): Tell world.nativeEnqueuer about the types created here.
    registerForeignTypes(node);
  }

  @override
  void visitCreate(HCreate node) {
    js.Expression jsClassReference = _emitter.constructorAccess(node.element);
    List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
    push(
      js.New(
        jsClassReference,
        arguments,
      ).withSourceInformation(node.sourceInformation),
    );
    // We also use HCreate to instantiate closure classes that belong to
    // function expressions. We have to register their use here, as otherwise
    // code for them might not be emitted.
    if (node.element.isClosure) {
      _registry
      // ignore:deprecated_member_use_from_same_package
      .registerInstantiatedClass(node.element);
    }
    if (node.element is JRecordClass) {
      _registry
      // ignore:deprecated_member_use_from_same_package
      .registerInstantiatedClass(node.element);
    }
    node.instantiatedTypes?.forEach(_registry.registerInstantiation);
    final callMethod = node.callMethod;
    if (callMethod != null) {
      _registry.registerStaticUse(StaticUse.implicitInvoke(callMethod));
      _registry.registerInstantiatedClosure(callMethod);
    }
  }

  @override
  void visitCreateBox(HCreateBox node) {
    push(js.ObjectInitializer([]));
  }

  js.Expression newLiteralBool(
    bool value,
    SourceInformation? sourceInformation,
  ) {
    if (_options.enableMinification) {
      // Use !0 for true, !1 for false.
      return js.Prefix(
        "!",
        js.LiteralNumber(value ? "0" : "1"),
      ).withSourceInformation(sourceInformation);
    } else {
      return js.LiteralBool(value).withSourceInformation(sourceInformation);
    }
  }

  void generateConstant(
    ConstantValue constant,
    SourceInformation? sourceInformation,
  ) {
    js.Expression expression = _emitter.constantReference(constant);
    if (!constant.isDummy) {
      // TODO(johnniwinther): Support source information on synthetic constants.
      expression = expression.withSourceInformation(sourceInformation);
    }
    push(expression);
  }

  @override
  void visitConstant(HConstant node) {
    assert(isGenerateAtUseSite(node));
    generateConstant(node.constant, node.sourceInformation);

    _registry.registerConstantUse(ConstantUse.literal(node.constant));
    ConstantValue constant = node.constant;
    if (constant is TypeConstantValue) {
      _registry.registerTypeUse(
        TypeUse.constTypeLiteral(constant.representedType),
      );
    }
  }

  @override
  void visitNot(HNot node) {
    assert(node.inputs.length == 1);
    generateNot(node.inputs[0], node.sourceInformation);
  }

  static String mapRelationalOperator(String op, bool inverse) {
    Map<String, String> inverseOperator = const {
      "==": "!=",
      "!=": "==",
      "===": "!==",
      "!==": "===",
      "<": ">=",
      "<=": ">",
      ">": "<=",
      ">=": "<",
    };
    return inverse ? inverseOperator[op]! : op;
  }

  void generateNot(HInstruction input, SourceInformation? sourceInformation) {
    bool canGenerateOptimizedComparison(HRelational relational) {
      HInstruction left = relational.left;
      HInstruction right = relational.right;
      if (left.isStringOrNull(_abstractValueDomain).isDefinitelyTrue &&
          right.isStringOrNull(_abstractValueDomain).isDefinitelyTrue) {
        return true;
      }

      // This optimization doesn't work for NaN, so we only do it if the
      // type is known to be an integer.
      return left.isInteger(_abstractValueDomain).isDefinitelyTrue &&
          right.isInteger(_abstractValueDomain).isDefinitelyTrue;
    }

    bool handledBySpecialCase = false;
    if (isGenerateAtUseSite(input)) {
      handledBySpecialCase = true;
      if (input is HIsTestSimple) {
        _emitIsTestSimple(input, negative: true);
      } else if (input is HNot) {
        use(input.inputs[0]);
      } else if (input is HIdentity) {
        emitIdentityComparison(input, sourceInformation, inverse: true);
      } else if (input is HIsLateSentinel) {
        _emitIsLateSentinel(input, sourceInformation, inverse: true);
      } else if (input is HRelational &&
          canGenerateOptimizedComparison(input)) {
        constant_system.BinaryOperation operation = input.operation();
        String op = mapRelationalOperator(operation.name, true);
        handleInvokeBinary(input, op, sourceInformation);
      } else {
        handledBySpecialCase = false;
      }
    }
    if (!handledBySpecialCase) {
      use(input);
      push(js.Prefix("!", pop()).withSourceInformation(sourceInformation));
    }
  }

  @override
  void visitParameterValue(HParameterValue node) {
    assert(!isGenerateAtUseSite(node));
    String name = variableNames.getName(node)!;
    parameters.add(js.Parameter(name));
    declaredLocals.add(name);
  }

  @override
  void visitLocalValue(HLocalValue node) {
    assert(!isGenerateAtUseSite(node));
    String name = variableNames.getName(node)!;
    collectedVariableDeclarations.add(name);
  }

  @override
  void visitPhi(HPhi node) {
    // This method is only called for phis that are generated at use
    // site. A phi can be generated at use site only if it is the
    // result of a control flow operation.
    HBasicBlock ifBlock = node.block!.dominator!;
    assert(controlFlowOperators.contains(ifBlock.last));
    HInstruction input = ifBlock.last!.inputs[0];
    if (input.isConstantFalse()) {
      use(node.inputs[1]);
    } else if (input.isConstantTrue()) {
      use(node.inputs[0]);
    } else if (node.inputs[1].isConstantBoolean()) {
      String operation = node.inputs[1].isConstantFalse() ? '&&' : '||';
      if (operation == '||') {
        generateNot(input, input.sourceInformation);
      } else {
        use(input);
      }
      js.Expression left = pop();
      use(node.inputs[0]);
      push(js.Binary(operation, left, pop()));
    } else {
      use(input);
      js.Expression test = pop();
      use(node.inputs[0]);
      js.Expression then = pop();
      use(node.inputs[1]);
      push(js.Conditional(test, then, pop()));
    }
  }

  @override
  void visitReturn(HReturn node) {
    if (node.inputs.isEmpty) {
      pushStatement(js.Return().withSourceInformation(node.sourceInformation));
    } else {
      use(node.inputs.single);
      pushStatement(
        js.Return(pop()).withSourceInformation(node.sourceInformation),
      );
    }
  }

  @override
  void visitThis(HThis node) {
    push(js.This());
  }

  @override
  void visitThrow(HThrow node) {
    SourceInformation? sourceInformation = node.sourceInformation;
    if (node.isRethrow) {
      use(node.inputs[0]);
      pushStatement(js.Throw(pop()).withSourceInformation(sourceInformation));
    } else {
      use(node.inputs[0]);
      if (node.withoutHelperFrame) {
        _pushCallStatic(_commonElements.initializeExceptionWrapper, [
          pop(),
          _newErrorObject(sourceInformation),
        ], sourceInformation);
      } else {
        _pushCallStatic(_commonElements.wrapExceptionHelper, [
          pop(),
        ], sourceInformation);
      }
      pushStatement(js.Throw(pop()).withSourceInformation(sourceInformation));
    }
  }

  js.Expression _newErrorObject(SourceInformation? sourceInformation) {
    return js.js('new Error()').withSourceInformation(sourceInformation);
  }

  @override
  void visitAwait(HAwait node) {
    use(node.inputs[0]);
    push(js.Await(pop()).withSourceInformation(node.sourceInformation));
  }

  @override
  void visitYield(HYield node) {
    use(node.inputs[0]);
    pushStatement(
      js.DartYield(
        pop(),
        node.hasStar,
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitRangeConversion(HRangeConversion node) {
    // Range conversion instructions are removed by the value range
    // analyzer.
    assert(false);
  }

  @override
  void visitBoundsCheck(HBoundsCheck node) {
    // TODO(ngeoffray): Separate the two checks of the bounds check, so,
    // e.g., the zero checks can be shared if possible.

    // If the checks always succeeds, we would have removed the bounds check
    // completely.
    assert(node.staticChecks != StaticBoundsChecks.alwaysTrue);

    if (node.staticChecks == StaticBoundsChecks.alwaysFalse) {
      _pushThrowWithHelper(
        _commonElements.throwIndexOutOfRangeException,
        [node.array, node.reportedIndex],
        sourceInformation: node.sourceInformation,
      );
      return;
    }

    HInstruction index = node.index;

    // Generate a test for out-of-bounds, either under or over the range.  NaN
    // values can creep in, and comparisons on NaN are false, so
    //
    //     if (i < 0) throw ...
    //
    // will fail to throw if `i` is NaN. The test
    //
    //     if (!(i >= 0)) ...
    //
    // is 'NaN-safe'.

    // TODO(sra): Better analysis of possible NaN input.
    bool indexCanBeNaN = !_isDefinitelyNotNaN(index);

    js.Expression? under;
    js.Expression? over;

    if (index.isInteger(_abstractValueDomain).isPotentiallyFalse) {
      // Combined domain check and low bound check. `a >>> 0 !== a` is true for
      // `null`, `undefined`, `NaN`, and non-integral number and any integral
      // number outside the 32-bit unsigned range.
      use(index);
      js.Expression jsIndex = pop();
      // This test is 'NaN-safe' since `a!==b` is the same as `!(a===b)`.
      under = js.js("# >>> 0 !== #", [jsIndex, jsIndex]);
      indexCanBeNaN = false;
    } else if (node.staticChecks != StaticBoundsChecks.alwaysAboveZero) {
      use(index);
      // The index must be an `int`, otherwise we could have used the combined
      // check above.
      if (indexCanBeNaN) {
        under = js.js('!(# >= 0)', pop());
      } else {
        under = js.js('# < 0', pop());
      }
    }

    if (node.staticChecks != StaticBoundsChecks.alwaysBelowLength) {
      use(index);
      js.Expression jsIndex = pop();
      use(node.length);
      js.Expression jsLength = pop();
      if (indexCanBeNaN) {
        over = js.js('!(# < #)', [jsIndex, jsLength]);
      } else {
        over = js.js('# >= #', [jsIndex, jsLength]);
      }
    }

    assert(over != null || under != null);
    js.Expression underOver;
    if (under == null) {
      underOver = over!;
    } else if (over == null) {
      underOver = under;
    } else {
      if (under is js.Prefix &&
          under.op == '!' &&
          over is js.Prefix &&
          over.op == '!') {
        // De Morgans law:  !(a) || !(b)  <->  !(a && b)
        underOver = js.js('!(# && #)', [under.argument, over.argument]);
      } else {
        underOver = js.Binary('||', under, over);
      }
    }

    // Generate the call to the 'throw' helper in a block in case it needs
    // multiple statements.
    js.Block thenBody = js.Block.empty();
    js.Block oldContainer = currentContainer;
    currentContainer = thenBody;
    _pushThrowWithHelper(
      _commonElements.throwIndexOutOfRangeException,
      [node.array, node.reportedIndex],
      sourceInformation: node.sourceInformation,
    );
    currentContainer = oldContainer;
    pushStatement(
      js.If.noElse(
        underOver,
        unwrapStatement(thenBody),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  bool _isDefinitelyNotNaN(HInstruction node) {
    if (node is HConstant) {
      if (node.isInteger(_abstractValueDomain).isDefinitelyTrue) return true;
      return false;
    }

    // TODO(sra): Use some form of dataflow. Starting from a small number you
    // can add or subtract a small number any number of times and still have a
    // finite number. Many operations, produce small numbers (some constants,
    // HGetLength, HBitAnd). This could be used to determine that most loop
    // indexes are finite and thus not NaN.

    return false;
  }

  void _pushThrowWithHelper(
    FunctionEntity helper,
    List<HInstruction> inputs, {
    SourceInformation? sourceInformation,
  }) {
    List<js.Expression> arguments = [];
    for (final input in inputs) {
      use(input);
      arguments.add(pop());
    }
    _pushCallStatic(helper, arguments, sourceInformation);
    // BUG(4906): Using throw/return here adds to the size of the generated code
    // but it has the advantage of explicitly telling the JS engine that
    // this code path will terminate abruptly. Needs more work.
    pushStatement(js.Return(pop()).withSourceInformation(sourceInformation));
  }

  void _pushCallStatic(
    FunctionEntity target,
    List<js.Expression> arguments,
    SourceInformation? sourceInformation,
  ) {
    _registry.registerStaticUse(
      StaticUse.staticInvoke(target, CallStructure.unnamed(arguments.length)),
    );
    js.Expression jsTarget = _emitter.staticFunctionAccess(target);
    js.Call call = js.Call(
      jsTarget,
      List.of(arguments, growable: false),
      sourceInformation: sourceInformation,
    );
    push(call);
  }

  @override
  void visitThrowExpression(HThrowExpression node) {
    use(node.inputs[0]);
    _pushCallStatic(_commonElements.throwExpressionHelper, [
      pop(),
      if (node.withoutHelperFrame) _newErrorObject(node.sourceInformation),
    ], node.sourceInformation);
  }

  @override
  void visitSwitch(HSwitch node) {
    // Switches are handled using [visitSwitchInfo].
  }

  @override
  void visitStatic(HStatic node) {
    MemberEntity element = node.element;
    if (element is FunctionEntity) {
      // TODO(sra): Static tear-offs should be constants.
      push(
        _emitter
            .staticClosureAccess(element)
            .withSourceInformation(node.sourceInformation),
      );
      _registry.registerStaticUse(StaticUse.staticTearOff(element));
    } else if (element is FieldEntity) {
      push(
        _emitter
            .staticFieldAccess(element)
            .withSourceInformation(node.sourceInformation),
      );
      _registry.registerStaticUse(StaticUse.staticGet(element));
    } else {
      failedAt(node, 'HStatic must be a FieldEntity or FunctionEntity');
    }
  }

  @override
  void visitLazyStatic(HLazyStatic node) {
    FieldEntity element = node.element;
    _registry.registerStaticUse(StaticUse.staticInit(element));
    js.Expression lazyGetter = _emitter.isolateLazyInitializerAccess(element);
    js.Call call = js.Call(
      lazyGetter,
      [],
      sourceInformation: node.sourceInformation,
    );
    push(call);
  }

  @override
  void visitStaticStore(HStaticStore node) {
    _registry.registerStaticUse(StaticUse.staticSet(node.element));
    js.Expression variable = _emitter.staticFieldAccess(node.element);
    use(node.inputs[0]);
    push(
      js.Assignment(
        variable,
        pop(),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitStringConcat(HStringConcat node) {
    use(node.left);
    js.Expression jsLeft = pop();
    use(node.right);
    push(
      js.Binary(
        '+',
        jsLeft,
        pop(),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitStringify(HStringify node) {
    HInstruction input = node.inputs.first;
    if (input.isString(_abstractValueDomain).isDefinitelyTrue) {
      use(input);
    } else if (input.isInteger(_abstractValueDomain).isDefinitelyTrue ||
        input.isBoolean(_abstractValueDomain).isDefinitelyTrue) {
      // JavaScript's + operator with a string for the left operand will convert
      // the right operand to a string, and the conversion result is correct.
      use(input);
      if (node.usedBy.length == 1 &&
          node.usedBy[0] is HStringConcat &&
          node.usedBy[0].inputs[1] == node) {
        // The context is already <string> + value.
      } else {
        // Force an empty string for the first operand.
        push(
          js.Binary(
            '+',
            js.string(""),
            pop(),
          ).withSourceInformation(node.sourceInformation),
        );
      }
    } else {
      FunctionEntity convertToString =
          _commonElements.stringInterpolationHelper;
      _registry.registerStaticUse(
        StaticUse.staticInvoke(convertToString, CallStructure.oneArg),
      );
      js.Expression jsHelper = _emitter.staticFunctionAccess(convertToString);
      use(input);
      push(
        js.Call(jsHelper, [pop()], sourceInformation: node.sourceInformation),
      );
    }
  }

  @override
  void visitLiteralList(HLiteralList node) {
    _registry
    // ignore:deprecated_member_use_from_same_package
    .registerInstantiatedClass(_commonElements.listClass);
    generateArrayLiteral(node);
  }

  void generateArrayLiteral(HLiteralList node) {
    List<js.Expression> elements =
        node.inputs.map((HInstruction input) {
          use(input);
          return pop();
        }).toList();
    push(
      js.ArrayInitializer(
        elements,
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitIndex(HIndex node) {
    _metrics.countHIndex++;
    use(node.receiver);
    js.Expression receiver = pop();
    use(node.index);
    push(
      js.PropertyAccess(
        receiver,
        pop(),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitIndexAssign(HIndexAssign node) {
    use(node.receiver);
    js.Expression receiver = pop();
    use(node.index);
    js.Expression index = pop();
    use(node.value);
    push(
      js.Assignment(
        js.PropertyAccess(receiver, index),
        pop(),
      ).withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitCharCodeAt(HCharCodeAt node) {
    use(node.receiver);
    js.Expression receiver = pop();
    use(node.index);
    push(
      js
          .js('#.charCodeAt(#)', [receiver, pop()])
          .withSourceInformation(node.sourceInformation),
    );
  }

  void checkTypeOf(
    HInstruction input,
    String cmp,
    String typeName,
    SourceInformation? sourceInformation,
  ) {
    use(input);
    js.Expression typeOf = js.Prefix("typeof", pop());
    push(
      js.Binary(
        cmp,
        typeOf,
        js.string(typeName),
      ).withSourceInformation(sourceInformation),
    );
  }

  void checkNum(
    HInstruction input,
    String cmp,
    SourceInformation? sourceInformation,
  ) {
    return checkTypeOf(input, cmp, 'number', sourceInformation);
  }

  void checkBool(
    HInstruction input,
    String cmp,
    SourceInformation? sourceInformation,
  ) {
    return checkTypeOf(input, cmp, 'boolean', sourceInformation);
  }

  @override
  void visitPrimitiveCheck(HPrimitiveCheck node) {
    js.Expression test = _generateReceiverOrArgumentTypeTest(node);
    js.Block oldContainer = currentContainer;
    js.Block body = currentContainer = js.Block.empty();
    final sourceInformation = node.sourceInformation;
    switch (node.kind) {
      case PrimitiveCheckKind.argumentType:
        use(node.checkedInput);
        _pushCallStatic(_commonElements.throwIllegalArgumentException, [
          pop(),
        ], node.sourceInformation);
        pushStatement(
          js.Return(pop()).withSourceInformation(sourceInformation),
        );
      case PrimitiveCheckKind.receiverType:
        use(node.checkedInput);
        js.Name methodName = _namer.invocationName(
          node.receiverTypeCheckSelector!,
        );
        js.Expression call = js
            .propertyCall(pop(), methodName, [])
            .withSourceInformation(sourceInformation);
        pushStatement(js.Return(call).withSourceInformation(sourceInformation));
    }
    currentContainer = oldContainer;
    final then = unwrapStatement(body);
    pushStatement(
      js.If.noElse(test, then).withSourceInformation(sourceInformation),
    );
  }

  js.Expression _generateReceiverOrArgumentTypeTest(HPrimitiveCheck node) {
    DartType type = node.typeExpression;
    HInstruction input = node.checkedInput;
    AbstractValue checkedType = node.checkedType;
    // This path is no longer used for indexable primitive types.
    assert(_abstractValueDomain.isJsIndexable(checkedType).isPotentiallyFalse);
    // Figure out if it is beneficial to use a null check.  V8 generally prefers
    // 'typeof' checks, but for integers we cannot compile this test into a
    // single typeof check so the null check is cheaper.
    if (type == _commonElements.numType) {
      // input is !num
      checkNum(input, '!==', input.sourceInformation);
      return pop();
    }
    if (type == _commonElements.boolType) {
      // input is !bool
      checkBool(input, '!==', input.sourceInformation);
      return pop();
    }
    throw failedAt(input, 'Unexpected check: $type.');
  }

  @override
  void visitNullCheck(HNullCheck node) {
    use(node.checkedInput);
    // We access a JavaScript member 'toString' as all objects besides `null`
    // and `undefined` have it.

    // TODO(35996): Pick a shorter field. The instruction has a selector and
    // field that could be used here to pick the 'right' field. The 'field'
    // might need to be propagated to an earlier HNullCheck. JSArray and
    // JSString have 'length'.
    pushStatement(
      js.ExpressionStatement(
        js.PropertyAccess.field(
          pop(),
          'toString',
        ).withSourceInformation(node.sourceInformation),
      ),
    );
  }

  @override
  void visitLateReadCheck(HLateReadCheck node) {
    // We generate code roughly equivalent to invoking:
    //
    // T _lateReadCheck<T>(T value, String name) {
    //   if (isSentinel(value)) throw LateError.fieldNI(name);
    //   return value;
    // }

    assert(!node.isRedundant(_closedWorld));

    final sourceInformation = node.sourceInformation;

    _emitIsLateSentinel(node.checkedInput, sourceInformation);
    final condition = pop();

    if (node.hasName) {
      use(node.name);
      _pushCallStatic(_commonElements.throwLateFieldNI, [
        pop(),
      ], sourceInformation);
    } else {
      _pushCallStatic(
        _commonElements.throwUnnamedLateFieldNI,
        const [],
        sourceInformation,
      );
    }

    // `condition && helper();` is smaller than `if (condition) helper();`.
    pushStatement(
      js.js
          .statement('# && #;', [condition, pop()])
          .withSourceInformation(sourceInformation),
    );
  }

  @override
  void visitLateWriteOnceCheck(HLateWriteOnceCheck node) {
    // We generate code roughly equivalent to invoking:
    //
    // void _lateWriteOnceCheck(Object? value, String name) {
    //   if (!isSentinel(value)) throw LateError.fieldAI(name);
    // }

    assert(!node.isRedundant(_closedWorld));

    final sourceInformation = node.sourceInformation;
    _emitIsLateSentinel(node.checkedInput, sourceInformation, inverse: true);
    final condition = pop();

    if (node.hasName) {
      use(node.name);
      _pushCallStatic(_commonElements.throwLateFieldAI, [
        pop(),
      ], sourceInformation);
    } else {
      _pushCallStatic(
        _commonElements.throwUnnamedLateFieldAI,
        [],
        sourceInformation,
      );
    }

    // `condition && helper();` is smaller than `if (condition) helper();`.
    pushStatement(
      js.js
          .statement('# && #;', [condition, pop()])
          .withSourceInformation(sourceInformation),
    );
  }

  @override
  void visitLateInitializeOnceCheck(HLateInitializeOnceCheck node) {
    // We generate code roughly equivalent to invoking:
    //
    // void _lateInitializeOnceCheck(Object? value, String name) {
    //   if (!isSentinel(value)) throw LateError.fieldADI(name);
    // }

    assert(!node.isRedundant(_closedWorld));

    final sourceInformation = node.sourceInformation;
    _emitIsLateSentinel(node.checkedInput, sourceInformation, inverse: true);
    final condition = pop();

    if (node.hasName) {
      use(node.name);
      _pushCallStatic(_commonElements.throwLateFieldADI, [
        pop(),
      ], sourceInformation);
    } else {
      _pushCallStatic(
        _commonElements.throwUnnamedLateFieldADI,
        [],
        sourceInformation,
      );
    }

    // `condition && helper();` is smaller than `if (condition) helper();`.
    pushStatement(
      js.js
          .statement('# && #;', [condition, pop()])
          .withSourceInformation(sourceInformation),
    );
  }

  @override
  void visitTypeKnown(HTypeKnown node) {
    // [HTypeKnown] instructions are removed before generating code.
    assert(false);
  }

  @override
  void visitRef(HRef node) {
    visit(node.value);
  }

  @override
  void visitIsTest(HIsTest node) {
    _metrics.countHIsTest++;
    _registry.registerTypeUse(TypeUse.isCheck(node.dartType));

    use(node.typeInput);
    js.Expression first = pop();
    use(node.checkedInput);
    js.Expression second = pop();

    FieldEntity field = _commonElements.rtiIsField;
    js.Name name = _namer.instanceFieldPropertyName(field);

    push(
      js
          .js('#.#(#)', [first, name, second])
          .withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitIsTestSimple(HIsTestSimple node) {
    _metrics.countHIsTestSimple++;
    _emitIsTestSimple(node);
  }

  void _emitIsTestSimple(HIsTestSimple node, {bool negative = false}) {
    use(node.checkedInput);
    js.Expression value = pop();
    String relation = negative ? '!=' : '==';

    js.Expression handleNegative(js.Expression test) =>
        negative ? js.Prefix('!', test) : test;

    js.Expression typeof(String type) =>
        js.Binary(relation, js.Prefix('typeof', value), js.string(type));

    js.Expression isTest(FunctionEntity helper) {
      _registry.registerStaticUse(
        StaticUse.staticInvoke(helper, CallStructure.oneArg),
      );
      js.Expression test = js.Call(_emitter.staticFunctionAccess(helper), [
        value,
      ]);
      return handleNegative(test);
    }

    late js.Expression test;
    switch (node.specialization) {
      case SimpleIsTestSpecialization.isNull:
      case SimpleIsTestSpecialization.isNotNull:
        // These cases should be lowered using [HIdentity] during optimization.
        failedAt(node, 'Missing lowering');

      case SimpleIsTestSpecialization.isString:
        test = typeof("string");
        break;

      case SimpleIsTestSpecialization.isBool:
        test = isTest(_commonElements.specializedIsBool);
        break;

      case SimpleIsTestSpecialization.isNum:
        test = typeof("number");
        break;

      case SimpleIsTestSpecialization.isInt:
        test = isTest(_commonElements.specializedIsInt);
        break;

      case SimpleIsTestSpecialization.isArrayTop:
        test = handleNegative(js.js('Array.isArray(#)', [value]));
        break;

      case InstanceOfIsTestSpecialization(interfaceType: final type):
        _registry.registerTypeUse(TypeUse.constructorReference(type));
        test = handleNegative(
          js.js('# instanceof #', [
            value,
            _emitter.constructorAccess(type.element),
          ]),
        );
    }
    push(test.withSourceInformation(node.sourceInformation));
  }

  @override
  void visitAsCheck(HAsCheck node) {
    use(node.typeInput);
    js.Expression first = pop();
    use(node.checkedInput);
    js.Expression second = pop();

    _registry.registerTypeUse(TypeUse.isCheck(node.checkedTypeExpression));

    FieldEntity field = _commonElements.rtiAsField;
    js.Name name = _namer.instanceFieldPropertyName(field);

    push(
      js
          .js('#.#(#)', [first, name, second])
          .withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitAsCheckSimple(HAsCheckSimple node) {
    use(node.checkedInput);
    FunctionEntity method = node.method;
    _registry.registerStaticUse(
      StaticUse.staticInvoke(method, CallStructure.oneArg),
    );
    js.Expression methodAccess = _emitter.staticFunctionAccess(method);
    push(
      js
          .js(r'#(#)', [methodAccess, pop()])
          .withSourceInformation(node.sourceInformation),
    );
  }

  @override
  Never visitSubtypeCheck(HSubtypeCheck node) {
    throw UnimplementedError('SsaCodeGenerator.visitSubtypeCheck  $node');
  }

  @override
  void visitLoadType(HLoadType node) {
    // 'findType' will be called somewhere to initialize the type reference.
    _registry.registerStaticUse(
      StaticUse.staticInvoke(_commonElements.findType, CallStructure.oneArg),
    );
    TypeReference reference = TypeReference(node.typeExpression);
    reference.forLazyInitializer = currentGraph.isLazyInitializer;
    push(reference);
  }

  @override
  void visitInstanceEnvironment(HInstanceEnvironment node) {
    HInstruction input = node.inputs.single;
    use(input);
    js.Expression receiver = pop();

    void useRtiField() {
      push(js.js(r'#.#', [receiver, _namer.rtiFieldJsName]));
    }

    void useHelper(FunctionEntity helper) {
      _registry.registerStaticUse(
        StaticUse.staticInvoke(helper, CallStructure.oneArg),
      );
      js.Expression helperAccess = _emitter.staticFunctionAccess(helper);
      push(
        js
            .js(r'#(#)', [helperAccess, receiver])
            .withSourceInformation(node.sourceInformation),
      );
    }

    // Try to use the 'rti' field, or a specialization of 'instanceType'.
    AbstractValue receiverMask = node.codegenInputType;

    AbstractBool isArray = _abstractValueDomain.isInstanceOf(
      receiverMask,
      _commonElements.jsArrayClass,
    );

    if (isArray.isDefinitelyTrue) {
      useHelper(_commonElements.arrayInstanceType);
      return;
    }

    if (isArray.isDefinitelyFalse) {
      // See if the receiver type narrows the set of classes to ones that all
      // have a stored type field.
      // TODO(sra): Currently the only convenient query is [getExactClass]. We
      // should have a (cached) query to iterate over all the concrete classes
      // in [receiverMask].
      // TODO(sra): Store the context class on the HInstanceEnvironment. This
      // would allow the subtype classes to be iterated.
      ClassEntity? receiverClass = _abstractValueDomain.getExactClass(
        receiverMask,
      );
      if (receiverClass != null) {
        if (_closedWorld.rtiNeed.classNeedsTypeArguments(receiverClass)) {
          useRtiField();
          return;
        }
      }

      // If the type is not intercepted and is not a closure, use the 'simple'
      // helper.
      if (_abstractValueDomain.isInterceptor(receiverMask).isDefinitelyFalse) {
        if (_abstractValueDomain
            .isInstanceOf(receiverMask, _commonElements.closureClass)
            .isDefinitelyFalse) {
          useHelper(_commonElements.simpleInstanceType);
          return;
        }
      }
    }

    useHelper(_commonElements.instanceType);
  }

  @override
  void visitTypeEval(HTypeEval node) {
    // Call `env._eval("recipe")`.
    use(node.inputs[0]);
    js.Expression environment = pop();

    // Instead of generating `env._eval("$n")`, generate appropriate field
    // accesses where possible.
    TypeEnvironmentStructure envStructure = node.envStructure;
    TypeRecipe typeExpression = node.typeExpression;
    if (envStructure is FullTypeEnvironmentStructure &&
        typeExpression is TypeExpressionRecipe) {
      final type = typeExpression.type;
      if (type is TypeVariableType) {
        int? index = indexTypeVariable(
          _closedWorld,
          _rtiSubstitutions,
          envStructure,
          type,
        );
        if (index != null) {
          assert(index >= 1);
          List<TypeVariableType> bindings = envStructure.bindings;
          if (bindings.isNotEmpty) {
            // If the environment is a binding RTI, we should never index past
            // its length (i.e. into its base), since in that case, we could
            // eval against the base directly.
            assert(index <= bindings.length);
          } else {
            // If the environment is an interface RTI, use precomputed fields
            // for common accesses.
            if (index == 1) {
              push(
                _loadField(
                  environment,
                  _commonElements.rtiPrecomputed1Field,
                  node.sourceInformation,
                ),
              );
              return;
            }
          }

          js.Expression rest = _loadField(
            environment,
            _commonElements.rtiRestField,
            node.sourceInformation,
          );
          push(
            js.PropertyAccess.indexed(
              rest,
              index - 1,
            ).withSourceInformation(node.sourceInformation),
          );
          return;
        }
      }
    }

    RecipeEncoding encoding = _rtiRecipeEncoder.encodeRecipe(
      _emitter,
      node.envStructure,
      node.typeExpression,
    );
    js.Expression recipe = encoding.recipe;

    for (TypeVariableType typeVariable in encoding.typeVariables) {
      _registry.registerTypeUse(TypeUse.namedTypeVariable(typeVariable));
    }

    final method = _commonElements.rtiEvalMethod;
    Selector selector = Selector.fromElement(method);
    js.Name methodLiteral = _namer.invocationName(selector);
    push(
      js
          .js('#.#(#)', [environment, methodLiteral, recipe])
          .withSourceInformation(node.sourceInformation),
    );

    _registry.registerStaticUse(
      StaticUse.directInvoke(method, selector.callStructure, null),
    );
  }

  @override
  void visitTypeBind(HTypeBind node) {
    // Call `env1._bind(env2)`.
    assert(node.inputs.length == 2);
    use(node.inputs[0]);
    js.Expression environment = pop();
    use(node.inputs[1]);
    js.Expression extensions = pop();

    final method = _commonElements.rtiBindMethod;
    Selector selector = Selector.fromElement(method);
    js.Name methodLiteral = _namer.invocationName(selector);
    push(
      js
          .js('#.#(#)', [environment, methodLiteral, extensions])
          .withSourceInformation(node.sourceInformation),
    );

    _registry.registerStaticUse(
      StaticUse.directInvoke(method, selector.callStructure, null),
    );
  }

  void _emitIsLateSentinel(
    HInstruction input,
    SourceInformation? sourceInformation, {
    bool inverse = false,
  }) {
    use(input);
    js.Expression value = pop();
    js.Expression sentinel = _emitter.constantReference(
      LateSentinelConstantValue(),
    );
    push(
      js.Binary(
        mapRelationalOperator('===', inverse),
        value,
        sentinel,
      ).withSourceInformation(sourceInformation),
    );
  }

  @override
  void visitIsLateSentinel(HIsLateSentinel node) {
    _metrics.countHIsLateSentinel++;
    _emitIsLateSentinel(node.inputs.single, node.sourceInformation);
  }

  @override
  void visitArrayFlagsGet(HArrayFlagsGet node) {
    use(node.inputs.single);
    js.Expression array = pop();
    js.Expression flags = js.js(r'#.#', [
      array,
      _namer.fixedNames.arrayFlagsPropertyName,
    ]);
    if (isGenerateAtUseSite(node) && node.usedBy.single is HArrayFlagsCheck) {
      // The enclosing expression will be an immediate `& mask`.
      push(flags);
    } else {
      // The flags are reused, possibly hoisted, so force an `undefined` to be a
      // small integer once rather than at each check.
      push(js.js(r'# | 0', flags));
    }
  }

  @override
  void visitArrayFlagsSet(HArrayFlagsSet node) {
    use(node.inputs[0]);
    js.Expression array = pop();
    use(node.inputs[1]);
    js.Expression arrayFlags = pop();
    pushStatement(
      js.js
          .statement(r'#.# = #;', [
            array,
            _namer.fixedNames.arrayFlagsPropertyName,
            arrayFlags,
          ])
          .withSourceInformation(node.sourceInformation),
    );
  }

  @override
  void visitArrayFlagsCheck(HArrayFlagsCheck node) {
    use(node.array);
    js.Expression array = pop();

    js.Expression? test;
    if (!node.alwaysThrows()) {
      use(node.arrayFlags);
      js.Expression arrayFlags = pop();
      use(node.checkFlags);
      js.Expression checkFlags = pop();
      test = js.js('# & #', [arrayFlags, checkFlags]);
    }

    List<js.Expression> arguments = [array];

    if (node.hasOperation) {
      use(node.operation);
      arguments.add(pop());
    }

    if (node.hasVerb) {
      use(node.verb);
      arguments.add(pop());
    }

    _pushCallStatic(
      _commonElements.throwUnsupportedOperation,
      arguments,
      node.sourceInformation,
    );

    js.Statement check;
    if (test == null) {
      check = js.js.statement('#;', pop());
    } else {
      check = js.js.statement('# && #;', [test, pop()]);
    }

    pushStatement(check.withSourceInformation(node.sourceInformation));
  }
}
