// Copyright (c) 2017, the R8 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.
package com.android.tools.r8.graph;

import static com.android.tools.r8.utils.DexDebugUtils.verifySetPositionFramesFollowedByDefaultEvent;

import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexDebugEvent.Default;
import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.DebugLocalsChange;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SourcePosition;
import com.android.tools.r8.utils.InternalOptions;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import java.util.ArrayList;
import java.util.List;

/**
 * Builder for constructing a list of debug events suitable for DexDebugInfo.
 *
 * This builder is intended to be very pedantic and ensure a well-formed structure of the resulting
 * event stream.
 */
public class DexDebugEventBuilder {

  public static final int NO_PC_INFO = -1;
  private static final int NO_LINE_INFO = -1;

  private final DexEncodedMethod method;
  private final DexItemFactory factory;
  private final InternalOptions options;

  // In order list of non-this argument locals.
  private ArrayList<DebugLocalInfo> arguments;

  // Mapping from register to the last known local in that register (See DBG_RESTART_LOCAL).
  private Int2ReferenceMap<DebugLocalInfo> lastKnownLocals;

  // Mapping from register to local for currently open/visible locals.
  private Int2ReferenceMap<DebugLocalInfo> pendingLocals = null;

  // The method's preamble position. This is used in release mode to preserve the preamble position
  // for methods without throwing instructions that have been moved (i.e., have a caller position).
  private Position preamblePosition;

  // Conservative pending-state of locals to avoid some equality checks on locals.
  // pendingLocalChanges == true ==> localsEqual(emittedLocals, pendingLocals).
  private boolean pendingLocalChanges = false;

  // State of pc, line, file and locals in the emitted event stream.
  private int emittedPc = NO_PC_INFO;
  private Position emittedPosition = Position.none();
  private Int2ReferenceMap<DebugLocalInfo> emittedLocals;
  private final boolean isComposing;

  // Emitted events.
  private final List<DexDebugEvent> events = new ArrayList<>();

  // Initial known line for the method.
  private int startLine = NO_LINE_INFO;

  public DexDebugEventBuilder(AppView<?> appView, IRCode code) {
    method = code.context().getDefinition();
    factory = appView.dexItemFactory();
    options = appView.options();
    isComposing =
        options.mappingComposeOptions().enableExperimentalMappingComposition
            && appView.appInfo().app().getProguardMap() != null;
  }

  /** Add events at pc for instruction. */
  public void add(int pc, int postPc, Instruction instruction) {
    boolean isBlockEntry = instruction.getBlock().entry() == instruction;
    boolean isBlockExit = instruction.getBlock().exit() == instruction;

    // Initialize locals state on block entry.
    if (isBlockEntry) {
      updateBlockEntry(instruction);
      if (preamblePosition == null) {
        preamblePosition = instruction.getPosition();
      }
    }
    assert pendingLocals != null;

    Position position = instruction.getPosition();
    boolean pcAdvancing = pc != postPc;

    // In debug mode check that all non-nop instructions have positions.
    assert instruction.verifyValidPositionInfo(options.debug);

    if (instruction.isArgument()) {
      startArgument(instruction.asArgument());
    } else if (instruction.isDebugLocalsChange()) {
      updateLocals(instruction.asDebugLocalsChange());
    } else if (pcAdvancing) {
      if (!position.isNone() && !position.equals(emittedPosition)) {
        if (options.debug || instruction.instructionTypeCanThrow() || isComposing) {
          emitDebugPosition(pc, position);
        }
      }
      if (emittedPc != pc) {
        emitLocalChanges(pc);
      }
    }

    if (isBlockExit) {
      // If this is the end of the block clear out the pending state.
      pendingLocals = null;
      pendingLocalChanges = false;
    }
  }

  /** Build the resulting DexDebugInfo object. */
  public DexDebugInfo build() {
    assert pendingLocals == null;
    assert !pendingLocalChanges;
    assert preamblePosition != null;
    if (startLine == NO_LINE_INFO) {
      if (!preamblePosition.hasCallerPosition()) {
        return null;
      }
      return new EventBasedDebugInfo(
          preamblePosition.getLine(),
          new DexString[method.getReference().getArity()],
          new DexDebugEvent[] {
            factory.createPositionFrame(preamblePosition), factory.zeroChangeDefaultEvent
          });
    }
    DexString[] params = new DexString[method.getReference().getArity()];
    if (arguments != null) {
      assert params.length == arguments.size();
      for (int i = 0; i < arguments.size(); i++) {
        DebugLocalInfo local = arguments.get(i);
        params[i] = (local == null || local.signature != null) ? null : local.name;
      }
    }
    assert verifySetPositionFramesFollowedByDefaultEvent(events);
    return new EventBasedDebugInfo(startLine, params, events.toArray(DexDebugEvent.EMPTY_ARRAY));
  }

  private void updateBlockEntry(Instruction instruction) {
    assert pendingLocals == null;
    assert !pendingLocalChanges;
    Int2ReferenceMap<DebugLocalInfo> locals = instruction.getBlock().getLocalsAtEntry();
    if (locals == null) {
      pendingLocals = Int2ReferenceMaps.emptyMap();
    } else {
      pendingLocals = new Int2ReferenceOpenHashMap<>(locals);
      pendingLocalChanges = true;
    }
    if (emittedLocals == null) {
      initialize(locals);
    }
  }

  private void initialize(Int2ReferenceMap<DebugLocalInfo> locals) {
    assert arguments == null;
    assert emittedLocals == null;
    assert lastKnownLocals == null;
    assert startLine == NO_LINE_INFO;
    if (locals == null) {
      emittedLocals = Int2ReferenceMaps.emptyMap();
      lastKnownLocals = Int2ReferenceMaps.emptyMap();
      return;
    }
    // Implicitly open all unparameterized arguments.
    emittedLocals = new Int2ReferenceOpenHashMap<>();
    for (Entry<DebugLocalInfo> entry : locals.int2ReferenceEntrySet()) {
      if (entry.getValue().signature == null) {
        emittedLocals.put(entry.getIntKey(), entry.getValue());
      } else if (options.testing.emitDebugLocalStartBeforeDefaultEvent) {
        events.add(new StartLocal(entry.getIntKey(), entry.getValue()));
        emittedLocals.put(entry.getIntKey(), entry.getValue());
      }
    }
    lastKnownLocals = new Int2ReferenceOpenHashMap<>(emittedLocals);
  }

  private void startArgument(Argument argument) {
    if (arguments == null) {
      arguments = new ArrayList<>(method.getReference().getArity());
    }
    if (!argument.outValue().isThis()) {
      arguments.add(argument.getLocalInfo());
    }
  }

  private void updateLocals(DebugLocalsChange change) {
    pendingLocalChanges = true;
    change.apply(pendingLocals);
  }

  private boolean localsChanged() {
    if (!pendingLocalChanges) {
      return false;
    }
    pendingLocalChanges = !DebugLocalInfo.localsInfoMapsEqual(emittedLocals, pendingLocals);
    return pendingLocalChanges;
  }

  private void emitDebugPosition(int pc, Position position) {
    assert !position.equals(emittedPosition);
    if (startLine == NO_LINE_INFO) {
      assert emittedPosition.isNone();
      if (position.isSyntheticPosition() && !position.hasCallerPosition()) {
        // Ignore synthetic positions prior to any actual position.
        // We do need to preserve synthetic position establishing the stack frame for inlined
        // methods.
        return;
      }
      startLine = position.getLine();
      Position outermostCaller = position.getOutermostCaller();
      emittedPosition =
          SourcePosition.builder()
              .setLine(position.getLine())
              .setMethod(outermostCaller.getMethod())
              .setIsD8R8Synthesized(outermostCaller.isD8R8Synthesized())
              .build();
    }
    assert emittedPc != pc;
    int previousPc = emittedPc == NO_PC_INFO ? 0 : emittedPc;
    emitAdvancementEvents(previousPc, emittedPosition, pc, position, events, factory, false);
    emittedPc = pc;
    emittedPosition = position;
    if (localsChanged()) {
      emitLocalChangeEvents(emittedLocals, pendingLocals, lastKnownLocals, events, factory);
      assert DebugLocalInfo.localsInfoMapsEqual(emittedLocals, pendingLocals);
    }
    pendingLocalChanges = false;
  }

  private void emitLocalChanges(int pc) {
    // If pc advanced since the locals changed and locals indeed have changed, emit the changes.
    if (localsChanged()) {
      assert emittedPc != pc;
      int pcDelta = emittedPc == NO_PC_INFO ? pc : pc - emittedPc;
      assert pcDelta > 0 || emittedPc == NO_PC_INFO;
      if (pcDelta > 0) {
        events.add(factory.createAdvancePC(pcDelta));
      }
      emittedPc = pc;
      emitLocalChangeEvents(emittedLocals, pendingLocals, lastKnownLocals, events, factory);
      pendingLocalChanges = false;
      assert DebugLocalInfo.localsInfoMapsEqual(emittedLocals, pendingLocals);
    }
  }

  @SuppressWarnings("ReferenceEquality")
  public static void emitAdvancementEvents(
      int previousPc,
      Position previousPosition,
      int nextPc,
      Position nextPosition,
      List<DexDebugEvent> events,
      DexItemFactory factory,
      boolean optimizingLineNumbers) {
    assert previousPc >= 0;
    int pcDelta = nextPc - previousPc;
    assert !previousPosition.isNone() || nextPosition.isNone();
    assert nextPosition.isNone() || nextPosition.getLine() >= 0;
    int lineDelta = nextPosition.isNone() ? 0 : nextPosition.getLine() - previousPosition.getLine();
    assert pcDelta >= 0;
    if (nextPosition.getFile() != previousPosition.getFile()) {
      events.add(factory.createSetFile(nextPosition.getFile()));
    }
    // The LineNumberOptimizer maps new positions based on the outer most caller with
    // callerPosition == null.
    assert nextPosition.hasCallerPosition()
        || previousPosition.hasCallerPosition()
        || nextPosition.getMethod() == previousPosition.getMethod()
        || optimizingLineNumbers;
    boolean isNewPosition =
        nextPosition.getCallerPosition() != previousPosition.getCallerPosition()
            || nextPosition.getMethod() != previousPosition.getMethod();
    boolean isOutline = nextPosition.isOutline();
    boolean isOutlineCallerWithInfo =
        nextPosition.isOutlineCaller()
            && nextPosition.getOutlineCallee() != null
            && !nextPosition.getOutlinePositions().isEmpty();
    boolean isNoLongerOutlineCaller =
        previousPosition.isOutlineCaller() && !nextPosition.isOutlineCaller();
    if (isNewPosition || isOutline || isOutlineCallerWithInfo || isNoLongerOutlineCaller) {
      events.add(factory.createPositionFrame(nextPosition));
    }
    addDefaultEventWithAdvancePcIfNecessary(lineDelta, pcDelta, events, factory);
  }

  public static void addDefaultEventWithAdvancePcIfNecessary(
      int lineDelta, int pcDelta, List<DexDebugEvent> events, DexItemFactory factory) {
    if (lineDelta < Constants.DBG_LINE_BASE
        || lineDelta - Constants.DBG_LINE_BASE >= Constants.DBG_LINE_RANGE) {
      events.add(factory.createAdvanceLine(lineDelta));
      // TODO(herhut): To be super clever, encode only the part that is above limit.
      lineDelta = 0;
    }
    int specialOpcode = Default.computeSpecialOpcode(lineDelta, pcDelta);
    if (specialOpcode > Constants.DBG_LAST_SPECIAL) {
      events.add(factory.createAdvancePC(pcDelta));
      // TODO(herhut): To be super clever, encode only the part that is above limit.
      specialOpcode = Default.computeSpecialOpcode(lineDelta, 0);
    }
    assert specialOpcode >= Constants.DBG_FIRST_SPECIAL;
    assert specialOpcode <= Constants.DBG_LAST_SPECIAL;
    events.add(factory.createDefault(specialOpcode));
  }

  @SuppressWarnings("ReferenceEquality")
  private static void emitLocalChangeEvents(
      Int2ReferenceMap<DebugLocalInfo> previousLocals,
      Int2ReferenceMap<DebugLocalInfo> nextLocals,
      Int2ReferenceMap<DebugLocalInfo> lastKnownLocals,
      List<DexDebugEvent> events,
      DexItemFactory factory) {
    Int2ReferenceSortedMap<DebugLocalInfo> ending =
        DebugLocalInfo.endingLocals(previousLocals, nextLocals);
    Int2ReferenceSortedMap<DebugLocalInfo> starting =
        DebugLocalInfo.startingLocals(previousLocals, nextLocals);
    assert !ending.isEmpty() || !starting.isEmpty();
    for (Entry<DebugLocalInfo> end : ending.int2ReferenceEntrySet()) {
      int register = end.getIntKey();
      if (!starting.containsKey(register)) {
        previousLocals.remove(register);
        events.add(factory.createEndLocal(register));
      }
    }
    for (Entry<DebugLocalInfo> start : starting.int2ReferenceEntrySet()) {
      int register = start.getIntKey();
      DebugLocalInfo local = start.getValue();
      previousLocals.put(register, local);
      if (lastKnownLocals.get(register) == local) {
        events.add(factory.createRestartLocal(register));
      } else {
        events.add(new StartLocal(register, local));
        lastKnownLocals.put(register, local);
      }
    }
  }
}
