[Retrace] Use instance state for line parser Bug: b/240771846 Change-Id: Ia1ac0b6aa0f4a540a4162a996edeff98a359e34f
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java index 7c30dcd..282e28a 100644 --- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java +++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapReaderWithFiltering.java
@@ -4,9 +4,6 @@ package com.android.tools.r8.retrace.internal; -import static com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.LineParserState.COMPLETE_CLASS_MAPPING; -import static com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.LineParserState.IS_COMMENT_SOURCE_FILE; -import static com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.LineParserState.NOT_CLASS_MAPPING_OR_SOURCE_FILE; import static java.lang.Integer.MAX_VALUE; import com.android.tools.r8.errors.Unreachable; @@ -23,20 +20,9 @@ public abstract class ProguardMapReaderWithFiltering implements LineReader { - // The LineParserState encodes a simple state that the line parser can be in, where the - // (successful) transitions allowed are: + private static final byte[] SOURCE_FILE_BYTES = "sourceFile".getBytes(); - // BEGINNING -> BEGINNING_NO_WHITESPACE -> SEEN_ORIGINAL_CLASS || IS_COMMENT_START - - // IS_COMMENT_START -> IS_COMMENT_SOURCE_FILE - - // SEEN_ORIGINAL_CLASS -> SEEN_ARROW -> SEEN_OBFUSCATED_CLASS -> COMPLETE_CLASS_MAPPING - // - // From all states there is a transition on invalid input to NOT_CLASS_MAPPING_OR_SOURCE_FILE. - // The terminal states are: - // { IS_COMMENT_SOURCE_FILE, COMPLETE_CLASS_MAPPING, NOT_CLASS_MAPPING_OR_SOURCE_FILE } - // - public enum LineParserState { + public enum LineParserNode { BEGINNING, BEGINNING_NO_WHITESPACE, SEEN_ORIGINAL_CLASS, @@ -52,62 +38,87 @@ || this == COMPLETE_CLASS_MAPPING || this == IS_COMMENT_SOURCE_FILE; } + } - private static int currentIndex; - private static int endIndex; - private static byte[] bytes; - private static final byte[] SOURCE_FILE_BYTES = "sourceFile".getBytes(); + // The LineParserState encodes a simple state that the line parser can be in, where the + // (successful) transitions allowed are: - public static LineParserState computeState(byte[] bytes, int startIndex, int endIndex) { - currentIndex = startIndex; - LineParserState.endIndex = endIndex; - LineParserState.bytes = bytes; - LineParserState currentState = BEGINNING; - while (!currentState.isTerminal()) { - currentState = currentState.computeNextState(); - } - return currentState; + // BEGINNING -> BEGINNING_NO_WHITESPACE -> SEEN_ORIGINAL_CLASS || IS_COMMENT_START + + // IS_COMMENT_START -> IS_COMMENT_SOURCE_FILE + + // SEEN_ORIGINAL_CLASS -> SEEN_ARROW -> SEEN_OBFUSCATED_CLASS -> COMPLETE_CLASS_MAPPING + // + // From all states there is a transition on invalid input to NOT_CLASS_MAPPING_OR_SOURCE_FILE. + // The terminal states are: + // { IS_COMMENT_SOURCE_FILE, COMPLETE_CLASS_MAPPING, NOT_CLASS_MAPPING_OR_SOURCE_FILE } + // + private static class LineParserState { + + private int currentIndex; + private final int endIndex; + private final byte[] bytes; + private LineParserNode node; + + private LineParserState(byte[] bytes, int currentIndex, int endIndex) { + this.currentIndex = currentIndex; + this.endIndex = endIndex; + this.bytes = bytes; + node = LineParserNode.BEGINNING; } - private LineParserState computeNextState() { - assert this != NOT_CLASS_MAPPING_OR_SOURCE_FILE; - switch (this) { + private LineParserNode run() { + while (!node.isTerminal()) { + node = computeNextState(); + } + return node; + } + + private LineParserNode computeNextState() { + assert node != LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; + switch (node) { case BEGINNING: return readUntilNoWhiteSpace() - ? BEGINNING_NO_WHITESPACE - : NOT_CLASS_MAPPING_OR_SOURCE_FILE; + ? LineParserNode.BEGINNING_NO_WHITESPACE + : LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; case BEGINNING_NO_WHITESPACE: if (isCommentChar()) { - return IS_COMMENT_START; + return LineParserNode.IS_COMMENT_START; } else { int readLength = readCharactersNoWhiteSpaceUntil(' '); - return readLength > 0 ? SEEN_ORIGINAL_CLASS : NOT_CLASS_MAPPING_OR_SOURCE_FILE; + return readLength > 0 + ? LineParserNode.SEEN_ORIGINAL_CLASS + : LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; } case SEEN_ORIGINAL_CLASS: - return readArrow() ? SEEN_ARROW : NOT_CLASS_MAPPING_OR_SOURCE_FILE; + return readArrow() + ? LineParserNode.SEEN_ARROW + : LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; case SEEN_ARROW: int colonIndex = readCharactersNoWhiteSpaceUntil(':'); - return colonIndex > 0 ? SEEN_OBFUSCATED_CLASS : NOT_CLASS_MAPPING_OR_SOURCE_FILE; + return colonIndex > 0 + ? LineParserNode.SEEN_OBFUSCATED_CLASS + : LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; case SEEN_OBFUSCATED_CLASS: boolean read = readColon(); if (!read) { - return NOT_CLASS_MAPPING_OR_SOURCE_FILE; + return LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; } boolean noWhiteSpace = readUntilNoWhiteSpace(); return (!noWhiteSpace || isCommentChar()) - ? COMPLETE_CLASS_MAPPING - : NOT_CLASS_MAPPING_OR_SOURCE_FILE; + ? LineParserNode.COMPLETE_CLASS_MAPPING + : LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; case IS_COMMENT_START: if (readCharactersUntil('{') && readCharactersUntil(':') && readSingleOrDoubleQuote() && readSourceFile()) { - return IS_COMMENT_SOURCE_FILE; + return LineParserNode.IS_COMMENT_SOURCE_FILE; } else { - return NOT_CLASS_MAPPING_OR_SOURCE_FILE; + return LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; } default: - assert isTerminal(); + assert node.isTerminal(); throw new Unreachable("Should not compute next state on terminal state"); } } @@ -208,7 +219,7 @@ private boolean isInsideClassOfInterest = false; private boolean seenFirstClass = false; - private LineParserState lineParserState = NOT_CLASS_MAPPING_OR_SOURCE_FILE; + private LineParserNode lineParserResult = LineParserNode.NOT_CLASS_MAPPING_OR_SOURCE_FILE; @Override public String readLine() throws IOException { @@ -220,8 +231,8 @@ if (filter == null) { return new String(bytes, startIndex, endIndex - startIndex, StandardCharsets.UTF_8); } - lineParserState = LineParserState.computeState(bytes, startIndex, endIndex); - if (lineParserState == COMPLETE_CLASS_MAPPING) { + lineParserResult = new LineParserState(bytes, startIndex, endIndex).run(); + if (lineParserResult == LineParserNode.COMPLETE_CLASS_MAPPING) { seenFirstClass = true; String classMapping = getBufferAsString(bytes); String obfuscatedClassName = getObfuscatedClassName(classMapping); @@ -229,7 +240,8 @@ if (isInsideClassOfInterest || readPreambleAndSourceFiles) { return classMapping; } - } else if (lineParserState == IS_COMMENT_SOURCE_FILE && readPreambleAndSourceFiles) { + } else if (lineParserResult == LineParserNode.IS_COMMENT_SOURCE_FILE + && readPreambleAndSourceFiles) { return getBufferAsString(bytes); } else if (isInsideClassOfInterest || (!seenFirstClass && readPreambleAndSourceFiles)) { return getBufferAsString(bytes); @@ -238,7 +250,7 @@ } public boolean isClassMapping() { - return lineParserState == COMPLETE_CLASS_MAPPING; + return lineParserResult == LineParserNode.COMPLETE_CLASS_MAPPING; } private String getBufferAsString(byte[] bytes) {