1 /*
2 * Copyright (c) 2022, 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 */
23 package org.openjdk.asmtools;
24
25 import java.lang.reflect.Method;
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.ArrayList;
28 import java.nio.file.Path;
29 import java.nio.file.InvalidPathException;
30 import java.nio.file.Files;
31 import java.io.PrintWriter;
32 import java.io.IOException;
33 import org.openjdk.asmtools.jdis.uEscWriter;
34
35 /**
36 * An entry point to AsmTools for use with the jtreg '@run driver' command.
37 * Unlike 'Main', never invokes 'System.exit' (which crashes jtreg).
38 *
39 * Also adjusts file paths:
40 *
41 * - For jasm and jcoder, source files are expected to appear in ${test.src},
42 * and output is sent to ${test.classes}
43 *
44 * - For other tools, class files are expected to appear in ${test.classes},
45 * and output is sent to the scratch working directory
46 *
47 * Example jtreg usage:
48 *
49 * @library /test/lib
50 * @build org.openjdk.asmtools.* org.openjdk.asmtools.jasm.*
51 * @run driver org.openjdk.asmtools.JtregDriver jasm -strict TestFile.jasm
52 */
53 public class JtregDriver {
54
55 public static void main(String... args) throws Throwable {
56 // run AltLoaderMain from a class loader that prefers the modified AsmTools classes
57 ClassLoader loader = JtregDriver.class.getClassLoader();
58 Path file = Path.of(loader.getResource("org/openjdk/asmtools/JtregDriver.class").toURI());
59 Path root = file.getParent().getParent().getParent().getParent();
60 ClassLoader altLoader = new AsmToolsClassLoader(root);
61 Class<?> altMain = altLoader.loadClass(AltLoaderMain.class.getName());
62 try {
63 altMain.getMethod("main", String[].class).invoke(null, (Object) args);
64 } catch (InvocationTargetException e) {
65 throw e.getCause();
66 }
67 }
68
69 public static class AltLoaderMain {
70
71 public static void main(String... args) throws IOException {
72 if (args.length == 0) {
73 throw new IllegalArgumentException("Missing asmtools command");
74 }
75 String cmd = args[0];
76 if (!cmd.equals("jasm") && !cmd.equals("jdis") && !cmd.equals("jcoder")
77 && !cmd.equals("jdec") && !cmd.equals("jcdec")) {
78 throw new IllegalArgumentException("Unrecognized asmtools command: " + cmd);
79 }
80 boolean isAssembler = cmd.equals("jasm") || cmd.equals("jcoder");
81 String srcDir = System.getProperty("test.src", ".");
82 String clsDir = System.getProperty("test.classes", ".");
83 String fileDir = isAssembler ? srcDir : clsDir;
84
85 ArrayList<String> toolArgList = new ArrayList<String>();
86
87 if (isAssembler) {
88 Path destPath = Path.of(clsDir);
89 if (!Files.exists(destPath)) {
90 // jtreg creates classes dir on demand, might not have happened yet
91 Files.createDirectories(destPath);
92 }
93 toolArgList.add("-d");
94 toolArgList.add(clsDir);
95 }
96
97 boolean isOptionArg = false; // marks an argument to a previous option
98 for (int i = 1; i < args.length; i++) {
99 String arg = args[i];
100 if (isOptionArg) {
101 isOptionArg = false; // reset for next
102 } else {
103 if (arg.equals("-d")) {
104 isOptionArg = true;
105 } else if (!arg.startsWith("-") && !arg.startsWith("/")) {
106 // adjust filename
107 arg = Path.of(fileDir, arg).toString();
108 }
109 }
110 toolArgList.add(arg);
111 }
112
113 String[] toolArgs = toolArgList.toArray(new String[0]);
114 boolean success = switch (cmd) {
115 case "jasm" -> {
116 PrintWriter out = new PrintWriter(System.out);
117 yield new org.openjdk.asmtools.jasm.Main(out, "jasm").compile(toolArgs);
118 }
119 case "jdis" -> {
120 PrintWriter out = new PrintWriter(new uEscWriter(System.out));
121 PrintWriter err = new PrintWriter(System.err);
122 yield new org.openjdk.asmtools.jdis.Main(out, err, "jdis").disasm(toolArgs);
123 }
124 case "jcoder" -> {
125 PrintWriter out = new PrintWriter(System.out);
126 yield new org.openjdk.asmtools.jcoder.Main(out, "jcoder").compile(toolArgs);
127 }
128 case "jdec" -> {
129 PrintWriter out = new PrintWriter(new uEscWriter(System.out));
130 PrintWriter err = new PrintWriter(System.err);
131 yield new org.openjdk.asmtools.jdec.Main(out, err, "jdec").decode(toolArgs);
132 }
133 case "jcdec" -> {
134 PrintWriter out = new PrintWriter(new uEscWriter(System.out));
135 yield new org.openjdk.asmtools.jcdec.Main(out, "jcdec").decode(toolArgs);
136 }
137 default -> throw new AssertionError();
138 };
139 if (!success) {
140 throw new RuntimeException("asmtools execution failed");
141 }
142 }
143
144 }
145
146 /**
147 * Class loader for the AsmTools classes. Allows classes colocated with
148 * JtregDriver to have priority over versions of the classes loaded by
149 * jtreg (which includes its own copy of AsmTools).
150 */
151 private static class AsmToolsClassLoader extends ClassLoader {
152 private final Path root;
153 private final String separator;
154
155 public AsmToolsClassLoader(Path root) {
156 super(AsmToolsClassLoader.class.getClassLoader());
157 this.root = root;
158 this.separator = root.getFileSystem().getSeparator();
159 }
160
161 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
162 if (name.startsWith("org.openjdk.asmtools.")) {
163 Class<?> result = findClass(name);
164 if (resolve) resolveClass(result);
165 return result;
166 } else {
167 return super.loadClass(name, resolve);
168 }
169 }
170
171 protected Class<?> findClass(String name) throws ClassNotFoundException {
172 String filename = name.replace(".",separator) + ".class";
173 try {
174 Path classFile = root.resolve(filename);
175 byte[] bytes = Files.readAllBytes(classFile);
176 return defineClass(name, bytes, 0, bytes.length);
177 } catch (InvalidPathException | IOException e) {
178 throw new ClassNotFoundException("can't read class " + filename, e);
179 }
180 }
181
182 }
183
184 }