// 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_prototype/lowering_predicates.dart'
    show
        isExtensionMemberTearOff,
        getExtensionMemberImplementation,
        isExtensionThisName,
        isTearOffLowering,
        getConstructorTearOffLoweringTarget;
// ignore: implementation_imports
import 'package:front_end/src/api_unstable/dart2js.dart' show Link;
import 'package:kernel/ast.dart' as ir;

import '../common.dart';
import '../common/codegen.dart' show CodegenRegistry;
import '../common/elements.dart' show JCommonElements;
import '../common/metrics.dart';
import '../common/names.dart';
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/codegen_inputs.dart' show CodegenInputs;
import '../js_backend/interceptor_data.dart';
import '../js_backend/namer.dart' show ModularNamer;
import '../js_backend/native_data.dart';
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/recorded_use.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();

  /// Set of constants that have already been recorded for uses. Shard-global to
  /// avoid redundant traversal of recurring deep constants.
  ///
  /// Similar to the VM's `_ConstantCollector` in
  /// `pkg/vm/lib/transformations/record_use/constant_collector.dart`.
  final Map<ConstantValue, _RecordedUseSequence> _recordedConstantUsesVisited =
      {};

  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,
        field,
        _recordedConstantUsesVisited,
      );
      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,
        method,
        _recordedConstantUsesVisited,
      );
      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 MemberEntity _member;

  /// Set of constants that have already been recorded for uses. Shard-global.
  ///
  /// Similar to the VM's `_ConstantCollector` in
  /// `pkg/vm/lib/transformations/record_use/constant_collector.dart`.
  final Map<ConstantValue, _RecordedUseSequence> _recordedConstantUsesVisited;

  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,
    this._member,
    this._recordedConstantUsesVisited,
  );

  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 = newLoop(
            init: jsInitialization,
            condition: jsCondition,
            update: jsUpdates,
            body: 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 {
            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 = newLoop(
            condition: jsCondition,
            body: 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 = newLoop(
            body: 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;
    if (body.statements.isNotEmpty) {
      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;
      RecordedUse? recordedMethodUses;
      if (element is ConstructorEntity) {
        CallStructure callStructure = CallStructure.unnamed(
          arguments.length,
          node.typeArguments.length,
        );
        staticUse = StaticUse.constructorInvoke(element, callStructure);
        if (_shouldRecordConstructor(element)) {
          recordedMethodUses = _recordConstructorUses(element, node.inputs);
        }
      } else if (element.isGetter) {
        staticUse = StaticUse.staticGet(element);
        if (_shouldRecordMethodUses(element)) {
          recordedMethodUses = _recordMethodUses(element, node.inputs);
        }
      } else if (element.isSetter) {
        staticUse = StaticUse.staticSet(element);
        if (_shouldRecordMethodUses(element)) {
          recordedMethodUses = _recordMethodUses(element, node.inputs);
        }
      } else {
        assert(element.isFunction);
        CallStructure callStructure = CallStructure.unnamed(
          arguments.length,
          node.typeArguments.length,
        );
        staticUse = StaticUse.staticInvoke(
          element,
          callStructure,
          node.typeArguments,
        );
        if (_shouldRecordMethodUses(element)) {
          recordedMethodUses = _recordMethodUses(element, node.inputs);
        }
        if (_shouldRecordConstructor(element)) {
          final elementNode = _closedWorld.elementMap
              .getMemberDefinition(element)
              .node;
          if (elementNode is ir.Procedure &&
              getConstructorTearOffLoweringTarget(elementNode) != null) {
            recordedMethodUses = _recordConstructorTearOff(element);
          } else {
            recordedMethodUses = _recordConstructorUses(element, node.inputs);
          }
        }
      }
      _registry.registerStaticUse(staticUse);
      push(_emitter.staticFunctionAccess(element));
      push(
        js.Call(pop(), arguments, sourceInformation: node.sourceInformation),
      );
      if (recordedMethodUses != null) {
        push(pop().withAnnotation(recordedMethodUses));
      }
    }
  }

  bool _shouldRecordMethodUses(FunctionEntity element) {
    if (_closedWorld.annotationsData.shouldRecordMethodUses(element)) {
      final currentElement = currentGraph.element;
      if (currentElement is FunctionEntity) {
        final currentNode = _closedWorld.elementMap
            .getMemberDefinition(currentElement)
            .node;
        if (currentNode is ir.Procedure) {
          final implementation = getExtensionMemberImplementation(currentNode);
          if (implementation != null &&
              _closedWorld.elementMap.containsMethod(implementation)) {
            final implementationEntity = _closedWorld.elementMap.getMember(
              implementation,
            );
            if (element == implementationEntity) return false;
          }
        }
        // If we are currently compiling a tear-off closure's call method,
        // we should also skip recording the call to the implementation method.
        final enclosingMember = _closedWorld.closureDataLookup
            .getEnclosingMember(currentElement);
        if (enclosingMember != currentElement &&
            enclosingMember is FunctionEntity) {
          final enclosingNode = _closedWorld.elementMap
              .getMemberDefinition(enclosingMember)
              .node;
          if (enclosingNode is ir.Procedure) {
            final implementation = getExtensionMemberImplementation(
              enclosingNode,
            );
            if (implementation != null &&
                _closedWorld.elementMap.containsMethod(implementation)) {
              final implementationEntity = _closedWorld.elementMap.getMember(
                implementation,
              );
              if (element == implementationEntity) return false;
            }
          }
        }
      }
      return true;
    }
    return _shouldRecordExtensionTearOff(element);
  }

  /// Returns `true` if [element] is an extension member tear-off that should
  /// be recorded.
  ///
  /// When an extension member is annotated with `@RecordUse`, we want to
  /// record whenever it is torn off.
  bool _shouldRecordExtensionTearOff(FunctionEntity element) {
    final node = _closedWorld.elementMap.getMemberDefinition(element).node;
    if (node is ir.Procedure && isExtensionMemberTearOff(node)) {
      final implementation = getExtensionMemberImplementation(node);
      if (implementation != null &&
          _closedWorld.elementMap.containsMethod(implementation)) {
        return _closedWorld.annotationsData.shouldRecordMethodUses(
          _closedWorld.elementMap.getMember(implementation) as FunctionEntity,
        );
      }
    }
    return false;
  }

  bool _shouldRecordConstructor(MemberEntity element) {
    final callerNode = _closedWorld.elementMap
        .getMemberDefinition(_member)
        .node;
    if (callerNode is ir.Procedure &&
        (isTearOffLowering(callerNode) || callerNode.isRedirectingFactory)) {
      // If we are currently compiling a constructor tear-off lowering, we
      // don't want to record the generative constructor calls inside it.
      return false;
    }

    final node = _closedWorld.elementMap.getMemberDefinition(element).node;
    MemberEntity resolved = element;
    bool isTearOff = false;
    if (node is ir.Procedure) {
      final target = getConstructorTearOffLoweringTarget(node);
      if (target != null) {
        resolved = _closedWorld.elementMap.getMember(target);
        isTearOff = true;
      }
    }

    final irResolved = _closedWorld.elementMap
        .getMemberDefinition(resolved)
        .node;

    if (irResolved is ir.Procedure && irResolved.isRedirectingFactory) {
      final ultimate = _getConstructorEffectiveTarget(irResolved);
      if (ultimate == null) return false;
      resolved = _closedWorld.elementMap.getMember(ultimate);
    }

    if (resolved is! ConstructorEntity) return false;
    final constructor = resolved;

    final classAnnotated = _closedWorld.annotationsData
        .shouldRecordConstInstances(constructor.enclosingClass);

    if (isTearOff) {
      return classAnnotated;
    }

    if (constructor.isGenerativeConstructor) {
      return classAnnotated;
    }

    // Regular factory call. Treat as static call. Don't record instances.
    return false;
  }

  ir.Member? _getConstructorEffectiveTarget(ir.Member node) {
    ir.Member? current = node;
    while (current is ir.Procedure && current.isRedirectingFactory) {
      current = current.function.redirectingFactoryTarget?.target;
    }
    return current;
  }

  RecordedUse _recordConstructorUses(
    MemberEntity element,
    List<HInstruction> arguments,
  ) {
    ir.Member node =
        _closedWorld.elementMap.getMemberDefinition(element).node as ir.Member;
    node = _getConstructorEffectiveTarget(node)!;
    final constructor =
        _closedWorld.elementMap.getMember(node) as ConstructorEntity;

    final positionalArguments = <ConstantValue?>[];
    final namedArguments = <String, ConstantValue?>{};
    var argumentIndex = 0;
    _closedWorld.elementEnvironment.forEachParameter(constructor, (
      DartType type,
      String? name,
      ConstantValue? defaultValue,
    ) {
      final value = argumentIndex < arguments.length
          ? _findConstant(arguments[argumentIndex])
          : defaultValue;
      if (argumentIndex < constructor.parameterStructure.positionalParameters) {
        positionalArguments.add(value);
      } else {
        namedArguments[name!] = value;
      }
      argumentIndex++;
    });

    return RecordedInstanceCreation(
      constructor: constructor,
      positionalArguments: positionalArguments,
      namedArguments: namedArguments,
    );
  }

  RecordedUse _recordConstructorTearOff(FunctionEntity element) {
    final node = _closedWorld.elementMap.getMemberDefinition(element).node;
    ir.Member target = node as ir.Member;
    if (node is ir.Procedure) {
      target = getConstructorTearOffLoweringTarget(node) ?? target;
    }
    target = _getConstructorEffectiveTarget(target)!;
    final constructor = _closedWorld.elementMap.getMember(target);

    return RecordedConstructorTearOff(
      constructor: constructor as ConstructorEntity,
    );
  }

  RecordedUse _recordMethodUses(
    FunctionEntity element,
    List<HInstruction> arguments,
  ) {
    final node = _closedWorld.elementMap.getMemberDefinition(element).node;
    var definitionHasReceiver = false;
    if (node is ir.Procedure) {
      if (node.isExtensionMember || node.isExtensionTypeMember) {
        definitionHasReceiver =
            (node.function.positionalParameters.isNotEmpty &&
                isExtensionThisName(
                  node.function.positionalParameters[0].cosmeticName,
                )) ||
            isExtensionMemberTearOff(node);
      }
    }

    final originalParameterStructure = element.parameterStructure;

    ConstantValue? constantReceiver;
    final positionalArguments = <ConstantValue?>[];
    final namedArguments = <String, ConstantValue?>{};
    var argumentIndex = 0;
    // Loop over arguments in namedOrdering or in nativeOrdering.
    _closedWorld.elementEnvironment.forEachParameter(element, (
      DartType type,
      String? name,
      ConstantValue? defaultValue,
    ) {
      if (argumentIndex == 0 && definitionHasReceiver) {
        constantReceiver = _findConstant(arguments[argumentIndex++]);
      } else {
        final value = argumentIndex < arguments.length
            ? _findConstant(arguments[argumentIndex])
            : defaultValue;
        if (argumentIndex < originalParameterStructure.positionalParameters) {
          positionalArguments.add(value);
        } else {
          namedArguments[name!] = value;
        }
        argumentIndex++;
      }
    });

    if (_shouldRecordExtensionTearOff(element)) {
      return RecordedTearOff(
        function: element,
        definitionHasReceiver: definitionHasReceiver,
        constantReceiver: constantReceiver,
      );
    }

    return RecordedCallWithArguments(
      function: element,
      definitionHasReceiver: definitionHasReceiver,
      constantReceiver: constantReceiver,
      positionalArguments: positionalArguments,
      namedArguments: namedArguments,
    );
  }

  /// Records a tear-off of a static method.
  ///
  /// Since this is a tear-off of a static method, it has no receiver.
  /// Extension member tear-offs are recorded as calls to their tear-off
  /// implementation in [_recordMethodUses] instead.
  RecordedUse _recordTearOff(FunctionEntity element) {
    return RecordedTearOff(
      function: element,
      definitionHasReceiver: false,
      constantReceiver: null,
    );
  }

  ConstantValue? _findConstant(HInstruction node) {
    while (node is HLateValue) {
      node = node.target;
    }
    return node is HConstant ? node.constant : null;
  }

  @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());
      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;

    Object? recordedMethodUses;
    if (_shouldRecordMethodUses(target)) {
      recordedMethodUses = _recordMethodUses(target, inputs);
    }

    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);
      if (recordedMethodUses != null) {
        expression = expression.withAnnotation(recordedMethodUses);
      }
      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]);
        }
        if (recordedMethodUses != null) {
          expression = expression.withAnnotation(recordedMethodUses);
        }
        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 visitEmbeddedGlobalGet(HEmbeddedGlobalGet node) {
    push(_emitter.generateEmbeddedGlobalAccess(node.name));
  }

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

  /// Returns a 'for' loop or 'while' loop depending on which parts of a 'for'
  /// loop are present.  In effect, choose the loop kind by applying these
  /// reductions:
  ///
  ///     for(init;true;update) -->  for(init;;update)
  ///     for(;cond;)  -->  while(cond)
  ///     while(true)  -->  for(;;)
  js.Loop newLoop({
    js.Expression? init,
    js.Expression? condition, // `null` means indefinite, i.e. `true`.
    js.Expression? update,
    required js.Statement body,
    SourceInformation? sourceInformation,
  }) {
    // `condition` with `true` replaced with `null`:
    final conditionOrNull = switch (condition) {
      js.LiteralBool(value: true) => null,
      js.LiteralNumber(value: '1') => null,
      // Minified `true` is `!0`:
      js.Prefix(op: '!', argument: js.LiteralNumber(value: '0')) => null,
      _ => condition,
    };

    if (init == null && update == null && conditionOrNull != null) {
      return js.While(
        conditionOrNull,
        body,
        sourceInformation: sourceInformation,
      );
    }
    return js.For(
      init,
      conditionOrNull,
      update,
      body,
      sourceInformation: 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);
    }
    for (final recordedUse in _recordConstantUses(constant)) {
      expression = expression.withAnnotation(recordedUse);
    }
    push(expression);
  }

  _RecordedUseSequence _recordConstantUses(ConstantValue constant) {
    if (_recordedConstantUsesVisited.containsKey(constant)) {
      return _recordedConstantUsesVisited[constant]!;
    }

    final resultList = <RecordedUse>[];
    switch (constant) {
      case FunctionConstantValue():
        final element = constant.element;
        if (_shouldRecordMethodUses(element)) {
          resultList.add(_recordTearOff(element));
        }
        if (_shouldRecordConstructor(element)) {
          resultList.add(_recordConstructorTearOff(element));
        }
      case ConstructedConstantValue():
        final element = constant.type.element;
        if (_closedWorld.annotationsData.shouldRecordConstInstances(element)) {
          resultList.add(RecordedConstInstance(constant: constant));
        }
      default:
        break;
    }

    var result = _RecordedUseSequence.fromList(resultList);

    // Cover nested constants.
    for (final dependency in constant.getDependencies()) {
      result += _recordConstantUses(dependency);
    }

    _recordedConstantUsesVisited[constant] = result;
    return result;
  }

  @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.
      js.Expression expression = _emitter
          .staticClosureAccess(element)
          .withSourceInformation(node.sourceInformation);
      if (_shouldRecordConstructor(element)) {
        expression = expression.withAnnotation(
          _recordConstructorTearOff(element),
        );
      }
      push(expression);
      _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));
  }
}

/// A sequence of [RecordedUse] that supports O(1) composition and
/// linear iteration safe for deep, unbalanced trees.
///
/// Specialized for recording constant uses in [SsaCodeGenerator].
abstract class _RecordedUseSequence extends Iterable<RecordedUse> {
  static const _RecordedUseSequence _empty = _RecordedUseLeaf([], 0);

  @override
  final int length;

  @override
  bool get isEmpty => length == 0;

  const _RecordedUseSequence._(this.length);

  factory _RecordedUseSequence.fromList(List<RecordedUse> list) {
    if (list.isEmpty) return _empty;
    return _RecordedUseLeaf(list, list.length);
  }

  _RecordedUseSequence operator +(_RecordedUseSequence other) {
    if (isEmpty) return other;
    if (other.isEmpty) return this;
    return _RecordedUseComposite(this, other);
  }

  @override
  Iterator<RecordedUse> get iterator => _RecordedUseStackIterator(this);
}

class _RecordedUseLeaf extends _RecordedUseSequence {
  final List<RecordedUse> items;
  const _RecordedUseLeaf(this.items, int length) : super._(length);
}

class _RecordedUseComposite extends _RecordedUseSequence {
  final _RecordedUseSequence left;
  final _RecordedUseSequence right;
  _RecordedUseComposite(this.left, this.right)
    : super._(left.length + right.length);
}

class _RecordedUseStackIterator implements Iterator<RecordedUse> {
  final List<_RecordedUseSequence> _stack = [];
  Iterator<RecordedUse>? _currentLeafIterator;
  RecordedUse? _currentValue;

  _RecordedUseStackIterator(_RecordedUseSequence root) {
    _pushLeft(root);
  }

  void _pushLeft(_RecordedUseSequence node) {
    _RecordedUseSequence current = node;
    while (current is _RecordedUseComposite) {
      _stack.add(current.right);
      current = current.left;
    }
    _currentLeafIterator = (current as _RecordedUseLeaf).items.iterator;
  }

  @override
  RecordedUse get current => _currentValue!;

  @override
  bool moveNext() {
    if (_currentLeafIterator != null && _currentLeafIterator!.moveNext()) {
      _currentValue = _currentLeafIterator!.current;
      return true;
    }

    if (_stack.isNotEmpty) {
      _pushLeft(_stack.removeLast());
      return moveNext();
    }

    _currentValue = null;
    return false;
  }
}
