Avoid calling toString on all dex strings to collect markers.
This is used during dex merging to make sure that we preserve all
markers. This change adds a fast case that check that the first
two raw chars are consistent with a marker before calling toString.
R=sgjesse@google.com, tamaskenez@google.com
Change-Id: I2e5913df18655c019f0a28c6dbcd0c02517a2efc
diff --git a/src/main/java/com/android/tools/r8/dex/Marker.java b/src/main/java/com/android/tools/r8/dex/Marker.java
index c9af221..31628ad 100644
--- a/src/main/java/com/android/tools/r8/dex/Marker.java
+++ b/src/main/java/com/android/tools/r8/dex/Marker.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dex;
+import com.android.tools.r8.graph.DexString;
import java.util.Map;
import java.util.TreeMap;
import org.json.simple.JSONObject;
@@ -20,9 +21,10 @@
public enum Tool {D8, R8}
- private static final String kPrefix = "~~";
- private static final String kD8prefix = kPrefix + Tool.D8 + "{";
- private static final String kR8prefix = kPrefix + Tool.R8 + "{";
+ private static final char PREFIX_CHAR = '~';
+ private static final String PREFIX = "~~";
+ private static final String D8_PREFIX = PREFIX + Tool.D8 + "{";
+ private static final String R8_PREFIX = PREFIX + Tool.R8 + "{";
private final TreeMap<String, Object> content;
private final Tool tool;
@@ -92,7 +94,7 @@
public String toString() {
// The JSONObject does not support a predictable sorted serialization of the object.
// Therefore, a TreeMap is used and iteration is over the keySet.
- StringBuffer sb = new StringBuffer(kPrefix + tool);
+ StringBuffer sb = new StringBuffer(PREFIX + tool);
boolean first = true;
sb.append('{');
for (String key : content.keySet()) {
@@ -123,12 +125,17 @@
// Try to parse str as a marker.
// Returns null if parsing fails.
- public static Marker parse(String str) {
- if (str.startsWith(kD8prefix)) {
- return internalParse(Tool.D8, str.substring(kD8prefix.length() - 1));
- }
- if (str.startsWith(kR8prefix)) {
- return internalParse(Tool.R8, str.substring(kR8prefix.length() - 1));
+ public static Marker parse(DexString dexString) {
+ if (dexString.size > 2
+ && dexString.content[0] == PREFIX_CHAR
+ && dexString.content[1] == PREFIX_CHAR) {
+ String str = dexString.toString();
+ if (str.startsWith(D8_PREFIX)) {
+ return internalParse(Tool.D8, str.substring(D8_PREFIX.length() - 1));
+ }
+ if (str.startsWith(R8_PREFIX)) {
+ return internalParse(Tool.R8, str.substring(R8_PREFIX.length() - 1));
+ }
}
return null;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index d45402d..9e77dd5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -510,7 +510,7 @@
public synchronized Marker extractMarker() {
// This is slow but it is not needed for any production code yet.
for (DexString dexString : strings.keySet()) {
- Marker result = Marker.parse(dexString.toString());
+ Marker result = Marker.parse(dexString);
if (result != null) {
return result;
}
@@ -524,7 +524,7 @@
// This is slow but it is not needed for any production code yet.
List<Marker> markers = new ArrayList<>();
for (DexString dexString : strings.keySet()) {
- Marker marker = Marker.parse(dexString.toString());
+ Marker marker = Marker.parse(dexString);
if (marker != null) {
markers.add(marker);
}
diff --git a/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java b/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java
index 9ce3d9c..7daaddd 100644
--- a/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -61,12 +62,14 @@
Marker marker = new Marker(Tool.D8)
.setVersion("1.0.0")
.setMinApi(minApi);
- Marker selfie = Marker.parse(marker.toString());
+ InternalOptions options = new InternalOptions();
+ DexString markerDexString = options.itemFactory.createString(marker.toString());
+ Marker selfie = Marker.parse(markerDexString);
assert marker.equals(selfie);
- AndroidApp app = ToolHelper.runD8(command, options -> options.setMarker(marker));
+ AndroidApp app = ToolHelper.runD8(command, opts -> opts.setMarker(marker));
DexApplication dexApp =
new ApplicationReader(
- app, new InternalOptions(), new Timing("D8FrameworkDexPassthroughMarkerTest"))
+ app, options, new Timing("D8FrameworkDexPassthroughMarkerTest"))
.read();
Marker readMarker = dexApp.dexItemFactory.extractMarker();
assertEquals(marker, readMarker);