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 }