Fri, 24 Apr 2020 03:58:51 +0100
Merge
1 /*
2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
24 import java.io.DataInputStream;
25 import java.io.File;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.PrintWriter;
29 import java.io.StringWriter;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Enumeration;
33 import java.util.List;
34 import java.util.Set;
35 import java.util.TreeSet;
36 import java.util.jar.JarEntry;
37 import java.util.jar.JarFile;
39 import com.sun.tools.classfile.AccessFlags;
40 import com.sun.tools.classfile.ClassFile;
41 import com.sun.tools.classfile.ConstantPoolException;
42 import com.sun.tools.classfile.Method;
43 import java.io.BufferedReader;
44 import java.io.FileInputStream;
45 import java.io.InputStreamReader;
46 import java.util.LinkedHashSet;
48 public class CompareTest {
49 String[][] testCases = {
50 { },
51 { "-jni" },
52 // { "-llni" },
53 };
55 public static void main(String... args) throws Exception {
56 new CompareTest().run(args);
57 }
59 public void run(String... args) throws Exception {
60 old_javah_cmd = new File(args[0]);
61 rt_jar = new File(args[1]);
63 Set<String> testClasses;
64 if (args.length > 2) {
65 testClasses = new LinkedHashSet<String>(Arrays.asList(Arrays.copyOfRange(args, 2, args.length)));
66 } else
67 testClasses = getNativeClasses(new JarFile(rt_jar));
69 for (String[] options: testCases) {
70 for (String name: testClasses) {
71 test(Arrays.asList(options), rt_jar, name);
72 }
73 }
75 if (errors == 0)
76 System.out.println(count + " tests passed");
77 else
78 throw new Exception(errors + "/" + count + " tests failed");
79 }
81 public void test(List<String> options, File bootclasspath, String className)
82 throws IOException, InterruptedException {
83 System.err.println("test: " + options + " " + className);
84 count++;
86 testOptions = options;
87 testClassName = className;
89 File oldOutDir = initDir(file(new File("old"), className));
90 int old_rc = old_javah(options, oldOutDir, bootclasspath, className);
92 File newOutDir = initDir(file(new File("new"), className));
93 int new_rc = new_javah(options, newOutDir, bootclasspath, className);
95 if (old_rc != new_rc)
96 error("return codes differ; old: " + old_rc + ", new: " + new_rc);
98 compare(oldOutDir, newOutDir);
99 }
101 int old_javah(List<String> options, File outDir, File bootclasspath, String className)
102 throws IOException, InterruptedException {
103 List<String> cmd = new ArrayList<String>();
104 cmd.add(old_javah_cmd.getPath());
105 cmd.addAll(options);
106 cmd.add("-d");
107 cmd.add(outDir.getPath());
108 cmd.add("-bootclasspath");
109 cmd.add(bootclasspath.getPath());
110 cmd.add(className);
111 System.err.println("old_javah: " + cmd);
112 ProcessBuilder pb = new ProcessBuilder(cmd);
113 pb.redirectErrorStream(true);
114 Process p = pb.start();
115 BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
116 String line;
117 StringBuilder sb = new StringBuilder();
118 while ((line = in.readLine()) != null) {
119 sb.append(line);
120 sb.append("\n");
121 }
122 System.err.println("old javah out: " + sb.toString());
123 return p.waitFor();
124 }
126 int new_javah(List<String> options, File outDir, File bootclasspath, String className) {
127 List<String> args = new ArrayList<String>();
128 args.addAll(options);
129 args.add("-d");
130 args.add(outDir.getPath());
131 args.add("-bootclasspath");
132 args.add(bootclasspath.getPath());
133 args.add(className);
134 StringWriter sw = new StringWriter();
135 PrintWriter pw = new PrintWriter(sw);
136 int rc = com.sun.tools.javah.Main.run(args.toArray(new String[args.size()]), pw);
137 pw.close();
138 System.err.println("new javah out: " + sw.toString());
139 return rc;
140 }
142 Set<String> getNativeClasses(JarFile jar) throws IOException, ConstantPoolException {
143 System.err.println("getNativeClasses: " + jar.getName());
144 Set<String> results = new TreeSet<String>();
145 Enumeration<JarEntry> e = jar.entries();
146 while (e.hasMoreElements()) {
147 JarEntry je = e.nextElement();
148 if (isNativeClass(jar, je)) {
149 String name = je.getName();
150 results.add(name.substring(0, name.length() - 6).replace("/", "."));
151 }
152 }
153 return results;
154 }
156 boolean isNativeClass(JarFile jar, JarEntry entry) throws IOException, ConstantPoolException {
157 String name = entry.getName();
158 if (name.startsWith("META-INF") || !name.endsWith(".class"))
159 return false;
160 //String className = name.substring(0, name.length() - 6).replace("/", ".");
161 //System.err.println("check " + className);
162 InputStream in = jar.getInputStream(entry);
163 ClassFile cf = ClassFile.read(in);
164 for (int i = 0; i < cf.methods.length; i++) {
165 Method m = cf.methods[i];
166 if (m.access_flags.is(AccessFlags.ACC_NATIVE)) {
167 // System.err.println(className);
168 return true;
169 }
170 }
171 return false;
172 }
174 void compare(File f1, File f2) throws IOException {
175 if (f1.isFile() && f2.isFile())
176 compareFiles(f1, f2);
177 else if (f1.isDirectory() && f2.isDirectory())
178 compareDirectories(f1, f2);
179 else
180 error("files differ: "
181 + f1 + " (" + getFileType(f1) + "), "
182 + f2 + " (" + getFileType(f2) + ")");
183 }
185 void compareDirectories(File d1, File d2) throws IOException {
186 Set<String> list = new TreeSet<String>();
187 list.addAll(Arrays.asList(d1.list()));
188 list.addAll(Arrays.asList(d2.list()));
189 for (String c: list)
190 compare(new File(d1, c), new File(d2, c));
191 }
193 void compareFiles(File f1, File f2) throws IOException {
194 byte[] c1 = readFile(f1);
195 byte[] c2 = readFile(f2);
196 if (!Arrays.equals(c1, c2))
197 error("files differ: " + f1 + ", " + f2);
198 }
200 byte[] readFile(File file) throws IOException {
201 int size = (int) file.length();
202 byte[] data = new byte[size];
203 DataInputStream in = new DataInputStream(new FileInputStream(file));
204 try {
205 in.readFully(data);
206 } finally {
207 in.close();
208 }
209 return data;
210 }
212 String getFileType(File f) {
213 return f.isDirectory() ? "directory"
214 : f.isFile() ? "file"
215 : f.exists() ? "other"
216 : "not found";
217 }
219 /**
220 * Set up an empty directory.
221 */
222 public File initDir(File dir) {
223 if (dir.exists())
224 deleteAll(dir);
225 dir.mkdirs();
226 return dir;
227 }
229 /**
230 * Delete a file or a directory (including all its contents).
231 */
232 boolean deleteAll(File file) {
233 if (file.isDirectory()) {
234 for (File f: file.listFiles())
235 deleteAll(f);
236 }
237 return file.delete();
238 }
240 File file(File dir, String... path) {
241 File f = dir;
242 for (String p: path)
243 f = new File(f, p);
244 return f;
245 }
247 /**
248 * Report an error.
249 */
250 void error(String msg, String... more) {
251 System.err.println("test: " + testOptions + " " + testClassName);
252 System.err.println("error: " + msg);
253 for (String s: more)
254 System.err.println(s);
255 errors++;
256 System.exit(1);
257 }
259 File old_javah_cmd;
260 File rt_jar;
261 List<String> testOptions;
262 String testClassName;
263 int count;
264 int errors;
265 }