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