Merge "Copy method access flags in LambdaClass"
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueType.java b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
index 69618b3..c414342 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -48,10 +48,6 @@
if (other == INT_OR_FLOAT_OR_NULL) {
return other.meet(this);
}
- if (isPreciseType() && other.isPreciseType()) {
- // Precise types must be identical, hitting the first check above.
- throw new CompilationError("Cannot compute meet of types: " + this + " and " + other);
- }
switch (this) {
case OBJECT:
{
diff --git a/src/test/examples/inlining/A.java b/src/test/examples/inlining/A.java
index dd857c8..a7aa4d2 100644
--- a/src/test/examples/inlining/A.java
+++ b/src/test/examples/inlining/A.java
@@ -6,15 +6,21 @@
class A {
int a;
+ int b;
A(int a) {
this.a = a;
+ this.b = a + 1;
}
int a() {
return a;
}
+ int b() {
+ return b;
+ }
+
int cannotInline(int v) {
// Cannot inline due to recursion.
if (v > 0) {
diff --git a/src/test/examples/inlining/Nullability.java b/src/test/examples/inlining/Nullability.java
index 74747d0..95422f0 100644
--- a/src/test/examples/inlining/Nullability.java
+++ b/src/test/examples/inlining/Nullability.java
@@ -43,8 +43,8 @@
}
int conditionalOperator(A a) {
- // a is not null when a.a() is invoked.
- return a != null ? a.a() : -1;
+ // a is not null when a.b() is invoked.
+ return a != null ? a.b() : -1;
}
int notInlinableOnThrow(Throwable t) throws Throwable {
@@ -97,8 +97,8 @@
// instructions with side effects.
if (a != null && result != 0) {
// Thus, the invocation below is the first instruction with side effect.
- // Also, a is not null here, hence a.a() is inlinable.
- result *= a.a();
+ // Also, a is not null here, hence a.b() is inlinable.
+ result *= a.b();
}
return result;
}
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 11ad12b..0f3cadc 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -11,14 +11,12 @@
import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -91,11 +89,6 @@
// This list is currently empty!
);
- private Set<String> failingOnX8 = ImmutableSet.of(
- // Contains use of register as both an int and a float.
- "regression/33336471"
- );
-
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@@ -168,10 +161,6 @@
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.setOutput(Paths.get(outputPath), OutputMode.DexIndexed);
ToolHelper.getAppBuilder(builder).addProgramFiles(originalDexFile);
-
- if (failingOnX8.contains(directoryName)) {
- thrown.expect(CompilationFailedException.class);
- }
R8.run(builder.build());
if (!ToolHelper.artSupported()) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
index 8e78784..7284384 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.code.Throw;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.dexinspector.ClassSubject;
@@ -55,17 +56,26 @@
private static final String DEFAULT_DEX_FILENAME = "classes.dex";
private static final String DEFAULT_MAP_FILENAME = "proguard.map";
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, minification={1}, allowaccessmodification={2}")
public static Collection<Object[]> data() {
- return Arrays.asList(new Object[][]{{"Inlining"}});
+ return Arrays.asList(new Object[][]{
+ {"Inlining", false, false},
+ {"Inlining", false, true},
+ {"Inlining", true, false},
+ {"Inlining", true, true}
+ });
}
private final String name;
private final String keepRulesFile;
+ private final boolean minification;
+ private final boolean allowAccessModification;
- public R8InliningTest(String name) {
+ public R8InliningTest(String name, boolean minification, boolean allowAccessModification) {
this.name = name.toLowerCase();
this.keepRulesFile = ToolHelper.EXAMPLES_DIR + this.name + "/keep-rules.txt";
+ this.minification = minification;
+ this.allowAccessModification = allowAccessModification;
}
private Path getInputFile() {
@@ -81,7 +91,7 @@
}
private String getGeneratedProguardMap() throws IOException {
- Path mapFile = Paths.get(temp.getRoot().getCanonicalPath(), DEFAULT_MAP_FILENAME);
+ Path mapFile = temp.getRoot().toPath().resolve(DEFAULT_MAP_FILENAME);
if (Files.exists(mapFile)) {
return mapFile.toAbsolutePath().toString();
}
@@ -94,19 +104,23 @@
@Before
public void generateR8Version() throws Exception {
Path out = temp.getRoot().toPath();
- R8Command command =
+ Path mapFile = out.resolve(DEFAULT_MAP_FILENAME);
+ R8Command.Builder commandBuilder =
R8Command.builder()
.addProgramFiles(getInputFile())
.setMinApiLevel(AndroidApiLevel.M.getLevel())
.setOutput(out, OutputMode.DexIndexed)
- .addProguardConfigurationFiles(Paths.get(keepRulesFile))
- .build();
- // TODO(62048823): Enable minification.
- ToolHelper.runR8(command, o -> {
- o.enableMinification = false;
+ .setProguardMapOutputPath(mapFile)
+ .addProguardConfigurationFiles(Paths.get(keepRulesFile));
+ if (allowAccessModification) {
+ commandBuilder.addProguardConfiguration(
+ ImmutableList.of("-allowaccessmodification"), Origin.unknown());
+ }
+ ToolHelper.runR8(commandBuilder.build(), o -> {
+ o.enableMinification = minification;
});
- String artOutput = ToolHelper.runArtNoVerificationErrors(out + "/classes.dex",
- "inlining.Inlining");
+ String artOutput =
+ ToolHelper.runArtNoVerificationErrors(out + "/classes.dex", "inlining.Inlining");
// Compare result with Java to make sure we have the same behavior.
ProcessResult javaResult = ToolHelper.runJava(getInputFile(), "inlining.Inlining");
@@ -179,17 +193,21 @@
new DexInspector(getGeneratedDexFile().toAbsolutePath(), getGeneratedProguardMap());
ClassSubject clazz = inspector.clazz("inlining.Nullability");
MethodSubject m = clazz.method("int", "inlinable", ImmutableList.of("inlining.A"));
- assertTrue(m.isPresent());
- DexCode code = m.getMethod().getCode().asDexCode();
- checkInstructions(
- code,
- ImmutableList.of(
- Iget.class,
- // TODO(b/70572176): below two could be replaced with Iget via inlining
- InvokeVirtual.class,
- MoveResult.class,
- AddInt2Addr.class,
- Return.class));
+ DexCode code;
+ if (allowAccessModification) {
+ assertFalse(m.isPresent());
+ } else {
+ assertTrue(m.isPresent());
+ code = m.getMethod().getCode().asDexCode();
+ checkInstructions(
+ code,
+ ImmutableList.of(
+ Iget.class,
+ InvokeVirtual.class,
+ MoveResult.class,
+ AddInt2Addr.class,
+ Return.class));
+ }
m = clazz.method("int", "notInlinable", ImmutableList.of("inlining.A"));
assertTrue(m.isPresent());
@@ -249,10 +267,7 @@
code,
ImmutableList.of(
IfEqz.class,
- // TODO(b/70794661): below two could be replaced with Iget via inlining if access
- // modification is allowed.
- InvokeVirtual.class,
- MoveResult.class,
+ Iget.class,
Goto.class,
Const4.class,
Return.class));
@@ -273,9 +288,7 @@
builder.add(Const4.class);
builder.add(IfEqz.class);
builder.add(IfEqz.class);
- // TODO(b/70794661): below two could be replaced with Iget via inlining
- builder.add(InvokeVirtual.class);
- builder.add(MoveResult.class);
+ builder.add(Iget.class);
builder.add(MulInt2Addr.class);
builder.add(Return.class);
builder.add(PackedSwitchPayload.class);
diff --git a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
index 876a758..39d7f0b 100644
--- a/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ApplyMappingTest.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -15,8 +16,6 @@
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.NewInstance;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.shaking.ProguardRuleParserException;
@@ -26,14 +25,21 @@
import com.android.tools.r8.utils.dexinspector.InstructionSubject;
import com.android.tools.r8.utils.dexinspector.InvokeInstructionSubject;
import com.android.tools.r8.utils.dexinspector.MethodSubject;
+import com.android.tools.r8.utils.dexinspector.NewInstanceInstructionSubject;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ExecutionException;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class ApplyMappingTest extends TestBase {
private static final String MAPPING = "test-mapping.txt";
@@ -52,9 +58,20 @@
private Path out;
+ private Backend backend;
+
+ @Parameters(name = "Backend: {0}")
+ public static Collection<Backend> data() {
+ return Arrays.asList(Backend.values());
+ }
+
+ public ApplyMappingTest(Backend backend) {
+ this.backend = backend;
+ }
+
@Before
public void setup() throws IOException {
- out = temp.newFolder("outdex").toPath();
+ out = temp.newFolder("out").toPath();
}
@Test
@@ -97,7 +114,7 @@
pgConfig -> pgConfig.setApplyMappingFile(proguardMap))
.build());
- DexInspector inspector = new DexInspector(instrApp);
+ DexInspector inspector = createDexInspector(instrApp);
MethodSubject main = inspector.clazz("applymapping044.Main").method(DexInspector.MAIN);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isInvoke);
@@ -152,7 +169,7 @@
.build());
// Make sure the given proguard map is indeed applied.
- DexInspector inspector = new DexInspector(outputApp);
+ DexInspector inspector = createDexInspector(outputApp);
MethodSubject main = inspector.clazz("applymapping044.Main").method(DexInspector.MAIN);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isInvoke);
@@ -194,6 +211,15 @@
assertEquals("p", original_f.invokedMethod().name.toString());
}
+ private static DexInspector createDexInspector(AndroidApp outputApp)
+ throws IOException, ExecutionException {
+ return new DexInspector(
+ outputApp,
+ o -> {
+ o.enableCfFrontend = true;
+ });
+ }
+
@Test
public void test_naming001_rule105() throws Exception {
// keep rules to reserve D and E, along with a proguard map.
@@ -210,7 +236,7 @@
.build());
// Make sure the given proguard map is indeed applied.
- DexInspector inspector = new DexInspector(outputApp);
+ DexInspector inspector = createDexInspector(outputApp);
MethodSubject main = inspector.clazz("naming001.D").method(DexInspector.MAIN);
Iterator<InvokeInstructionSubject> iterator =
main.iterateInstructions(InstructionSubject::isInvoke);
@@ -242,13 +268,20 @@
.build());
// Make sure the given proguard map is indeed applied.
- DexInspector inspector = new DexInspector(outputApp);
+ DexInspector inspector = createDexInspector(outputApp);
MethodSubject main = inspector.clazz("naming001.D").method(DexInspector.MAIN);
+ Iterator<InstructionSubject> iterator = main.iterateInstructions();
// naming001.E is renamed to a.a, so first instruction must be: new-instance La/a;
- Instruction[] instructions = main.getMethod().getCode().asDexCode().instructions;
- assertTrue(instructions[0] instanceof NewInstance);
- NewInstance newInstance = (NewInstance) instructions[0];
+ NewInstanceInstructionSubject newInstance = null;
+ while (iterator.hasNext()) {
+ InstructionSubject instruction = iterator.next();
+ if (instruction.isNewInstance()) {
+ newInstance = (NewInstanceInstructionSubject) instruction;
+ break;
+ }
+ }
+ assertNotNull(newInstance);
assertEquals( "La/a;", newInstance.getType().toSmaliString());
}
@@ -269,7 +302,7 @@
return R8Command.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar(), mainApp)
.addProgramFiles(instrApp)
- .setOutput(out, OutputMode.DexIndexed)
+ .setOutput(out, backend == Backend.DEX ? OutputMode.DexIndexed : OutputMode.ClassFile)
.addProguardConfigurationFiles(flag);
}
@@ -278,15 +311,17 @@
return R8Command.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
.addProgramFiles(jars)
- .setOutput(out, OutputMode.DexIndexed)
+ .setOutput(out, backend == Backend.DEX ? OutputMode.DexIndexed : OutputMode.ClassFile)
.addProguardConfigurationFiles(flag);
}
private static AndroidApp runR8(R8Command command)
throws ProguardRuleParserException, ExecutionException, IOException {
- return ToolHelper.runR8(command, options -> {
- // Disable inlining to make this test not depend on inlining decisions.
- options.enableInlining = false;
- });
+ return ToolHelper.runR8(
+ command,
+ options -> {
+ // Disable inlining to make this test not depend on inlining decisions.
+ options.enableInlining = false;
+ });
}
}
diff --git a/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java b/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
new file mode 100644
index 0000000..d424c39
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
@@ -0,0 +1,51 @@
+// Copyright (c) 2018, 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.regress.b111080693;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.VmTestRunner;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.regress.b111080693.a.Observable;
+import com.android.tools.r8.regress.b111080693.b.RecyclerView;
+import com.android.tools.r8.utils.AndroidApp;
+import com.google.common.collect.ImmutableList;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(VmTestRunner.class)
+public class B111080693 extends TestBase {
+ @Ignore("b/111080693")
+ @Test
+ public void test() throws Exception {
+ R8Command.Builder builder = R8Command.builder();
+ builder.addProgramFiles(
+ ToolHelper.getClassFilesForTestPackage(Observable.class.getPackage()));
+ builder.addProgramFiles(
+ ToolHelper.getClassFilesForTestPackage(RecyclerView.class.getPackage()));
+ builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestMain.class));
+ builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestMain.TestAdapter.class));
+ builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+ builder.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm().getLevel());
+ String config = keepMainProguardConfiguration(TestMain.class);
+ builder.addProguardConfiguration(
+ ImmutableList.of(config,
+ "-keepattributes Signature, InnerClasses, EnclosingMethod, *Annotation*"),
+ Origin.unknown());
+ AndroidApp app = ToolHelper.runR8(builder.build());
+ ProcessResult result = runOnArtRaw(app, TestMain.class);
+ assertEquals(0, result.exitCode);
+ assertThat(result.stderr, not(containsString("IllegalAccessError")));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b111080693/TestMain.java b/src/test/java/com/android/tools/r8/regress/b111080693/TestMain.java
new file mode 100644
index 0000000..8979250
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b111080693/TestMain.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2018, 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.regress.b111080693;
+
+import com.android.tools.r8.regress.b111080693.b.RecyclerView;
+import com.android.tools.r8.regress.b111080693.b.RecyclerView.Adapter;
+
+public class TestMain {
+ static final class TestAdapter extends Adapter {
+ TestAdapter() {
+ }
+ }
+
+ public static void main(String[] args) {
+ TestAdapter adapter = new TestAdapter();
+ RecyclerView view = new RecyclerView();
+ view.setAdapter(adapter);
+ adapter.notifyDataSetChanged();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b111080693/a/Observable.java b/src/test/java/com/android/tools/r8/regress/b111080693/a/Observable.java
new file mode 100644
index 0000000..c7a4858
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b111080693/a/Observable.java
@@ -0,0 +1,15 @@
+// Copyright (c) 2018, 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.regress.b111080693.a;
+
+import java.util.ArrayList;
+
+public abstract class Observable<T> {
+ /**
+ * The list of observers. An observer can be in the list at most
+ * once and will never be null.
+ */
+ protected final ArrayList<T> mObservers = new ArrayList<T>();
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b111080693/b/RecyclerView.java b/src/test/java/com/android/tools/r8/regress/b111080693/b/RecyclerView.java
new file mode 100644
index 0000000..06347fe
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b111080693/b/RecyclerView.java
@@ -0,0 +1,78 @@
+// Copyright (c) 2018, 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.regress.b111080693.b;
+
+import com.android.tools.r8.regress.b111080693.a.Observable;
+
+public class RecyclerView {
+
+ final State mState = new State();
+
+ public static class State {
+ boolean mStructureChanged = false;
+ }
+
+ public abstract static class AdapterDataObserver {
+ public void onChanged() {
+ // Do nothing
+ }
+ }
+
+ private class RecyclerViewDataObserver extends AdapterDataObserver {
+ RecyclerViewDataObserver() {
+ }
+
+ @Override
+ public void onChanged() {
+ // This is the single target of AdapterDataObserver#onChanged(), and could be inlined to
+ // AdapterDataObservable#notifyChanged() as long as this preserves null check of the receiver.
+ // To do so, access the enclosing class' member to use the receiver.
+ mState.mStructureChanged = true;
+ }
+ }
+
+ static class AdapterDataObservable extends Observable<AdapterDataObserver> {
+ public void registerObserver(AdapterDataObserver observer) {
+ mObservers.add(observer);
+ }
+ public void notifyChanged() {
+ for (int i = mObservers.size() - 1; i >= 0; i--) {
+ // The single target, RecyclerViewDataObserver#onChange is inlined, along with check-cast:
+ // AdapterDataObserver observer_i = mObservers.get(i);
+ // RecyclerViewDataObserver casted_obs = (RecyclerViewDataObserver) observer_i;
+ // // inlining RecyclerViewDataObserver#onChanged():
+ mObservers.get(i).onChanged();
+ }
+ }
+ }
+
+ public abstract static class Adapter {
+ private final AdapterDataObservable mObservable = new AdapterDataObservable();
+
+ public void registerAdapterDataObserver(AdapterDataObserver observer) {
+ mObservable.registerObserver(observer);
+ }
+
+ public final void notifyDataSetChanged() {
+ // Single callee, AdapterDataObservable#notifyChanged(), could be inlined, but should not.
+ // Accessing AdapterDataObservable.mObservers, which is a protected field in Observable,
+ // results in an illegal access error.
+ //
+ // Without the above inlining, the inlining constraint for the target here is SUBCLASS due to
+ // that protected field, and thus decline to inline because the holder, Adapter, is not a
+ // subtype of the target holder, AdapterDataObservable.
+ // However, after the above inlining, check-cast to RecyclerViewDataObserver overrides that
+ // condition to PACKAGE, which accidentally allows the target to be inlined here.
+ mObservable.notifyChanged();
+ }
+ }
+
+ private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
+
+ public void setAdapter(Adapter adapter) {
+ adapter.registerAdapterDataObserver(mObserver);
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java b/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
index b6ec9c3..c8713e3 100644
--- a/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
@@ -36,23 +37,28 @@
builder.addStaticField("stringField", "Ljava/lang/String;");
builder.addStaticField("testField", "LTest;");
+ boolean isDalvik = ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST);
+ String additionalConstZero = isDalvik ? "const v0, 0" : "";
+ String additionalConstZeroWide = isDalvik ? "const-wide v0, 0" : "";
+
builder.addStaticMethod("void", "test", ImmutableList.of(),
2,
- "const v0, 0", // single non-float typed zero (ie, int type)
+ "const v0, 0",
"sput-boolean v0, LTest;->booleanField:Z",
"sput-byte v0, LTest;->byteField:B",
- "sput-char v0, LTest;->charField:C",
"sput-short v0, LTest;->shortField:S",
"sput v0, LTest;->intField:I",
- "const v0, 0", // float typed zero
+ // Dalvik 4.x. does not require a new const 0 here.
"sput v0, LTest;->floatField:F",
- "const v0, 0", // reference typed null
+ additionalConstZero, // Required for Dalvik 4.x.
+ "sput-char v0, LTest;->charField:C",
+ "const v0, 0",
"sput-object v0, LTest;->objectField:Ljava/lang/Object;",
"sput-object v0, LTest;->stringField:Ljava/lang/String;",
"sput-object v0, LTest;->testField:LTest;",
- "const-wide v0, 0", // wide typed long
+ "const-wide v0, 0",
"sput-wide v0, LTest;->longField:J",
- "const-wide v0, 0", // wide typed double
+ additionalConstZeroWide, // Required for Dalvik 4.x.
"sput-wide v0, LTest;->doubleField:D",
"return-void");
@@ -97,23 +103,28 @@
builder.addInstanceField("stringField", "Ljava/lang/String;");
builder.addInstanceField("testField", "LTest;");
+ boolean isDalvik = ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST);
+ String additionalConstZero = isDalvik ? "const v0, 0" : "";
+ String additionalConstZeroWide = isDalvik ? "const-wide v0, 0" : "";
+
builder.addInstanceMethod("void", "test", ImmutableList.of(),
2,
"const v0, 0",
"iput-boolean v0, p0, LTest;->booleanField:Z",
"iput-byte v0, p0, LTest;->byteField:B",
- "iput-char v0, p0, LTest;->charField:C",
"iput-short v0, p0, LTest;->shortField:S",
"iput v0, p0, LTest;->intField:I",
- "const v0, 0",
+ // Dalvik 4.x. does not require a new const 0 here.
"iput v0, p0, LTest;->floatField:F",
+ additionalConstZero, // Required for Dalvik 4.x.
+ "iput-char v0, p0, LTest;->charField:C",
"const v0, 0",
"iput-object v0, p0, LTest;->objectField:Ljava/lang/Object;",
"iput-object v0, p0, LTest;->stringField:Ljava/lang/String;",
"iput-object v0, p0, LTest;->testField:LTest;",
"const-wide v0, 0",
"iput-wide v0, p0, LTest;->longField:J",
- "const-wide v0, 0",
+ additionalConstZeroWide, // Required for Dalvik 4.x.
"iput-wide v0, p0, LTest;->doubleField:D",
"return-void");
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java
index 7213a54..e2fa906 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/AbsentClassSubject.java
@@ -10,12 +10,6 @@
public class AbsentClassSubject extends ClassSubject {
- private DexInspector dexInspector;
-
- public AbsentClassSubject(DexInspector dexInspector) {
- this.dexInspector = dexInspector;
- }
-
@Override
public boolean isPresent() {
return false;
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionIterator.java b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionIterator.java
new file mode 100644
index 0000000..d000250
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionIterator.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2018, 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.graph.Code;
+import java.util.Iterator;
+
+class CfInstructionIterator implements InstructionIterator {
+
+ private final DexInspector dexInspector;
+ private final Iterator<CfInstruction> iterator;
+
+ CfInstructionIterator(DexInspector dexInspector, MethodSubject method) {
+ this.dexInspector = dexInspector;
+ assert method.isPresent();
+ Code code = method.getMethod().getCode();
+ assert code != null && code.isCfCode();
+ iterator = code.asCfCode().getInstructions().iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public InstructionSubject next() {
+ return dexInspector.createInstructionSubject(iterator.next());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java
new file mode 100644
index 0000000..ae900f3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2018, 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfConstString;
+import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfGoto;
+import com.android.tools.r8.cf.code.CfIf;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfNop;
+import com.android.tools.r8.cf.code.CfPosition;
+import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.cf.code.CfThrow;
+import org.objectweb.asm.Opcodes;
+
+public class CfInstructionSubject implements InstructionSubject {
+ protected final CfInstruction instruction;
+
+ public CfInstructionSubject(CfInstruction instruction) {
+ this.instruction = instruction;
+ }
+
+ @Override
+ public boolean isFieldAccess() {
+ return instruction instanceof CfFieldInstruction;
+ }
+
+ @Override
+ public boolean isInvokeVirtual() {
+ return instruction instanceof CfInvoke
+ && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKEVIRTUAL;
+ }
+
+ @Override
+ public boolean isInvokeInterface() {
+ return instruction instanceof CfInvoke
+ && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKEINTERFACE;
+ }
+
+ @Override
+ public boolean isInvokeStatic() {
+ return instruction instanceof CfInvoke
+ && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKESTATIC;
+ }
+
+ @Override
+ public boolean isNop() {
+ return instruction instanceof CfNop;
+ }
+
+ @Override
+ public boolean isConstString() {
+ return instruction instanceof CfConstString;
+ }
+
+ @Override
+ public boolean isConstString(String value) {
+ return isConstString() && ((CfConstString) instruction).getString().toString().equals(value);
+ }
+
+ @Override
+ public boolean isGoto() {
+ return instruction instanceof CfGoto;
+ }
+
+ @Override
+ public boolean isIfNez() {
+ return instruction instanceof CfIf && ((CfIf) instruction).getOpcode() == Opcodes.IFNE;
+ }
+
+ @Override
+ public boolean isIfEqz() {
+ return instruction instanceof CfIf && ((CfIf) instruction).getOpcode() == Opcodes.IFEQ;
+ }
+
+ @Override
+ public boolean isReturnVoid() {
+ return instruction instanceof CfReturnVoid;
+ }
+
+ @Override
+ public boolean isThrow() {
+ return instruction instanceof CfThrow;
+ }
+
+ @Override
+ public boolean isInvoke() {
+ return instruction instanceof CfInvoke || instruction instanceof CfInvokeDynamic;
+ }
+
+ @Override
+ public boolean isNewInstance() {
+ return instruction instanceof CfNew;
+ }
+
+ public boolean isInvokeSpecial() {
+ return instruction instanceof CfInvoke
+ && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKESPECIAL;
+ }
+
+ public boolean isInvokeDynamic() {
+ return instruction instanceof CfInvokeDynamic;
+ }
+
+ public boolean isLabel() {
+ return instruction instanceof CfLabel;
+ }
+
+ public boolean isPosition() {
+ return instruction instanceof CfPosition;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java
index 51e4ce2..c67a560 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInspector.java
@@ -6,8 +6,10 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.StringResource;
+import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
@@ -205,7 +207,7 @@
}
DexClass clazz = application.definitionFor(toDexTypeIgnorePrimitives(name));
if (clazz == null) {
- return new AbsentClassSubject(this);
+ return new AbsentClassSubject();
}
return new FoundClassSubject(this, clazz, naming);
}
@@ -250,15 +252,36 @@
return new InvokeDexInstructionSubject(this, instruction);
} else if (dexInst.isFieldAccess()) {
return new FieldAccessDexInstructionSubject(this, instruction);
+ } else if (dexInst.isNewInstance()) {
+ return new NewInstanceDexInstructionSubject(instruction);
} else {
return dexInst;
}
}
+ InstructionSubject createInstructionSubject(CfInstruction instruction) {
+ CfInstructionSubject cfInst = new CfInstructionSubject(instruction);
+ if (cfInst.isInvoke()) {
+ return new InvokeCfInstructionSubject(this, instruction);
+ } else if (cfInst.isFieldAccess()) {
+ return new FieldAccessCfInstructionSubject(this, instruction);
+ } else if (cfInst.isNewInstance()) {
+ return new NewInstanceCfInstructionSubject(instruction);
+ } else {
+ return cfInst;
+ }
+ }
+
InstructionIterator createInstructionIterator(MethodSubject method) {
Code code = method.getMethod().getCode();
- assert code != null && code.isDexCode();
- return new DexInstructionIterator(this, method);
+ assert code != null;
+ if (code.isDexCode()) {
+ return new DexInstructionIterator(this, method);
+ } else if (code.isCfCode()) {
+ return new CfInstructionIterator(this, method);
+ } else {
+ throw new Unimplemented("InstructionIterator is implemented for DexCode and CfCode only.");
+ }
}
// Build the generic signature using the current mapping if any.
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java
index eaff010..9ed4de1 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionIterator.java
@@ -10,7 +10,7 @@
class DexInstructionIterator implements InstructionIterator {
- private DexInspector dexInspector;
+ private final DexInspector dexInspector;
private final DexCode code;
private int index;
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java
index b2320d3..82d725a 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/DexInstructionSubject.java
@@ -34,6 +34,7 @@
import com.android.tools.r8.code.IputObject;
import com.android.tools.r8.code.IputShort;
import com.android.tools.r8.code.IputWide;
+import com.android.tools.r8.code.NewInstance;
import com.android.tools.r8.code.Nop;
import com.android.tools.r8.code.ReturnVoid;
import com.android.tools.r8.code.Sget;
@@ -53,7 +54,7 @@
import com.android.tools.r8.code.Throw;
public class DexInstructionSubject implements InstructionSubject {
- protected Instruction instruction;
+ protected final Instruction instruction;
public DexInstructionSubject(Instruction instruction) {
this.instruction = instruction;
@@ -75,16 +76,6 @@
}
@Override
- public boolean isInvokeDirect() {
- return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
- }
-
- @Override
- public boolean isInvokeSuper() {
- return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
- }
-
- @Override
public boolean isInvokeStatic() {
return instruction instanceof InvokeStatic || instruction instanceof InvokeStaticRange;
}
@@ -131,6 +122,28 @@
return instruction instanceof Throw;
}
+ @Override
+ public boolean isInvoke() {
+ return isInvokeVirtual()
+ || isInvokeInterface()
+ || isInvokeDirect()
+ || isInvokeSuper()
+ || isInvokeStatic();
+ }
+
+ @Override
+ public boolean isNewInstance() {
+ return instruction instanceof NewInstance;
+ }
+
+ public boolean isInvokeSuper() {
+ return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
+ }
+
+ public boolean isInvokeDirect() {
+ return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
+ }
+
public boolean isConst4() {
return instruction instanceof Const4;
}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessCfInstructionSubject.java
new file mode 100644
index 0000000..a2103e6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessCfInstructionSubject.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2018, 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstruction;
+
+public class FieldAccessCfInstructionSubject extends CfInstructionSubject
+ implements FieldAccessInstructionSubject {
+ private final DexInspector dexInspector;
+
+ public FieldAccessCfInstructionSubject(DexInspector dexInspector, CfInstruction instruction) {
+ super(instruction);
+ this.dexInspector = dexInspector;
+ assert isFieldAccess();
+ }
+
+ public TypeSubject holder() {
+ return new TypeSubject(dexInspector, ((CfFieldInstruction) instruction).getField().getHolder());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java
index c3ea3fc..ed54f90 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FieldAccessDexInstructionSubject.java
@@ -9,7 +9,7 @@
public class FieldAccessDexInstructionSubject extends DexInstructionSubject
implements FieldAccessInstructionSubject {
- private DexInspector dexInspector;
+ private final DexInspector dexInspector;
public FieldAccessDexInstructionSubject(DexInspector dexInspector, Instruction instruction) {
super(instruction);
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java
index 33ac77f..5f3c078 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FilteredInstructionIterator.java
@@ -10,14 +10,12 @@
class FilteredInstructionIterator<T extends InstructionSubject> implements Iterator<T> {
- private DexInspector dexInspector;
private final InstructionIterator iterator;
private final Predicate<InstructionSubject> predicate;
private InstructionSubject pendingNext = null;
FilteredInstructionIterator(
DexInspector dexInspector, MethodSubject method, Predicate<InstructionSubject> predicate) {
- this.dexInspector = dexInspector;
this.iterator = dexInspector.createInstructionIterator(method);
this.predicate = predicate;
hasNext();
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java
index 12dbaeb..2202f89 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundClassSubject.java
@@ -25,7 +25,7 @@
public class FoundClassSubject extends ClassSubject {
- private DexInspector dexInspector;
+ private final DexInspector dexInspector;
private final DexClass dexClass;
final ClassNamingForNameMapper naming;
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java
index 52aa0ce..5dfa4f1 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundFieldSubject.java
@@ -12,7 +12,7 @@
public class FoundFieldSubject extends FieldSubject {
- private DexInspector dexInspector;
+ private final DexInspector dexInspector;
private final FoundClassSubject clazz;
private final DexEncodedField dexField;
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java
index e245258..6eb3858 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/FoundMethodSubject.java
@@ -13,7 +13,7 @@
public class FoundMethodSubject extends MethodSubject {
- private DexInspector dexInspector;
+ private final DexInspector dexInspector;
private final FoundClassSubject clazz;
private final DexEncodedMethod dexMethod;
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java
index 00102e5..b6f1e52 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/InstructionSubject.java
@@ -11,10 +11,6 @@
boolean isInvokeInterface();
- boolean isInvokeDirect();
-
- boolean isInvokeSuper();
-
boolean isInvokeStatic();
boolean isNop();
@@ -33,11 +29,7 @@
boolean isThrow();
- default boolean isInvoke() {
- return isInvokeVirtual()
- || isInvokeInterface()
- || isInvokeDirect()
- || isInvokeSuper()
- || isInvokeStatic();
- }
+ boolean isInvoke();
+
+ boolean isNewInstance();
}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeCfInstructionSubject.java
new file mode 100644
index 0000000..4d245b2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeCfInstructionSubject.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2018, 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.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.graph.DexMethod;
+
+public class InvokeCfInstructionSubject extends CfInstructionSubject
+ implements InvokeInstructionSubject {
+ private final DexInspector dexInspector;
+
+ public InvokeCfInstructionSubject(DexInspector dexInspector, CfInstruction instruction) {
+ super(instruction);
+ assert isInvoke();
+ this.dexInspector = dexInspector;
+ }
+
+ public TypeSubject holder() {
+ return new TypeSubject(dexInspector, invokedMethod().getHolder());
+ }
+
+ public DexMethod invokedMethod() {
+ if (isInvokeDynamic()) {
+ throw new Unimplemented(
+ "invokeMethod is not implemented for the INVOKEDYNAMIC CF instruction.");
+ }
+ return ((CfInvoke) instruction).getMethod();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java
index a4f5636..51d0767 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/InvokeDexInstructionSubject.java
@@ -10,7 +10,7 @@
public class InvokeDexInstructionSubject extends DexInstructionSubject
implements InvokeInstructionSubject {
- private DexInspector dexInspector;
+ private final DexInspector dexInspector;
public InvokeDexInstructionSubject(DexInspector dexInspector, Instruction instruction) {
super(instruction);
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceCfInstructionSubject.java
new file mode 100644
index 0000000..71a1dfc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceCfInstructionSubject.java
@@ -0,0 +1,17 @@
+package com.android.tools.r8.utils.dexinspector;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.graph.DexType;
+
+public class NewInstanceCfInstructionSubject extends CfInstructionSubject
+ implements NewInstanceInstructionSubject {
+ public NewInstanceCfInstructionSubject(CfInstruction instruction) {
+ super(instruction);
+ }
+
+ @Override
+ public DexType getType() {
+ return ((CfNew) instruction).getType();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceDexInstructionSubject.java
new file mode 100644
index 0000000..675ded2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceDexInstructionSubject.java
@@ -0,0 +1,17 @@
+package com.android.tools.r8.utils.dexinspector;
+
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.code.NewInstance;
+import com.android.tools.r8.graph.DexType;
+
+public class NewInstanceDexInstructionSubject extends DexInstructionSubject
+ implements NewInstanceInstructionSubject {
+ public NewInstanceDexInstructionSubject(Instruction instruction) {
+ super(instruction);
+ }
+
+ @Override
+ public DexType getType() {
+ return ((NewInstance) instruction).getType();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceInstructionSubject.java
new file mode 100644
index 0000000..98a10ec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/NewInstanceInstructionSubject.java
@@ -0,0 +1,7 @@
+package com.android.tools.r8.utils.dexinspector;
+
+import com.android.tools.r8.graph.DexType;
+
+public interface NewInstanceInstructionSubject extends InstructionSubject {
+ DexType getType();
+}
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java
index 6a911eb..5b21c41 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/TypeSubject.java
@@ -8,7 +8,7 @@
public class TypeSubject extends Subject {
- private DexInspector dexInspector;
+ private final DexInspector dexInspector;
private final DexType dexType;
TypeSubject(DexInspector dexInspector, DexType dexType) {