1// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5package com.android.tools.r8.regress;
6
7import static org.junit.Assert.assertEquals;
8import static org.junit.Assert.assertNull;
9import static org.junit.Assert.assertTrue;
10
11import com.android.tools.r8.D8Command;
12import com.android.tools.r8.ToolHelper;
13import com.android.tools.r8.smali.SmaliTestBase;
14import com.android.tools.r8.utils.AndroidApp;
15import com.android.tools.r8.utils.DexInspector;
16import com.android.tools.r8.utils.DexInspector.ClassSubject;
17import java.util.Base64;
18import java.util.List;
19import org.junit.Test;
20
21public class Regress37740372 extends SmaliTestBase {
22
23  /*
24    Binary class file data for a java.lang.Object stub implementation. Runnong javap -c on the
25    bytecode produces the following output:
26
27    Compiled from "Object.java"
28    public class java.lang.Object {
29      public java.lang.Object();
30        Code:
31           0: new           #1                  // class java/lang/RuntimeException
32           3: dup
33           4: ldc           #2                  // String Stub!
34           6: invokespecial #3                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
35           9: athrow
36
37      protected java.lang.Object clone() throws java.lang.CloneNotSupportedException;
38        Code:
39           0: new           #1                  // class java/lang/RuntimeException
40           3: dup
41           4: ldc           #2                  // String Stub!
42           6: invokespecial #3                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
43           9: athrow
44
45      public boolean equals(java.lang.Object);
46        Code:
47           0: new           #1                  // class java/lang/RuntimeException
48           3: dup
49           4: ldc           #2                  // String Stub!
50           6: invokespecial #3                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
51           9: athrow
52
53      protected void finalize() throws java.lang.Throwable;
54        Code:
55           0: new           #1                  // class java/lang/RuntimeException
56           3: dup
57           4: ldc           #2                  // String Stub!
58           6: invokespecial #3                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
59           9: athrow
60
61      public final native java.lang.Class<?> getClass();
62
63      public native int hashCode();
64
65      public final native void notify();
66
67      public final native void notifyAll();
68
69      public java.lang.String toString();
70        Code:
71           0: new           #1                  // class java/lang/RuntimeException
72           3: dup
73           4: ldc           #2                  // String Stub!
74           6: invokespecial #3                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
75           9: athrow
76
77      public final void wait() throws java.lang.InterruptedException;
78        Code:
79           0: new           #1                  // class java/lang/RuntimeException
80           3: dup
81           4: ldc           #2                  // String Stub!
82           6: invokespecial #3                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
83           9: athrow
84
85      public final void wait(long) throws java.lang.InterruptedException;
86        Code:
87           0: new           #1                  // class java/lang/RuntimeException
88           3: dup
89           4: ldc           #2                  // String Stub!
90           6: invokespecial #3                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
91           9: athrow
92
93      public final native void wait(long, int) throws java.lang.InterruptedException;
94    }
95  */
96  String javaLangObjectClassFile =
97      "yv66vgAAADEALwcAJwgAKAoAAQApBwAqAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1i" +
98          "ZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABJMamF2YS9sYW5nL09iamVjdDsB" +
99          "AAVjbG9uZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAKRXhjZXB0aW9ucwcAKwEABmVxdWFscwEA" +
100          "FShMamF2YS9sYW5nL09iamVjdDspWgEAAW8BAAhmaW5hbGl6ZQcALAEACGdldENsYXNzAQATKClM" +
101          "amF2YS9sYW5nL0NsYXNzOwEACVNpZ25hdHVyZQEAFigpTGphdmEvbGFuZy9DbGFzczwqPjsBAAho" +
102          "YXNoQ29kZQEAAygpSQEABm5vdGlmeQEACW5vdGlmeUFsbAEACHRvU3RyaW5nAQAUKClMamF2YS9s" +
103          "YW5nL1N0cmluZzsBAAR3YWl0BwAtAQAEKEopVgEABm1pbGxpcwEAAUoBAAUoSkkpVgEAClNvdXJj" +
104          "ZUZpbGUBAAtPYmplY3QuamF2YQEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uAQAFU3R1YiEM" +
105          "AAUALgEAEGphdmEvbGFuZy9PYmplY3QBACRqYXZhL2xhbmcvQ2xvbmVOb3RTdXBwb3J0ZWRFeGNl" +
106          "cHRpb24BABNqYXZhL2xhbmcvVGhyb3dhYmxlAQAeamF2YS9sYW5nL0ludGVycnVwdGVkRXhjZXB0" +
107          "aW9uAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABAAAAAAAAAAMAAEABQAGAAEABwAAADQAAwAB" +
108          "AAAACrsAAVkSArcAA78AAAACAAgAAAAGAAEAAAAEAAkAAAAMAAEAAAAKAAoACwAAAAQADAANAAIA" +
109          "BwAAADQAAwABAAAACrsAAVkSArcAA78AAAACAAgAAAAGAAEAAAAFAAkAAAAMAAEAAAAKAAoACwAA" +
110          "AA4AAAAEAAEADwABABAAEQABAAcAAAA+AAMAAgAAAAq7AAFZEgK3AAO/AAAAAgAIAAAABgABAAAA" +
111          "BgAJAAAAFgACAAAACgAKAAsAAAAAAAoAEgALAAEABAATAAYAAgAHAAAANAADAAEAAAAKuwABWRIC" +
112          "twADvwAAAAIACAAAAAYAAQAAAAcACQAAAAwAAQAAAAoACgALAAAADgAAAAQAAQAUAREAFQAWAAEA" +
113          "FwAAAAIAGAEBABkAGgAAAREAGwAGAAABEQAcAAYAAAABAB0AHgABAAcAAAA0AAMAAQAAAAq7AAFZ" +
114          "EgK3AAO/AAAAAgAIAAAABgABAAAADAAJAAAADAABAAAACgAKAAsAAAARAB8ABgACAAcAAAA0AAMA" +
115          "AQAAAAq7AAFZEgK3AAO/AAAAAgAIAAAABgABAAAADQAJAAAADAABAAAACgAKAAsAAAAOAAAABAAB" +
116          "ACAAEQAfACEAAgAHAAAAPgADAAMAAAAKuwABWRICtwADvwAAAAIACAAAAAYAAQAAAA4ACQAAABYA" +
117          "AgAAAAoACgALAAAAAAAKACIAIwABAA4AAAAEAAEAIAERAB8AJAABAA4AAAAEAAEAIAABACUAAAAC" +
118          "ACY=";
119
120  private void assertIsJavaLangObjet(ClassSubject clazz) {
121    assertTrue(clazz.getOriginalDescriptor().equals("Ljava/lang/Object;"));
122    assertNull(clazz.getDexClass().superType);
123  }
124
125  private void checkApplicationOnlyHasJavaLangObject(AndroidApp app) throws Throwable {
126    DexInspector inspector = new DexInspector(app);
127    inspector.forAllClasses(this::assertIsJavaLangObjet);
128  }
129
130  @Test
131  public void test() throws Throwable {
132    // Build an application with the java.lang.Object stub from a class file.
133    AndroidApp output =
134        ToolHelper.runD8(
135            D8Command.builder()
136                .addClassProgramData(Base64.getDecoder().decode(javaLangObjectClassFile))
137                .build());
138    checkApplicationOnlyHasJavaLangObject(output);
139
140    // Build an application with the java.lang.Object stub from a dex file.
141    List<byte[]> dex = output.writeToMemory();
142    assertEquals(1, dex.size());
143    checkApplicationOnlyHasJavaLangObject(
144        ToolHelper.runD8(D8Command.builder().addDexProgramData(dex).build()));
145  }
146}
147