// Copyright (c) 2022, 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:math' show min;

import 'package:kernel/ast.dart';
import 'package:vm/metadata/procedure_attributes.dart';
import 'package:vm/metadata/table_selector.dart';
import 'package:wasm_builder/wasm_builder.dart' as w;

import 'class_info.dart';
import 'dynamic_module_kernel_metadata.dart';
import 'dynamic_modules.dart';
import 'param_info.dart';
import 'reference_extensions.dart';
import 'serialization.dart';
import 'translator.dart';

/// Information for a dispatch table selector.
///
/// A selector encapsulates information to generate code that selects the right
/// member (method, getter, setter) implementation in an instance invocation,
/// from the dispatch table. Dispatch table is generated by [DispatchTable].
///
/// Target of a selector is a method, getter, or setter [Reference]. A target
/// does not have to correspond to a user-written Dart member, it can be for a
/// generated one. For example, for torn-off methods, we generate a [Reference]
/// for the tear-off getter a selector for it.
class SelectorInfo {
  final DispatchTable dispatchTable;

  Translator get translator => dispatchTable.translator;

  /// Unique ID of the selector.
  final int id;

  /// Number of use sites of the selector.
  final int callCount;

  /// Least upper bound of [ParameterInfo]s of all targets.
  late final ParameterInfo paramInfo;

  /// Is this an implicit or explicit setter?
  final bool isSetter;

  /// Whether we create multiple entry points for the selector.
  ///
  /// We create multiple entry points when any implementation of this selector
  /// performs type checks on the passed arguments.
  late bool useMultipleEntryPoints;

  late bool isDynamicSubmoduleOverridable;
  late bool isDynamicSubmoduleCallable;
  late bool isDynamicSubmoduleInheritable;

  /// Whether the computation of [paramInfo] should enforce usage of sentinels
  /// for optional parameters.
  late bool _useSentinelForOptionalParameters;

  /// Wasm function type for the selector.
  ///
  /// This should be read after all targets have been added to the selector.
  late final w.FunctionType signature = _computeSignature();

  /// The selector's member's name.
  final String name;

  SelectorTargets? _checked;
  SelectorTargets? _unchecked;
  SelectorTargets? _normal;

  /// The set of references we use to calculate the [paramInfo].
  final List<Reference> _references = [];

  SelectorTargets targets({required bool unchecked}) {
    if (useMultipleEntryPoints) {
      assert(_checked!.targetRanges.length == _unchecked!.targetRanges.length);
      return unchecked ? _unchecked! : _checked!;
    }
    assert(_checked == null && _unchecked == null);
    return _normal!;
  }

  SelectorInfo._(
    this.dispatchTable,
    this.id,
    this.name,
    this.callCount, {
    required this.isSetter,
  });

  void serialize(DataSerializer sink) {
    sink.writeInt(id);
    sink.writeString(name);
    sink.writeInt(callCount);
    sink.writeBoolList([
      isSetter,
      useMultipleEntryPoints,
      isDynamicSubmoduleOverridable,
      isDynamicSubmoduleCallable,
      isDynamicSubmoduleInheritable,
      _useSentinelForOptionalParameters,
    ]);
    sink.writeNullable(_checked, (targets) => targets.serialize(sink));
    sink.writeNullable(_unchecked, (targets) => targets.serialize(sink));
    sink.writeNullable(_normal, (targets) => targets.serialize(sink));
    sink.writeList(_references, sink.writeReference);
  }

  factory SelectorInfo.deserialize(
      DataDeserializer source, DispatchTable dispatchTable) {
    final id = source.readInt();
    final name = source.readString();
    final callCount = source.readInt();
    final [
      isSetter,
      useMultipleEntryPoints,
      isDynamicSubmoduleOverridable,
      isDynamicSubmoduleCallable,
      isDynamicSubmoduleInheritable,
      useSentinelForOptionalParameters,
    ] = source.readBoolList();
    final checked =
        source.readNullable(() => SelectorTargets.deserialize(source));
    final unchecked =
        source.readNullable(() => SelectorTargets.deserialize(source));
    final normal =
        source.readNullable(() => SelectorTargets.deserialize(source));
    final references = source.readList(source.readReference);

    final paramInfo = _parameterInfoFromReferences(
        references, useSentinelForOptionalParameters);
    return SelectorInfo._(dispatchTable, id, name, callCount,
        isSetter: isSetter)
      ..useMultipleEntryPoints = useMultipleEntryPoints
      ..isDynamicSubmoduleCallable = isDynamicSubmoduleCallable
      ..isDynamicSubmoduleOverridable = isDynamicSubmoduleOverridable
      ..isDynamicSubmoduleInheritable = isDynamicSubmoduleInheritable
      .._useSentinelForOptionalParameters = useSentinelForOptionalParameters
      .._checked = checked
      .._unchecked = unchecked
      .._normal = normal
      .._references.addAll(references)
      ..paramInfo = paramInfo;
  }

  String entryPointName(bool unchecked) {
    if (!useMultipleEntryPoints) return name;
    return '$name (${unchecked ? 'unchecked' : 'checked'})';
  }

  /// Compute the signature for the functions implementing members targeted by
  /// this selector.
  ///
  /// When the selector has multiple targets, the type of each parameter/return
  /// is the upper bound across all targets, such that all targets have the
  /// same signature, and the actual representation types of the parameters and
  /// returns are subtypes (resp. supertypes) of the types in the signature.
  w.FunctionType _computeSignature() {
    var nameIndex = paramInfo.nameIndex;
    final int returnCount = isSetter ? 0 : 1;
    List<Set<w.ValueType>> inputSets =
        List.generate(1 + paramInfo.paramCount, (_) => {});
    List<Set<w.ValueType>> outputSets = List.generate(returnCount, (_) => {});
    List<bool> ensureBoxed = List.filled(1 + paramInfo.paramCount, false);
    Iterable<({Reference target, Range range})> targetRanges =
        targets(unchecked: false).targetRanges;
    for (final (range: _, :target) in targetRanges) {
      Member member = target.asMember;
      DartType receiver =
          InterfaceType(member.enclosingClass!, Nullability.nonNullable);
      List<DartType> positional;
      Map<String, DartType> named;
      List<DartType> returns;
      if (member is Field) {
        if (target.isImplicitGetter) {
          positional = const [];
          named = const {};
          returns = [translator.typeOfReturnValue(member)];
        } else {
          positional = [member.setterType];
          named = const {};
          returns = const [];
        }
      } else {
        FunctionNode function = member.function!;
        if (target.isTearOffReference) {
          positional = const [];
          named = const {};
          returns = [function.computeFunctionType(Nullability.nonNullable)];
        } else {
          final typeForParam = translator.typeOfParameterVariable;
          positional = [
            for (int i = 0; i < function.positionalParameters.length; i++)
              typeForParam(function.positionalParameters[i],
                  i < function.requiredParameterCount)
          ];
          named = {
            for (VariableDeclaration param in function.namedParameters)
              param.name!: typeForParam(param, param.isRequired)
          };
          returns = target.isSetter
              ? const []
              : [translator.typeOfReturnValue(member)];
        }
      }
      assert(returns.length <= outputSets.length);
      inputSets[0].add(isDynamicSubmoduleOverridable
          ? translator.topTypeNonNullable
          : translator.translateType(receiver));
      for (int i = 0; i < positional.length; i++) {
        DartType type = positional[i];
        inputSets[1 + i].add(translator.translateType(type));
        ensureBoxed[1 + i] |=
            paramInfo.positional[i] == ParameterInfo.defaultValueSentinel;
      }
      for (String name in named.keys) {
        int i = nameIndex[name]!;
        DartType type = named[name]!;
        inputSets[1 + i].add(translator.translateType(type));
        ensureBoxed[1 + i] |=
            paramInfo.named[name] == ParameterInfo.defaultValueSentinel;
      }
      for (int i = 0; i < returnCount; i++) {
        if (i < returns.length) {
          DartType type = returns[i];
          outputSets[i].add(translator.translateReturnType(type));
        } else {
          outputSets[i].add(translator.topType);
        }
      }
    }

    List<w.ValueType> typeParameters = List.filled(paramInfo.typeParamCount,
        translator.classInfo[translator.typeClass]!.nonNullableType);
    List<w.ValueType> inputs = List.generate(
        inputSets.length,
        (i) => _upperBound(inputSets[i],
            ensureBoxed: ensureBoxed[i], isReceiver: i == 0));
    if (name == '==') {
      // == can't be called with null
      inputs[1] = inputs[1].withNullability(false);
    }
    List<w.ValueType> outputs = List.generate(outputSets.length,
        (i) => _upperBound(outputSets[i], ensureBoxed: false));
    return translator.typesBuilder.defineFunction(
        [inputs[0], ...typeParameters, ...inputs.sublist(1)], outputs);
  }

  w.ValueType _upperBound(Set<w.ValueType> types,
      {required bool ensureBoxed, bool isReceiver = false}) {
    if (types.isEmpty) {
      // This happens if the selector doesn't have any targets. Any call site of
      // such a selector is unreachable. Though such call sites still have to
      // evaluate receiver and arguments. Doing so requires the signature. So we
      // create a dummy signature with top types. Receivers specifically should
      // be non-nullable since we must be invoking a selector on some object.
      assert(!isReceiver || isDynamicSubmoduleOverridable);
      return isReceiver ? translator.topTypeNonNullable : translator.topType;
    }
    if (!ensureBoxed && types.length == 1 && types.single.isPrimitive) {
      // Unboxed primitive.
      return types.single;
    }
    final bool nullable = types.any((type) => type.nullable);
    int minDepth = 999999999;
    Set<w.DefType> heapTypes = types
        .where((type) => type is! w.RefType || type.heapType is w.DefType)
        .map((type) {
      w.DefType def = type is w.RefType
          ? type.heapType as w.DefType
          : translator.classInfo[translator.boxedClasses[type]!]!.struct;
      minDepth = min(minDepth, def.depth);
      return def;
    }).toSet();
    if (heapTypes.isEmpty) {
      // Only abstract heap types.
      Set<w.HeapType> heapTypes =
          types.map((type) => (type as w.RefType).heapType).toSet();
      return w.RefType(heapTypes.single, nullable: nullable);
    }
    int targetDepth = minDepth;
    while (heapTypes.length > 1) {
      heapTypes = heapTypes.map((s) {
        while (s.depth > targetDepth) {
          s = s.superType!;
        }
        return s;
      }).toSet();
      targetDepth -= 1;
    }
    return w.RefType.def(heapTypes.single, nullable: nullable);
  }

  late final Set<Reference> _targetSet = useMultipleEntryPoints
      ? {
          ..._checked!._targetSet,
          ..._unchecked!._targetSet,
        }
      : _normal!._targetSet;

  bool containsTarget(Reference target) => _targetSet.contains(target);
}

class SelectorTargets {
  /// Targets for all concrete classes implementing this selector.
  ///
  /// As a subclass hierarchy often inherits the same target, we associate the
  /// target with a range of class ids. The ranges are non-empty,
  /// non-overlapping and sorted in ascending order.
  final List<({Range range, Reference target})> targetRanges;

  /// Targets that a interface call will check & directly call before falling
  /// back to dispatch table calls.
  ///
  /// The targets in here are mainly the ones annotated with
  /// `@pragma('wasm:static-dispatch')`. The compiler will generate then code
  /// that first checks the receiver for those targets directly and issue direct
  /// calls before falling back to dispatch table calls.
  final List<({Range range, Reference target})> staticDispatchRanges;

  /// Offset of the selector in the dispatch table.
  ///
  /// For a class in [targetRanges], `class ID + offset` gives the offset of the
  /// class member for this selector.
  int? offset;

  SelectorTargets(this.targetRanges, this.staticDispatchRanges);

  late final Set<Reference> _targetSet =
      targetRanges.map((e) => e.target).toSet();

  void serialize(DataSerializer sink) {
    sink.writeInt(offset == null ? 0 : offset! + 1);
    sink.writeInt(targetRanges.length);
    for (final (:range, :target) in targetRanges) {
      range.serialize(sink);
      sink.writeReference(target);
    }
    sink.writeInt(staticDispatchRanges.length);
    for (final (:range, :target) in staticDispatchRanges) {
      range.serialize(sink);
      sink.writeReference(target);
    }
  }

  factory SelectorTargets.deserialize(DataDeserializer source) {
    final offset = source.readInt();
    final targetRangesLength = source.readInt();
    final targetRanges = <({Range range, Reference target})>[];
    for (int i = 0; i < targetRangesLength; i++) {
      final range = Range.deserialize(source);
      final target = source.readReference();
      targetRanges.add((range: range, target: target));
    }
    final staticDispatchRangesLength = source.readInt();
    final staticDispatchRanges = <({Range range, Reference target})>[];
    for (int i = 0; i < staticDispatchRangesLength; i++) {
      final range = Range.deserialize(source);
      final target = source.readReference();
      staticDispatchRanges.add((range: range, target: target));
    }
    return SelectorTargets(targetRanges, staticDispatchRanges)
      ..offset = offset == 0 ? null : offset - 1;
  }
}

/// Builds the dispatch table for member calls.
class DispatchTable {
  static const _functionType = w.RefType.func(nullable: true);
  final bool isDynamicSubmoduleTable;

  late final Map<TreeNode, ProcedureAttributesMetadata>
      procedureAttributeMetadata =
      translator.isDynamicSubmodule && !isDynamicSubmoduleTable
          ? (translator.component
                      .metadata[dynamicMainModuleProcedureAttributeMetadataTag]
                  as ProcedureAttributesMetadataRepository)
              .mapping
          : translator.procedureAttributeMetadata;

  late final Translator translator;

  late final List<TableSelectorInfo> _selectorMetadata =
      translator.isDynamicSubmodule && !isDynamicSubmoduleTable
          ? (translator.component.metadata[dynamicMainModuleSelectorMetadataTag]
                  as TableSelectorMetadataRepository)
              .mapping[translator.component]!
              .selectors
          : (translator.component
                      .metadata[TableSelectorMetadataRepository.repositoryTag]
                  as TableSelectorMetadataRepository)
              .mapping[translator.component]!
              .selectors;
  late final int minClassId = isDynamicSubmoduleTable
      ? translator.classIdNumbering.firstDynamicSubmoduleClassId
      : 0;
  late final int maxClassId = isDynamicSubmoduleTable
      ? translator.classIdNumbering.maxDynamicSubmoduleConcreteClassId!
      : translator.classIdNumbering.maxConcreteClassId;

  /// Maps selector IDs to selectors.
  final Map<int, SelectorInfo> _selectorInfo = {};

  /// Maps member names to getter selectors with the same member name.
  final Map<Name, Set<SelectorInfo>> _dynamicGetters = {};

  /// Maps member names to setter selectors with the same member name.
  final Map<Name, Set<SelectorInfo>> _dynamicSetters = {};

  /// Maps member names to method selectors with the same member name.
  final Map<Name, Set<SelectorInfo>> _dynamicMethods = {};

  /// Contents of [_definedWasmTable]. For a selector with ID S and a target
  /// class of the selector with ID C, `table[S + C]` gives the reference to the
  /// class member for the selector.
  late final List<Reference?> _table;

  late final w.TableBuilder _definedWasmTable;
  late final WasmTableImporter _importedWasmTables =
      WasmTableImporter(translator, 'dispatch');

  /// The Wasm table for the dispatch table.
  w.Table getWasmTable(w.ModuleBuilder module) =>
      _importedWasmTables.get(_definedWasmTable, module);

  DispatchTable({this.isDynamicSubmoduleTable = false});

  void serialize(DataSerializer sink) {
    sink.writeList(_selectorInfo.values, (s) => s.serialize(sink));
    sink.writeList(_table, (r) => sink.writeNullable(r, sink.writeReference));
    // Preserve call selectors for closure calls which are handled dynamically.
    final callSelectors = _dynamicGetters[Name('call')]!;
    sink.writeList(callSelectors, (s) => sink.writeInt(s.id));
  }

  factory DispatchTable.deserialize(DataDeserializer source) {
    final dispatchTable = DispatchTable();

    final selectors =
        source.readList(() => SelectorInfo.deserialize(source, dispatchTable));
    final table = source
        .readList(() => source.readNullable(() => source.readReference()));
    final callSelectorIds = source.readList(source.readInt);

    for (final selector in selectors) {
      dispatchTable._selectorInfo[selector.id] = selector;
    }
    dispatchTable._table = table;

    // Preserve call selectors for closure calls which are handled dynamically.
    final callSelectors = <SelectorInfo>{};
    for (final selectorId in callSelectorIds) {
      callSelectors.add(dispatchTable._selectorInfo[selectorId]!);
    }
    dispatchTable._dynamicGetters[Name('call')] = callSelectors;

    return dispatchTable;
  }

  SelectorInfo selectorForTarget(Reference target) {
    Member member = target.asMember;
    bool isGetter = target.isGetter || target.isTearOffReference;
    ProcedureAttributesMetadata metadata = procedureAttributeMetadata[member]!;
    int selectorId = isGetter
        ? metadata.getterSelectorId
        : metadata.methodOrSetterSelectorId;
    return _selectorInfo[selectorId]!;
  }

  SelectorInfo _createSelectorForTarget(Reference target) {
    Member member = target.asMember;
    bool isGetter = target.isGetter || target.isTearOffReference;
    bool isSetter = target.isSetter;
    ProcedureAttributesMetadata metadata = procedureAttributeMetadata[member]!;
    int selectorId = isGetter
        ? metadata.getterSelectorId
        : metadata.methodOrSetterSelectorId;

    // _WasmBase and its subclass methods cannot be called dynamically
    final cls = member.enclosingClass;
    final isWasmType = cls != null && translator.isWasmType(cls);

    final calledDynamically = !isWasmType &&
        (metadata.getterCalledDynamically ||
            metadata.methodOrSetterCalledDynamically ||
            member.name.text == "call");

    // The compiler will generate calls to `noSuchMethod` in the dynamic
    // invocation forwarders. So we ensure that the call count is positive.
    final isNoSuchMethod = member == translator.objectNoSuchMethod;
    final callCount =
        _selectorMetadata[selectorId].callCount + (isNoSuchMethod ? 1 : 0);
    final selector = _selectorInfo.putIfAbsent(
        selectorId,
        () => SelectorInfo._(this, selectorId, member.name.text, callCount,
            isSetter: isSetter));
    assert(selector.isSetter == isSetter);
    selector._references.add(target);

    if (calledDynamically) {
      if (isGetter) {
        (_dynamicGetters[member.name] ??= {}).add(selector);
      } else if (isSetter) {
        (_dynamicSetters[member.name] ??= {}).add(selector);
      } else {
        (_dynamicMethods[member.name] ??= {}).add(selector);
      }
    }

    return selector;
  }

  /// Get selectors for getters and tear-offs with the given name.
  Iterable<SelectorInfo> dynamicGetterSelectors(Name memberName) =>
      _dynamicGetters[memberName] ?? Iterable.empty();

  /// Get selectors for setters with the given name.
  Iterable<SelectorInfo> dynamicSetterSelectors(Name memberName) =>
      _dynamicSetters[memberName] ?? Iterable.empty();

  /// Get selectors for methods with the given name.
  Iterable<SelectorInfo> dynamicMethodSelectors(Name memberName) =>
      _dynamicMethods[memberName] ?? Iterable.empty();

  void _initializeWasmTable() {
    final module = isDynamicSubmoduleTable
        ? translator.dynamicSubmodule
        : translator.mainModule;
    _definedWasmTable = module.tables.define(_functionType, _table.length);
    if (!isDynamicSubmoduleTable) {
      for (final module in translator.modules) {
        // Ensure the dispatch table is imported into every module as the first
        // table.
        getWasmTable(module);
      }
    }
  }

  void build() {
    if (!isDynamicSubmoduleTable && translator.isDynamicSubmodule) {
      _initializeWasmTable();
      return;
    }
    // Collect class/selector combinations

    // Maps class to selector IDs of the class
    final selectorsInClass = <Class, Map<SelectorInfo, Reference>>{};
    final staticDispatchPragmas = <Reference>{};

    // Add classes to selector targets for their members
    for (ClassInfo info in translator.classesSupersFirst) {
      final Class cls = info.cls ?? translator.coreTypes.objectClass;
      final Map<SelectorInfo, Reference> selectors;

      // Add the class to its inherited members' selectors. Skip `_WasmBase`:
      // it's defined as a Dart class (in `dart._wasm` library) but it's special
      // and does not inherit from `Object`.
      final ClassInfo? superInfo = info.superInfo;
      if (superInfo == null || cls == translator.wasmTypesBaseClass) {
        selectors = {};
      } else {
        final Class superCls =
            superInfo.cls ?? translator.coreTypes.objectClass;
        selectors = Map.of(selectorsInClass[superCls]!);
      }

      final classIsDynamicSubmoduleExtendable =
          cls.isDynamicSubmoduleExtendable(translator.coreTypes);

      /// Add a method (or getter, setter) of the current class ([info]) to
      /// [reference]'s selector's targets.
      ///
      /// Because we visit a superclass before its subclasses, if the class
      /// inherits [reference], then the selector will already have a target
      /// for the class. Override that target if [reference] is a not abstract.
      /// If it's abstract, then the superclass's method will be called, so do
      /// not update the target.
      void addMember(Reference reference, bool staticDispatch) {
        SelectorInfo selector = _createSelectorForTarget(reference);
        if (reference.asMember.isAbstract) {
          // Reference is abstract, do not override inherited concrete member
          selectors[selector] ??= reference;
        } else {
          // Reference is concrete, override inherited member
          selectors[selector] = reference;

          if (staticDispatch) staticDispatchPragmas.add(reference);
        }
      }

      // Add the class to its non-static members' selectors. If `info.cls` is
      // `null`, that means [info] represents the `#Top` type, which is not a
      // Dart class but has the members of `Object`.
      for (Member member in cls.members) {
        // Skip static members
        if (!member.isInstanceMember) {
          continue;
        }
        final bool staticDispatch =
            translator.getPragma<bool>(member, 'wasm:static-dispatch', true) ??
                false;
        if (member is Field) {
          addMember(member.getterReference, staticDispatch);
          if (member.hasSetter) {
            final target = member.setterReference!;
            addMember(target, staticDispatch);
          }
        } else if (member is Procedure) {
          final target = member.reference;
          addMember(target, staticDispatch);
          final procedureMetadata = procedureAttributeMetadata[member]!;
          // `hasTearOffUses` can be true for operators as well, even though
          // it's not possible to tear-off an operator. (no syntax for it)
          if (member.kind == ProcedureKind.Method &&
              (procedureMetadata.hasTearOffUses ||
                  // If the member can be invoked from a dynamic submodule then
                  // we need to include the tearoff too.
                  member.isDynamicSubmoduleCallable(translator.coreTypes) ||
                  classIsDynamicSubmoduleExtendable)) {
            addMember(member.tearOffReference, staticDispatch);
          }
        }
      }
      selectorsInClass[cls] = selectors;
    }

    final selectorTargets = <SelectorInfo, Map<int, Reference>>{};
    for (int classId = minClassId; classId <= maxClassId; ++classId) {
      final cls = translator.classes[classId].cls;
      if (cls != null) {
        selectorsInClass[cls]!.forEach((selectorInfo, target) {
          if (!target.asMember.isAbstract) {
            selectorTargets.putIfAbsent(selectorInfo, () => {})[classId] =
                target;
          }
        });
      }
    }

    _selectorInfo.forEach((_, selector) {
      bool isDynamicSubmoduleCallable = false;
      bool isDynamicSubmoduleOverridable = false;
      bool isDynamicSubmoduleInheritable = false;
      for (final target in selector._references) {
        final member = target.asMember;
        isDynamicSubmoduleOverridable |=
            member.isDynamicSubmoduleOverridable(translator.coreTypes);
        isDynamicSubmoduleCallable |=
            member.isDynamicSubmoduleCallable(translator.coreTypes);
        isDynamicSubmoduleInheritable |=
            member.isDynamicSubmoduleInheritable(translator.coreTypes);
      }
      selector.isDynamicSubmoduleOverridable = isDynamicSubmoduleOverridable;
      selector.isDynamicSubmoduleCallable = isDynamicSubmoduleCallable;
      selector.isDynamicSubmoduleInheritable = isDynamicSubmoduleInheritable;

      if (!selectorTargets.containsKey(selector)) {
        // There are no concrete implementations for the given [selector].
        selector._normal = SelectorTargets([], []);
        selector.useMultipleEntryPoints = false;
        selector._useSentinelForOptionalParameters = true;
        selector.paramInfo = _parameterInfoFromReferences(
            selector._references, selector._useSentinelForOptionalParameters);
      } else {
        // Will be initialized in the `selectorTargets.forEach()` below.
      }
    });
    selectorTargets
        .forEach((SelectorInfo selector, Map<int, Reference> targets) {
      final List<({Range range, Reference target})> ranges = targets.entries
          .map((entry) =>
              (range: Range(entry.key, entry.key), target: entry.value))
          .toList()
        ..sort((a, b) => a.range.start.compareTo(b.range.start));
      assert(ranges.isNotEmpty);
      int writeIndex = 0;
      for (int readIndex = 1; readIndex < ranges.length; ++readIndex) {
        final current = ranges[writeIndex];
        final next = ranges[readIndex];
        assert(next.range.length == 1);
        if ((current.range.end + 1) == next.range.start &&
            identical(current.target, next.target)) {
          ranges[writeIndex] = (
            range: Range(current.range.start, next.range.end),
            target: current.target
          );
        } else {
          ranges[++writeIndex] = next;
        }
      }
      ranges.length = writeIndex + 1;

      bool useMultipleEntryPoints = false;
      final implementationReferences = <Reference>[];
      for (final targetRange in ranges) {
        final target = targetRange.target;
        final member = target.asMember;
        assert(!member.isAbstract);

        // Compute [useMultipleEntryPoints]
        if (!member.isExternal &&
            !target.isGetter &&
            !target.isTearOffReference &&
            translator.needToCheckTypesFor(member)) {
          useMultipleEntryPoints = true;
        }
        implementationReferences.add(target);
      }
      selector.useMultipleEntryPoints = useMultipleEntryPoints;

      if (!selector.isDynamicSubmoduleOverridable &&
          implementationReferences.isNotEmpty) {
        // We have global knowledge of all targets of the selector. We can use
        // this global knowledge to compute the [ParameterInfo].
        selector._references.clear();
        selector._references.addAll(implementationReferences);
        selector._useSentinelForOptionalParameters = false;
      } else {
        // Case 1) We may have no targets for the selector, but there may
        // still be calls to it (see e.g. https://dartbug.com/60733).
        //
        // Case 2) We may have 3rd party implementations of the selector
        // in a dynamic module with unknown default values for optionals.
        //
        // => We make caller pass sentinel if the optional parameter is not
        // provided.
        selector._useSentinelForOptionalParameters = true;
      }
      selector.paramInfo = _parameterInfoFromReferences(
          selector._references, selector._useSentinelForOptionalParameters);

      // Split up [ranges] into those that are statically dispatched to and
      // those are used via dispatch table.
      final staticDispatchRanges = selector.isDynamicSubmoduleOverridable
          ? const <({Range range, Reference target})>[]
          : (translator.options.polymorphicSpecialization || ranges.length == 1)
              ? ranges
              : ranges
                  .where(
                      (range) => staticDispatchPragmas.contains(range.target))
                  .toList();
      if (selector.useMultipleEntryPoints) {
        ({Range range, Reference target}) getChecked(
          ({Range range, Reference target}) targetRange,
          bool unchecked,
        ) =>
            (
              range: targetRange.range,
              target: translator.getFunctionEntry(targetRange.target,
                  uncheckedEntry: unchecked)
            );
        final checkedTargets = SelectorTargets(
          ranges.map((r) => getChecked(r, false)).toList(),
          staticDispatchRanges.map((r) => getChecked(r, false)).toList(),
        );
        final uncheckedTargets = SelectorTargets(
          ranges.map((r) => getChecked(r, true)).toList(),
          staticDispatchRanges.map((r) => getChecked(r, true)).toList(),
        );
        selector._checked = checkedTargets;
        selector._unchecked = uncheckedTargets;
      } else {
        final normalTargets = SelectorTargets(ranges, staticDispatchRanges);
        selector._normal = normalTargets;
      }
    });

    // Assign selector offsets

    final List<SelectorInfo> selectors =
        selectorTargets.keys.where(_isUsedViaDispatchTableCall).toList();

    // Sort the selectors based on number of targets and number of use sites.
    // This is a heuristic to keep the table small.
    //
    // Place selectors with more targets first as they are less likely to fit
    // into the gaps left by selectors placed earlier.
    //
    // Among the selectors with approximately same number of targets, place
    // more used ones first, as the smaller selector offset will have a smaller
    // instruction encoding.
    int selectorSortWeight(SelectorInfo selector) =>
        selectorTargets[selector]!.length * 10 + selector.callCount;

    selectors.sort((a, b) => selectorSortWeight(b) - selectorSortWeight(a));

    final rows = <Row<Reference>>[];
    for (final selector in selectors) {
      Row<Reference> buildRow(
          List<({Range range, Reference target})> targetRanges) {
        final rowValues = <({int index, Reference value})>[];
        for (final (:range, :target) in targetRanges) {
          for (int classId = range.start; classId <= range.end; ++classId) {
            final adjustedClassId = classId - minClassId;
            rowValues.add((index: adjustedClassId, value: target));
          }
        }
        rowValues.sort((a, b) => a.index.compareTo(b.index));
        return Row(rowValues);
      }

      if (selector.useMultipleEntryPoints) {
        rows.add(buildRow((selector._checked!.targetRanges)));
        rows.add(buildRow((selector._unchecked!.targetRanges)));
      } else {
        rows.add(buildRow((selector._normal!.targetRanges)));
      }
    }

    _table = buildRowDisplacementTable<Reference>(rows);

    int rowIndex = 0;
    for (final selector in selectors) {
      if (selector.useMultipleEntryPoints) {
        selector._checked!.offset = rows[rowIndex++].offset;
        selector._unchecked!.offset = rows[rowIndex++].offset;
      } else {
        selector._normal!.offset = rows[rowIndex++].offset;
      }
    }

    _initializeWasmTable();
  }

  void output() {
    final Map<w.BaseFunction, w.BaseFunction> wrappedDynamicSubmoduleImports =
        {};
    for (int i = 0; i < _table.length; i++) {
      Reference? target = _table[i];
      if (target != null) {
        w.BaseFunction? fun = translator.functions.getExistingFunction(target);
        // Any call to the dispatch table is guaranteed to hit a target.
        //
        // If a target is in a deferred module and that deferred module hasn't
        // been loaded yet, then the entry is `null`.
        //
        // Though we can only hit a target if that target's class has been
        // allocated. In order for the class to be allocated, the deferred
        // module must've been loaded to call the constructor.
        if (fun != null) {
          final targetModule = fun.enclosingModule;
          final targetModuleBuilder =
              translator.moduleToBuilder[fun.enclosingModule]!;
          if (targetModule == _definedWasmTable.enclosingModule) {
            if (isDynamicSubmoduleTable &&
                targetModuleBuilder == translator.dynamicSubmodule &&
                fun is w.ImportedFunction) {
              // Functions imported into submodules may need to be wrapped to
              // match the updated dispatch table signature.
              fun = wrappedDynamicSubmoduleImports[fun] ??=
                  _wrapDynamicSubmoduleFunction(target, fun);
            }
            _definedWasmTable.moduleBuilder.elements
                .activeFunctionSegmentBuilderFor(_definedWasmTable)
                .setFunctionAt(i, fun);
          } else {
            // This will generate the imported table if it doesn't already
            // exist.
            final importedTable =
                getWasmTable(targetModuleBuilder) as w.ImportedTable;
            targetModuleBuilder.elements
                .activeFunctionSegmentBuilderFor(importedTable)
                .setFunctionAt(i, fun);
          }
        }
      }
    }
  }

  w.BaseFunction _wrapDynamicSubmoduleFunction(
      Reference target, w.BaseFunction importedFunction) {
    final mainSelector =
        translator.dynamicMainModuleDispatchTable!.selectorForTarget(target);
    final mainSignature = translator.signatureForMainModule(target);
    final localSelector = translator.dispatchTable.selectorForTarget(target);
    final localSignature = localSelector.signature;

    // If the type is the same in both the main module and the submodule, use
    // the imported function itself.
    if (mainSignature.isStructurallyEqualTo(localSignature)) {
      return importedFunction;
    }

    // Otherwise we need to create a wrapper to handle the differing types.
    // The local signature should include all the parameters necessary to call
    // the target in main since the local signature must include the target
    // member itself and any other members in the main module's selector range.
    final wrapper = translator.dynamicSubmodule.functions
        .define(localSignature, '${target.asMember} wrapper');

    final ib = wrapper.body;

    assert(mainSignature.inputs.length <= localSignature.inputs.length);

    final mainModulePreParamCount =
        (mainSelector.paramInfo.takesContextOrReceiver ? 1 : 0) +
            mainSelector.paramInfo.typeParamCount;
    final mainModuleBeforeNamedCount =
        mainModulePreParamCount + mainSelector.paramInfo.positional.length;
    int mainIndex = 0;
    for (; mainIndex < mainModuleBeforeNamedCount; mainIndex++) {
      final local = ib.locals[mainIndex];
      ib.local_get(local);
      translator.convertType(ib, local.type, mainSignature.inputs[mainIndex]);
    }

    final localPreParamCount =
        (localSelector.paramInfo.takesContextOrReceiver ? 1 : 0) +
            localSelector.paramInfo.typeParamCount;

    for (final name in mainSelector.paramInfo.names) {
      final namedIndex = localSelector.paramInfo.nameIndex[name]!;
      final local = ib.locals[localPreParamCount + namedIndex];
      ib.local_get(local);
      translator.convertType(ib, local.type, mainSignature.inputs[mainIndex++]);
    }
    ib.call(importedFunction);
    translator.convertType(
        ib, mainSignature.outputs.single, localSignature.outputs.single);
    ib.end();

    return wrapper;
  }
}

bool _isUsedViaDispatchTableCall(SelectorInfo selector) {
  // If there's no callers in this module and no callers in dynamic modules then
  // there's no need for us to create a dispatch table entry.
  if (selector.callCount == 0 && !selector.isDynamicSubmoduleCallable) {
    return false;
  }

  final targets = selector.targets(unchecked: false);

  //  If there's 0 or 1 target than the call sites will either emit an
  //  unreachable or a direct call, so no call site goes via dispatch table, so
  //  we don't need a row in the table.
  if (targets.targetRanges.length <= 1) return false;

  // If all targets are dispatched to via static polymorphic dispatchers,
  // then no callsite will emit a dispatch table call, so we don't need a row in
  // the table.
  if (targets.staticDispatchRanges.length == targets.targetRanges.length) {
    return false;
  }

  return true;
}

ParameterInfo _parameterInfoFromReferences(
    List<Reference> references, bool useDefaultValueSentinel) {
  // We know all target implementations (closed world) if all of them use
  // the same default value for optionals, we can make the caller pass it.
  final first = references.first;
  final paramInfo = ParameterInfo.fromMember(
      first, useDefaultValueSentinel || first.asMember.isAbstract);
  for (final target in references.skip(1)) {
    paramInfo.merge(ParameterInfo.fromMember(
        target, useDefaultValueSentinel || target.asMember.isAbstract));
  }
  return paramInfo;
}

/// Build a row-displacement table based on fitting the [rows].
///
/// The returned list is the resulting row displacement table with `null`
/// entries representing unused space.
///
/// The offset of all [Row]s will be initialized.
List<V?> buildRowDisplacementTable<V extends Object>(List<Row<V>> rows,
    {int firstAvailable = 0}) {
  final table = <V?>[];
  for (final row in rows) {
    final values = row.values;
    int offset = firstAvailable - values.first.index;
    bool fits;
    do {
      fits = true;
      for (final value in values) {
        final int entry = offset + value.index;
        if (entry >= table.length) {
          // Fits
          break;
        }
        if (table[entry] != null) {
          fits = false;
          break;
        }
      }
      if (!fits) offset++;
    } while (!fits);
    row.offset = offset;
    for (final (:index, :value) in values) {
      final int tableIndex = offset + index;
      while (table.length <= tableIndex) {
        table.add(null);
      }
      assert(table[tableIndex] == null);
      table[tableIndex] = value;
    }
    while (firstAvailable < table.length && table[firstAvailable] != null) {
      firstAvailable++;
    }
  }
  return table;
}

class Row<V extends Object> {
  /// The values of the table row, represented sparsely as (index, value) tuples.
  final List<({int index, V value})> values;

  /// The given [values] must not be empty and should be sorted by index.
  Row(this.values) {
    assert(values.isNotEmpty);
    assert(() {
      int previous = values.first.index;
      for (final value in values.skip(1)) {
        if (value.index <= previous) return false;
        previous = value.index;
      }
      return true;
    }());
  }

  /// The selected offset of this row.
  late final int offset;

  int get width => values.last.index - values.first.index + 1;
  int get holes => width - values.length;
  int get density => (100 * values.length) ~/ width;
  int get sparsity => 100 - density;
}
