Main.java revision 973:d564abed1e6a
138102Speter/*
250472Speter * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
338102Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
473210Sgshapiro *
573210Sgshapiro * This code is free software; you can redistribute it and/or modify it
673210Sgshapiro * under the terms of the GNU General Public License version 2 only, as
773210Sgshapiro * published by the Free Software Foundation.  Oracle designates this
838102Speter * particular file as subject to the "Classpath" exception as provided
973250Sgshapiro * by Oracle in the LICENSE file that accompanied this code.
1073250Sgshapiro *
11120397Sgshapiro * This code is distributed in the hope that it will be useful, but WITHOUT
1273250Sgshapiro * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1373210Sgshapiro * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14120397Sgshapiro * version 2 for more details (a copy is included in the LICENSE file that
1538102Speter * accompanied this code).
16117286Sgshapiro *
1773210Sgshapiro * You should have received a copy of the GNU General Public License version
18117286Sgshapiro * 2 along with this work; if not, write to the Free Software Foundation,
1973210Sgshapiro * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20277787Sgshapiro *
21277787Sgshapiro * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22120397Sgshapiro * or visit www.oracle.com if you need additional information or have any
2373210Sgshapiro * questions.
2438102Speter */
25117288Sgshapiro
26117288Sgshapiropackage jdk.nashorn.internal.tools.nasgen;
27117288Sgshapiro
28119631Sgshapiroimport java.io.File;
29119631Sgshapiroimport java.io.FileInputStream;
3038102Speterimport java.io.FileOutputStream;
3172846Sgshapiroimport java.io.IOException;
32117288Sgshapiroimport java.io.PrintWriter;
3372846Sgshapiroimport jdk.internal.org.objectweb.asm.ClassReader;
3438102Speterimport jdk.internal.org.objectweb.asm.ClassWriter;
35124839Sruimport jdk.internal.org.objectweb.asm.Opcodes;
36124839Sruimport jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
37124839Sru
38117288Sgshapiro/**
39117288Sgshapiro * Main class for the "nasgen" tool.
40117373Sgshapiro *
41117288Sgshapiro */
42117288Sgshapiropublic class Main {
43117373Sgshapiro    /**
4472846Sgshapiro     * ASM version to be used by nasgen tool.
4538102Speter     */
4638102Speter    public static final int ASM_VERSION = Opcodes.ASM5;
47117288Sgshapiro
48117288Sgshapiro    private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug");
49117288Sgshapiro
50117373Sgshapiro    private interface ErrorReporter {
51117288Sgshapiro        public void error(String msg);
5294676Sgshapiro    }
5394676Sgshapiro
54117288Sgshapiro    /**
5572918Sgshapiro     * Public entry point for Nasgen if invoked from command line. Nasgen takes three arguments
56117288Sgshapiro     * in order: input directory, package list, output directory
5786639Sgshapiro     *
58117373Sgshapiro     * @param args argument vector
59117288Sgshapiro     */
60117288Sgshapiro    public static void main(final String[] args) {
61117288Sgshapiro        final ErrorReporter reporter = new ErrorReporter() {
6272918Sgshapiro            @Override
6372918Sgshapiro            public void error(final String msg) {
64117286Sgshapiro                Main.error(msg, 1);
6538102Speter            }
66124839Sru        };
67117288Sgshapiro        if (args.length == 3) {
68117288Sgshapiro            processAll(args[0], args[1], args[2], reporter);
69117288Sgshapiro        } else {
70121232Sgshapiro            error("Usage: nasgen <input-dir> <package-list> <output-dir>", 1);
71117288Sgshapiro        }
72117288Sgshapiro    }
73117288Sgshapiro
74117288Sgshapiro    private static void processAll(final String in, final String pkgList, final String out, final ErrorReporter reporter) {
75289200Speter        final File inDir = new File(in);
76124839Sru        if (!inDir.exists() || !inDir.isDirectory()) {
77289200Speter            reporter.error(in + " does not exist or not a directory");
78289200Speter            return;
79289200Speter        }
80124839Sru
8194676Sgshapiro        final File outDir = new File(out);
82124839Sru        if (!outDir.exists() || !outDir.isDirectory()) {
83100872Sru            reporter.error(out + " does not exist or not a directory");
84117286Sgshapiro            return;
8580176Sgshapiro        }
86289200Speter
87289200Speter        final String[] packages = pkgList.split(":");
88289200Speter        for (String pkg : packages) {
89117286Sgshapiro            pkg = pkg.replace('.', File.separatorChar);
90289200Speter            final File dir = new File(inDir, pkg);
91289200Speter            final File[] classes = dir.listFiles();
92289200Speter            for (final File clazz : classes) {
9386639Sgshapiro                if (clazz.isFile() && clazz.getName().endsWith(".class")) {
94289200Speter                    if (! process(clazz, new File(outDir, pkg), reporter)) {
9538102Speter                        return;
9638102Speter                    }
97                }
98            }
99        }
100    }
101
102    private static boolean process(final File inFile, final File outDir, final ErrorReporter reporter) {
103        try {
104            byte[] buf = new byte[(int)inFile.length()];
105
106            try (FileInputStream fin = new FileInputStream(inFile)) {
107                fin.read(buf);
108            }
109
110            final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(buf);
111
112            if (sci != null) {
113                try {
114                    sci.verify();
115                } catch (final Exception e) {
116                    reporter.error(e.getMessage());
117                    return false;
118                }
119
120                // create necessary output package dir
121                outDir.mkdirs();
122
123                // instrument @ScriptClass
124                final ClassWriter writer = ClassGenerator.makeClassWriter();
125                final ClassReader reader = new ClassReader(buf);
126                final ScriptClassInstrumentor inst = new ScriptClassInstrumentor(writer, sci);
127                reader.accept(inst, 0);
128                //noinspection UnusedAssignment
129
130                // write instrumented class
131                try (FileOutputStream fos = new FileOutputStream(new File(outDir, inFile.getName()))) {
132                    buf = writer.toByteArray();
133                    if (DEBUG) {
134                        verify(buf);
135                    }
136                    fos.write(buf);
137                }
138
139                // simple class name without package prefix
140                String simpleName = inFile.getName();
141                simpleName = simpleName.substring(0, simpleName.indexOf(".class"));
142
143                if (sci.getPrototypeMemberCount() > 0) {
144                    // generate prototype class
145                    final PrototypeGenerator protGen = new PrototypeGenerator(sci);
146                    buf = protGen.getClassBytes();
147                    if (DEBUG) {
148                        verify(buf);
149                    }
150                    try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.PROTOTYPE_SUFFIX + ".class"))) {
151                        fos.write(buf);
152                    }
153                }
154
155                if (sci.getConstructorMemberCount() > 0 || sci.getConstructor() != null) {
156                    // generate constructor class
157                    final ConstructorGenerator consGen = new ConstructorGenerator(sci);
158                    buf = consGen.getClassBytes();
159                    if (DEBUG) {
160                        verify(buf);
161                    }
162                    try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.CONSTRUCTOR_SUFFIX + ".class"))) {
163                        fos.write(buf);
164                    }
165                }
166            }
167            return true;
168        } catch (final IOException | RuntimeException e) {
169            if (DEBUG) {
170                e.printStackTrace(System.err);
171            }
172            reporter.error(e.getMessage());
173
174            return false;
175        }
176    }
177
178    private static void verify(final byte[] buf) {
179        final ClassReader cr = new ClassReader(buf);
180        CheckClassAdapter.verify(cr, false, new PrintWriter(System.err));
181    }
182
183    private static void error(final String msg, final int exitCode) {
184        System.err.println(msg);
185        System.exit(exitCode);
186    }
187}
188