| // Copyright (c) 2016, 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; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.ByteDataView; |
| import com.android.tools.r8.D8; |
| import com.android.tools.r8.D8Command; |
| import com.android.tools.r8.D8Command.Builder; |
| import com.android.tools.r8.DexIndexedConsumer; |
| import com.android.tools.r8.DiagnosticsHandler; |
| import com.android.tools.r8.origin.EmbeddedOrigin; |
| import com.android.tools.r8.origin.Origin; |
| import com.android.tools.r8.smali.SmaliTestBase; |
| import com.android.tools.r8.utils.AndroidApp; |
| import com.android.tools.r8.utils.AndroidAppConsumers; |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import java.util.Base64; |
| import java.util.Set; |
| import org.junit.Test; |
| |
| public class Regress37740372 extends SmaliTestBase { |
| |
| /* |
| Binary class file data for a java.lang.Object stub implementation. Runnong javap -c on the |
| bytecode produces the following output: |
| |
| Compiled from "Object.java" |
| public class java.lang.Object { |
| public java.lang.Object(); |
| Code: |
| 0: new #1 // class java/lang/RuntimeException |
| 3: dup |
| 4: ldc #2 // String Stub! |
| 6: invokespecial #3 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V |
| 9: athrow |
| |
| protected java.lang.Object clone() throws java.lang.CloneNotSupportedException; |
| Code: |
| 0: new #1 // class java/lang/RuntimeException |
| 3: dup |
| 4: ldc #2 // String Stub! |
| 6: invokespecial #3 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V |
| 9: athrow |
| |
| public boolean equals(java.lang.Object); |
| Code: |
| 0: new #1 // class java/lang/RuntimeException |
| 3: dup |
| 4: ldc #2 // String Stub! |
| 6: invokespecial #3 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V |
| 9: athrow |
| |
| protected void finalize() throws java.lang.Throwable; |
| Code: |
| 0: new #1 // class java/lang/RuntimeException |
| 3: dup |
| 4: ldc #2 // String Stub! |
| 6: invokespecial #3 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V |
| 9: athrow |
| |
| public final native java.lang.Class<?> getClass(); |
| |
| public native int hashCode(); |
| |
| public final native void notify(); |
| |
| public final native void notifyAll(); |
| |
| public java.lang.String toString(); |
| Code: |
| 0: new #1 // class java/lang/RuntimeException |
| 3: dup |
| 4: ldc #2 // String Stub! |
| 6: invokespecial #3 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V |
| 9: athrow |
| |
| public final void wait() throws java.lang.InterruptedException; |
| Code: |
| 0: new #1 // class java/lang/RuntimeException |
| 3: dup |
| 4: ldc #2 // String Stub! |
| 6: invokespecial #3 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V |
| 9: athrow |
| |
| public final void wait(long) throws java.lang.InterruptedException; |
| Code: |
| 0: new #1 // class java/lang/RuntimeException |
| 3: dup |
| 4: ldc #2 // String Stub! |
| 6: invokespecial #3 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V |
| 9: athrow |
| |
| public final native void wait(long, int) throws java.lang.InterruptedException; |
| } |
| */ |
| String javaLangObjectClassFile = |
| "yv66vgAAADEALwcAJwgAKAoAAQApBwAqAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1i" + |
| "ZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABJMamF2YS9sYW5nL09iamVjdDsB" + |
| "AAVjbG9uZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAKRXhjZXB0aW9ucwcAKwEABmVxdWFscwEA" + |
| "FShMamF2YS9sYW5nL09iamVjdDspWgEAAW8BAAhmaW5hbGl6ZQcALAEACGdldENsYXNzAQATKClM" + |
| "amF2YS9sYW5nL0NsYXNzOwEACVNpZ25hdHVyZQEAFigpTGphdmEvbGFuZy9DbGFzczwqPjsBAAho" + |
| "YXNoQ29kZQEAAygpSQEABm5vdGlmeQEACW5vdGlmeUFsbAEACHRvU3RyaW5nAQAUKClMamF2YS9s" + |
| "YW5nL1N0cmluZzsBAAR3YWl0BwAtAQAEKEopVgEABm1pbGxpcwEAAUoBAAUoSkkpVgEAClNvdXJj" + |
| "ZUZpbGUBAAtPYmplY3QuamF2YQEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uAQAFU3R1YiEM" + |
| "AAUALgEAEGphdmEvbGFuZy9PYmplY3QBACRqYXZhL2xhbmcvQ2xvbmVOb3RTdXBwb3J0ZWRFeGNl" + |
| "cHRpb24BABNqYXZhL2xhbmcvVGhyb3dhYmxlAQAeamF2YS9sYW5nL0ludGVycnVwdGVkRXhjZXB0" + |
| "aW9uAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABAAAAAAAAAAMAAEABQAGAAEABwAAADQAAwAB" + |
| "AAAACrsAAVkSArcAA78AAAACAAgAAAAGAAEAAAAEAAkAAAAMAAEAAAAKAAoACwAAAAQADAANAAIA" + |
| "BwAAADQAAwABAAAACrsAAVkSArcAA78AAAACAAgAAAAGAAEAAAAFAAkAAAAMAAEAAAAKAAoACwAA" + |
| "AA4AAAAEAAEADwABABAAEQABAAcAAAA+AAMAAgAAAAq7AAFZEgK3AAO/AAAAAgAIAAAABgABAAAA" + |
| "BgAJAAAAFgACAAAACgAKAAsAAAAAAAoAEgALAAEABAATAAYAAgAHAAAANAADAAEAAAAKuwABWRIC" + |
| "twADvwAAAAIACAAAAAYAAQAAAAcACQAAAAwAAQAAAAoACgALAAAADgAAAAQAAQAUAREAFQAWAAEA" + |
| "FwAAAAIAGAEBABkAGgAAAREAGwAGAAABEQAcAAYAAAABAB0AHgABAAcAAAA0AAMAAQAAAAq7AAFZ" + |
| "EgK3AAO/AAAAAgAIAAAABgABAAAADAAJAAAADAABAAAACgAKAAsAAAARAB8ABgACAAcAAAA0AAMA" + |
| "AQAAAAq7AAFZEgK3AAO/AAAAAgAIAAAABgABAAAADQAJAAAADAABAAAACgAKAAsAAAAOAAAABAAB" + |
| "ACAAEQAfACEAAgAHAAAAPgADAAMAAAAKuwABWRICtwADvwAAAAIACAAAAAYAAQAAAA4ACQAAABYA" + |
| "AgAAAAoACgALAAAAAAAKACIAIwABAA4AAAAEAAEAIAERAB8AJAABAA4AAAAEAAEAIAABACUAAAAC" + |
| "ACY="; |
| |
| private void assertIsJavaLangObjet(ClassSubject clazz) { |
| assertTrue(clazz.getOriginalDescriptor().equals("Ljava/lang/Object;")); |
| assertNull(clazz.getDexClass().superType); |
| } |
| |
| private void checkApplicationOnlyHasJavaLangObject(AndroidApp app) throws Throwable { |
| CodeInspector inspector = new CodeInspector(app); |
| inspector.forAllClasses(this::assertIsJavaLangObjet); |
| } |
| |
| static class MemoryConsumer extends DexIndexedConsumer.ForwardingConsumer { |
| byte[] data; |
| |
| public MemoryConsumer() { |
| super(null); |
| } |
| |
| @Override |
| public void accept( |
| int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) { |
| assertEquals(0, fileIndex); |
| this.data = data.copyByteData(); |
| } |
| } |
| |
| @Test |
| public void test() throws Throwable { |
| // Build an application with the java.lang.Object stub from a class file. |
| MemoryConsumer consumer = new MemoryConsumer(); |
| AndroidAppConsumers appConsumer = new AndroidAppConsumers(); |
| D8.run( |
| D8Command.builder() |
| .setProgramConsumer(appConsumer.wrapProgramConsumer(consumer)) |
| .addClassProgramData( |
| Base64.getDecoder().decode(javaLangObjectClassFile), EmbeddedOrigin.INSTANCE) |
| .build()); |
| checkApplicationOnlyHasJavaLangObject(appConsumer.build()); |
| |
| // Build an application with the java.lang.Object stub from a dex file. |
| Builder builder = D8Command.builder(); |
| builder.addDexProgramData(consumer.data, Origin.unknown()); |
| appConsumer = new AndroidAppConsumers(builder); |
| D8.run(builder.build()); |
| checkApplicationOnlyHasJavaLangObject(appConsumer.build()); |
| } |
| } |