Main.java revision 6:5a1b0714df0e
1189251Ssam/* 2189251Ssam * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3214734Srpaulo * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4189251Ssam * 5252726Srpaulo * This code is free software; you can redistribute it and/or modify it 6252726Srpaulo * under the terms of the GNU General Public License version 2 only, as 7189251Ssam * published by the Free Software Foundation. Oracle designates this 8189251Ssam * particular file as subject to the "Classpath" exception as provided 9189251Ssam * by Oracle in the LICENSE file that accompanied this code. 10189251Ssam * 11189251Ssam * This code is distributed in the hope that it will be useful, but WITHOUT 12214734Srpaulo * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13214734Srpaulo * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14189251Ssam * version 2 for more details (a copy is included in the LICENSE file that 15189251Ssam * accompanied this code). 16252726Srpaulo * 17252726Srpaulo * You should have received a copy of the GNU General Public License version 18252726Srpaulo * 2 along with this work; if not, write to the Free Software Foundation, 19252726Srpaulo * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20189251Ssam * 21252726Srpaulo * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22189251Ssam * or visit www.oracle.com if you need additional information or have any 23189251Ssam * questions. 24189251Ssam */ 25189251Ssam 26189251Ssampackage jdk.nashorn.internal.tools.nasgen; 27214734Srpaulo 28214734Srpauloimport java.io.File; 29214734Srpauloimport java.io.FileInputStream; 30189251Ssamimport java.io.FileOutputStream; 31189251Ssamimport java.io.IOException; 32189251Ssamimport java.io.PrintWriter; 33214734Srpauloimport jdk.internal.org.objectweb.asm.ClassReader; 34189251Ssamimport jdk.internal.org.objectweb.asm.ClassWriter; 35189251Ssamimport jdk.internal.org.objectweb.asm.util.CheckClassAdapter; 36189251Ssam 37189251Ssam/** 38214734Srpaulo * Main class for the "nasgen" tool. 39214734Srpaulo * 40214734Srpaulo */ 41189251Ssampublic class Main { 42189251Ssam private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug"); 43189251Ssam 44189251Ssam private interface ErrorReporter { 45189251Ssam public void error(String msg); 46189251Ssam } 47189251Ssam 48189251Ssam /** 49189251Ssam * Public entry point for Nasgen if invoked from command line. Nasgen takes three arguments 50189251Ssam * in order: input directory, package list, output directory 51189251Ssam * 52189251Ssam * @param args argument vector 53189251Ssam */ 54189251Ssam public static void main(final String[] args) { 55189251Ssam final ErrorReporter reporter = new ErrorReporter() { 56189251Ssam @Override 57189251Ssam public void error(final String msg) { 58189251Ssam Main.error(msg, 1); 59252726Srpaulo } 60252726Srpaulo }; 61252726Srpaulo if (args.length == 3) { 62252726Srpaulo processAll(args[0], args[1], args[2], reporter); 63252726Srpaulo } else { 64252726Srpaulo error("Usage: nasgen <input-dir> <package-list> <output-dir>", 1); 65252726Srpaulo } 66189251Ssam } 67189251Ssam 68189251Ssam private static void processAll(final String in, final String pkgList, final String out, final ErrorReporter reporter) { 69189251Ssam final File inDir = new File(in); 70214734Srpaulo if (!inDir.exists() || !inDir.isDirectory()) { 71189251Ssam reporter.error(in + " does not exist or not a directory"); 72189251Ssam return; 73189251Ssam } 74189251Ssam 75189251Ssam final File outDir = new File(out); 76189251Ssam if (!outDir.exists() || !outDir.isDirectory()) { 77189251Ssam reporter.error(out + " does not exist or not a directory"); 78189251Ssam return; 79189251Ssam } 80189251Ssam 81189251Ssam final String[] packages = pkgList.split(":"); 82189251Ssam for (String pkg : packages) { 83189251Ssam pkg = pkg.replace('.', File.separatorChar); 84214734Srpaulo final File dir = new File(inDir, pkg); 85214734Srpaulo final File[] classes = dir.listFiles(); 86214734Srpaulo for (final File clazz : classes) { 87189251Ssam if (clazz.isFile() && clazz.getName().endsWith(".class")) { 88214734Srpaulo if (! process(clazz, new File(outDir, pkg), reporter)) { 89214734Srpaulo return; 90214734Srpaulo } 91214734Srpaulo } 92214734Srpaulo } 93214734Srpaulo } 94214734Srpaulo } 95214734Srpaulo 96214734Srpaulo private static boolean process(final File inFile, final File outDir, final ErrorReporter reporter) { 97214734Srpaulo try { 98214734Srpaulo byte[] buf = new byte[(int)inFile.length()]; 99214734Srpaulo 100214734Srpaulo try (FileInputStream fin = new FileInputStream(inFile)) { 101214734Srpaulo fin.read(buf); 102214734Srpaulo } 103214734Srpaulo 104214734Srpaulo final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(buf); 105214734Srpaulo 106214734Srpaulo if (sci != null) { 107214734Srpaulo try { 108214734Srpaulo sci.verify(); 109214734Srpaulo } catch (final Exception e) { 110214734Srpaulo reporter.error(e.getMessage()); 111214734Srpaulo return false; 112214734Srpaulo } 113214734Srpaulo 114214734Srpaulo // create necessary output package dir 115214734Srpaulo outDir.mkdirs(); 116214734Srpaulo 117214734Srpaulo // instrument @ScriptClass 118214734Srpaulo final ClassWriter writer = ClassGenerator.makeClassWriter(); 119214734Srpaulo final ClassReader reader = new ClassReader(buf); 120214734Srpaulo final ScriptClassInstrumentor inst = new ScriptClassInstrumentor(writer, sci); 121214734Srpaulo reader.accept(inst, 0); 122214734Srpaulo //noinspection UnusedAssignment 123214734Srpaulo 124214734Srpaulo // write instrumented class 125214734Srpaulo try (FileOutputStream fos = new FileOutputStream(new File(outDir, inFile.getName()))) { 126214734Srpaulo buf = writer.toByteArray(); 127214734Srpaulo if (DEBUG) { 128214734Srpaulo verify(buf); 129189251Ssam } 130214734Srpaulo fos.write(buf); 131214734Srpaulo } 132214734Srpaulo 133214734Srpaulo // simple class name without package prefix 134189251Ssam String simpleName = inFile.getName(); 135189251Ssam simpleName = simpleName.substring(0, simpleName.indexOf(".class")); 136189251Ssam 137189251Ssam if (sci.getPrototypeMemberCount() > 0) { 138189251Ssam // generate prototype class 139189251Ssam final PrototypeGenerator protGen = new PrototypeGenerator(sci); 140189251Ssam buf = protGen.getClassBytes(); 141189251Ssam if (DEBUG) { 142189251Ssam verify(buf); 143252726Srpaulo } 144189251Ssam try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.PROTOTYPE_SUFFIX + ".class"))) { 145252726Srpaulo fos.write(buf); 146252726Srpaulo } 147252726Srpaulo } 148252726Srpaulo 149252726Srpaulo if (sci.getConstructorMemberCount() > 0 || sci.getConstructor() != null) { 150189251Ssam // generate constructor class 151189251Ssam final ConstructorGenerator consGen = new ConstructorGenerator(sci); 152189251Ssam buf = consGen.getClassBytes(); 153252726Srpaulo if (DEBUG) { 154252726Srpaulo verify(buf); 155252726Srpaulo } 156252726Srpaulo try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.CONSTRUCTOR_SUFFIX + ".class"))) { 157252726Srpaulo fos.write(buf); 158252726Srpaulo } 159252726Srpaulo } 160252726Srpaulo } 161252726Srpaulo return true; 162252726Srpaulo } catch (final IOException | RuntimeException e) { 163252726Srpaulo if (DEBUG) { 164252726Srpaulo e.printStackTrace(System.err); 165252726Srpaulo } 166252726Srpaulo reporter.error(e.getMessage()); 167252726Srpaulo 168252726Srpaulo return false; 169252726Srpaulo } 170252726Srpaulo } 171252726Srpaulo 172252726Srpaulo private static void verify(final byte[] buf) { 173252726Srpaulo final ClassReader cr = new ClassReader(buf); 174252726Srpaulo CheckClassAdapter.verify(cr, false, new PrintWriter(System.err)); 175252726Srpaulo } 176252726Srpaulo 177252726Srpaulo private static void error(final String msg, final int exitCode) { 178214734Srpaulo System.err.println(msg); 179252726Srpaulo System.exit(exitCode); 180252726Srpaulo } 181189251Ssam} 182189251Ssam