diff --git a/BytecodeViewer 2.9.7.jar b/BytecodeViewer 2.9.7.jar deleted file mode 100644 index fa82a758..00000000 Binary files a/BytecodeViewer 2.9.7.jar and /dev/null differ diff --git a/BytecodeViewer 2.9.8-fatjar.jar b/BytecodeViewer 2.9.8-fatjar.jar new file mode 100644 index 00000000..1613637d Binary files /dev/null and b/BytecodeViewer 2.9.8-fatjar.jar differ diff --git a/BytecodeViewer 2.9.8-preview-4.jar b/BytecodeViewer 2.9.8-preview-4.jar deleted file mode 100644 index 844ae2da..00000000 Binary files a/BytecodeViewer 2.9.8-preview-4.jar and /dev/null differ diff --git a/BytecodeViewer 2.9.8.jar b/BytecodeViewer 2.9.8.jar new file mode 100644 index 00000000..56a56384 Binary files /dev/null and b/BytecodeViewer 2.9.8.jar differ diff --git a/README.txt b/README.txt index 89172507..ab894300 100644 --- a/README.txt +++ b/README.txt @@ -385,4 +385,33 @@ Changelog: 07/16/2015 - Removed the FileFilter classes. 07/16/2015 - Updated the decompiler class to make more sense. 07/16/2015 - Started working on BCV CLI. -07/16/2015 - Finished BCV CLI. \ No newline at end of file +07/16/2015 - Finished BCV CLI. +--- 2.9.8 ---: +07/19/2015 - Fixed enjarify. +07/20/2015 - Bibl sexified the boot loading time. +07/20/2015 - Decode APK Resources is selected by default. +07/20/2015 - Made the security manager slightly safer, it can still be targeted but not as obviously now. +07/20/2015 - Added CLI to the boot page. +07/21/2015 - Added support for offline mode in case you cannot connect to github for some reason. (kicks in after 7 seconds) +07/21/2015 - Added fatjar option back, in case anyone wants a 100% portable version. +07/21/2015 - Made it so it now shows the decompiler it's using - http://i.imgur.com/yMEzXwv.png. +07/21/2015 - Rewrote the file system, it now shows the path of the jar it's got loaded. +07/21/2015 - Now it shows if the decompiler is in editable mode or not. +07/21/2015 - Fixed Enjarify bug from new security manager. +07/22/2015 - Fixed a typo (Thanks affffsdsd) +07/22/2015 - Finally added icons to the File Navigator, credits to http://famfamfam.com/lab/icons/silk/ for the icons. +07/22/2015 - JD-GUI is now the default decompiler for GUI. +07/22/2015 - Added Set Python 3.X to the UI. +07/22/2015 - Fixed krakatau/export as jar bug introduced by file system update. +07/22/2015 - Sped up krakatau decompiler/disassembler on big files. +07/22/2015 - Made it so when you press enter on the file navigation pane it opens the class. +07/22/2015 - The Quick file search now opens the files again. +07/23/2015 - Fixed opening single files and file folders into BCV +07/24/2015 - Added File>Reload Resources. +07/26/2015 - Fixed the view pane refresh after toggling a viewer, it's now flawless. +07/26/2015 - Fixed Krakatau Disassembler. +07/26/2015 - Mibbzz is gay once again. +07/30/2015 - Removed Janino Compiler & moved to Javac, it can now compile decompiled classes again. +07/30/2015 - Affssdd fixed the File Navigator Pane's Quick Class Search. +07/30/2015 - Fixed a process leak in KrakatauDisassembler. +07/30/2015 - Started working on converting all the decompilers to launch in their own process in an effort to reduce BCV resources (only for non-fatjar version). \ No newline at end of file diff --git a/install/launch4j_config.xml b/install/launch4j_config.xml index b7115b83..5bfb07cd 100644 --- a/install/launch4j_config.xml +++ b/install/launch4j_config.xml @@ -12,7 +12,7 @@ w32api/libuser32.a w32api/libadvapi32.a w32api/libshell32.a - H:\Repo\BCV\bytecode-viewer\BytecodeViewer 2.9.7.jar + H:\Repo\BCV\bytecode-viewer\BytecodeViewer 2.9.8.jar H:\Repo\BCV\bytecode-viewer\BytecodeViewer.exe diff --git a/libs/commons-compiler-jdk.jar b/libs/commons-compiler-jdk.jar deleted file mode 100644 index 08958698..00000000 Binary files a/libs/commons-compiler-jdk.jar and /dev/null differ diff --git a/libs/janino.jar b/libs/janino.jar new file mode 100644 index 00000000..79b946df Binary files /dev/null and b/libs/janino.jar differ diff --git a/src/org/codehaus/janino/Access.java b/src/org/codehaus/janino/Access.java deleted file mode 100644 index ab6310b3..00000000 --- a/src/org/codehaus/janino/Access.java +++ /dev/null @@ -1,56 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -import org.codehaus.janino.util.enumerator.Enumerator; -import org.codehaus.janino.util.enumerator.EnumeratorFormatException; - -/** Return value for {@link IClass.IMember#getAccess}. */ -public final -class Access extends Enumerator { - - /** Representation of PRIVATE accessibility. */ - public static final Access PRIVATE = new Access("private"); - - /** Representation of PROTECTED accessibility. */ - public static final Access PROTECTED = new Access("protected"); - - /** Representation of DEFAULT accessibility. */ - public static final Access DEFAULT = new Access("/*default*/"); - - /** Representation of PUBLIC accessibility. */ - public static final Access PUBLIC = new Access("public"); - - // These MUST be declared exactly like this: - private Access(String name) { super(name); } - - /** @return The {@code name} converted to {@link Access} */ - public static Access - fromString(String name) throws EnumeratorFormatException { - return (Access) Enumerator.fromString(name, Access.class); - } -} diff --git a/src/org/codehaus/janino/ByteArrayClassLoader.java b/src/org/codehaus/janino/ByteArrayClassLoader.java deleted file mode 100644 index c6f3acd6..00000000 --- a/src/org/codehaus/janino/ByteArrayClassLoader.java +++ /dev/null @@ -1,74 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -import java.util.Map; - -/** This {@link ClassLoader} allows for the loading of a set of Java™ classes provided in class file format. */ -@SuppressWarnings({ "rawtypes", "unchecked" }) public -class ByteArrayClassLoader extends ClassLoader { - - /** - * The given {@link Map} of classes must not be modified afterwards. - * - * @param classes String className => byte[] data - */ - public - ByteArrayClassLoader(Map classes) { this.classes = classes; } - - /** @see #ByteArrayClassLoader(Map) */ - public - ByteArrayClassLoader(Map classes, ClassLoader parent) { - super(parent); - this.classes = classes; - } - - /** - * Implements {@link ClassLoader#findClass(String)}. - *

- * Notice that, although nowhere documented, no more than one thread at a time calls this - * method, because {@link ClassLoader#loadClass(java.lang.String)} is - * synchronized. - */ - @Override protected Class - findClass(String name) throws ClassNotFoundException { - byte[] data = (byte[]) this.classes.get(name); - if (data == null) throw new ClassNotFoundException(name); - - // Notice: Not inheriting the protection domain will cause problems with Java Web Start / - // JNLP. See - // http://jira.codehaus.org/browse/JANINO-104 - // http://www.nabble.com/-Help-jel--java.security.AccessControlException-to13073723.html - return super.defineClass( - name, // name - data, 0, data.length, // b, off, len - this.getClass().getProtectionDomain() // protectionDomain - ); - } - - private final Map classes; -} diff --git a/src/org/codehaus/janino/CachingJavaSourceClassLoader.java b/src/org/codehaus/janino/CachingJavaSourceClassLoader.java deleted file mode 100644 index 9e94e307..00000000 --- a/src/org/codehaus/janino/CachingJavaSourceClassLoader.java +++ /dev/null @@ -1,218 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; - -import org.codehaus.janino.util.ClassFile; -import org.codehaus.janino.util.resource.DirectoryResourceCreator; -import org.codehaus.janino.util.resource.DirectoryResourceFinder; -import org.codehaus.janino.util.resource.PathResourceFinder; -import org.codehaus.janino.util.resource.Resource; -import org.codehaus.janino.util.resource.ResourceCreator; -import org.codehaus.janino.util.resource.ResourceFinder; - -/** - * A {@link org.codehaus.janino.JavaSourceClassLoader} that uses a resource storage provided by the application to cache - * compiled classes and thus saving unnecessary recompilations. - *

- * The application provides access to the resource storeage through a pair of a {@link - * org.codehaus.janino.util.resource.ResourceFinder} and a {@link org.codehaus.janino.util.resource.ResourceCreator} - * (see {@link #CachingJavaSourceClassLoader(ClassLoader, ResourceFinder, String, ResourceFinder, ResourceCreator)}. - *

- * See {@link org.codehaus.janino.JavaSourceClassLoader#main(String[])} for an example how to use this class. - *

- * Notice: You must NOT rely on that this class stores some particular data in some particular resources through - * the given {@code classFileCacheResourceFinder/Creator}! These serve only as a means for the {@link - * CachingJavaSourceClassLoader} to persistently cache some data between invocations. In other words: If you want to - * compile {@code .java} files into {@code .class} files, then don't use this class but {@link Compiler} - * instead! - */ -@SuppressWarnings({ "rawtypes", "unchecked" }) public -class CachingJavaSourceClassLoader extends JavaSourceClassLoader { - private final ResourceFinder classFileCacheResourceFinder; - private final ResourceCreator classFileCacheResourceCreator; - private final ResourceFinder sourceFinder; - - /** - * See {@link #CachingJavaSourceClassLoader(ClassLoader, ResourceFinder, String, ResourceFinder, ResourceCreator)}. - * - * @param optionalSourcePath Directories to scan for source files - * @param cacheDirectory Directory to use for caching generated class files (see class description) - */ - public - CachingJavaSourceClassLoader( - ClassLoader parentClassLoader, - File[] optionalSourcePath, - String optionalCharacterEncoding, - File cacheDirectory - ) { - this( - parentClassLoader, // parentClassLoader - ( // sourceFinder - optionalSourcePath == null - ? (ResourceFinder) new DirectoryResourceFinder(new File(".")) - : (ResourceFinder) new PathResourceFinder(optionalSourcePath) - ), - optionalCharacterEncoding, // optionalCharacterEncoding - new DirectoryResourceFinder(cacheDirectory), // classFileCacheResourceFinder - new DirectoryResourceCreator(cacheDirectory) // classFileCacheResourceCreator - ); - } - - /** - * Notice that this class is thread-safe if and only if the {@code classFileCacheResourceCreator} stores its data - * atomically, i.e. the {@code classFileCacheResourceFinder} sees the resource written by the {@code - * classFileCacheResourceCreator} only after the {@link OutputStream} is closed. - *

- * In order to make the caching scheme work, both the {@code classFileCacheResourceFinder} and the {@code - * sourceFinder} must support the {@link org.codehaus.janino.util.resource.Resource#lastModified()} method, so that - * the modification time of the source and the class files can be compared. - * - * @param parentClassLoader Attempt to load classes through this one before looking for source files - * @param sourceFinder Finds Java™ source for class {@code pkg.Cls} in resource {@code - * pkg/Cls.java} - * @param optionalCharacterEncoding Encoding of Java™ source or {@code null} for platform default - * encoding - * @param classFileCacheResourceFinder Finds precompiled class {@code pkg.Cls} in resource {@code pkg/Cls.class} - * (see class description) - * @param classFileCacheResourceCreator Stores compiled class {@code pkg.Cls} in resource {@code pkg/Cls.class} (see - * class description) - */ - public - CachingJavaSourceClassLoader( - ClassLoader parentClassLoader, - ResourceFinder sourceFinder, - String optionalCharacterEncoding, - ResourceFinder classFileCacheResourceFinder, - ResourceCreator classFileCacheResourceCreator - ) { - super(parentClassLoader, sourceFinder, optionalCharacterEncoding); - this.classFileCacheResourceFinder = classFileCacheResourceFinder; - this.classFileCacheResourceCreator = classFileCacheResourceCreator; - this.sourceFinder = sourceFinder; - } - - /** - * Override {@link JavaSourceClassLoader#generateBytecodes(String)} to implement class file caching. - * - * @return String name => byte[] bytecode, or {@code null} if no source code could be found - * @throws ClassNotFoundException Compilation problems or class file cache I/O problems - */ - @Override protected Map - generateBytecodes(String className) throws ClassNotFoundException { - // Check whether a class file resource exists in the cache. - { - Resource classFileResource = this.classFileCacheResourceFinder.findResource( - ClassFile.getClassFileResourceName(className) - ); - if (classFileResource != null) { - - // Check whether a source file resource exists. - Resource sourceResource = this.sourceFinder.findResource(ClassFile.getSourceResourceName(className)); - if (sourceResource == null) return null; - - // Check whether the class file is up-to-date. - if (sourceResource.lastModified() < classFileResource.lastModified()) { - - // Yes, it is... read the bytecode from the file and define the class. - byte[] bytecode; - try { - bytecode = CachingJavaSourceClassLoader.readResource(classFileResource); - } catch (IOException ex) { - throw new ClassNotFoundException("Reading class file from \"" + classFileResource + "\"", ex); - } - Map m = new HashMap(); - m.put(className, bytecode); - return m; - } - } - } - - // Cache miss... generate the bytecode from source. - Map bytecodes = super.generateBytecodes(className); - if (bytecodes == null) return null; - - // Write the generated bytecodes to the class file cache. - for (Map.Entry me : bytecodes.entrySet()) { - String className2 = (String) me.getKey(); - byte[] bytecode = (byte[]) me.getValue(); - - try { - CachingJavaSourceClassLoader.writeResource( - this.classFileCacheResourceCreator, - ClassFile.getClassFileResourceName(className2), - bytecode - ); - } catch (IOException ex) { - throw new ClassNotFoundException( - "Writing class file to \"" + ClassFile.getClassFileResourceName(className2) + "\"", - ex - ); - } - } - - return bytecodes; - } - - /** Reads all bytes from the given resource. */ - private static byte[] - readResource(Resource r) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[4096]; - - InputStream is = r.open(); - try { - for (;;) { - int cnt = is.read(buffer); - if (cnt == -1) break; - baos.write(buffer, 0, cnt); - } - } finally { - try { is.close(); } catch (IOException ex) {} - } - - return baos.toByteArray(); - } - - /** Create a resource with the given name and store the data in it. */ - private static void - writeResource(ResourceCreator resourceCreator, String resourceName, byte[] data) throws IOException { - OutputStream os = resourceCreator.createResource(resourceName); - try { - os.write(data); - } finally { - try { os.close(); } catch (IOException ex) {} - } - } -} diff --git a/src/org/codehaus/janino/ClassBodyEvaluator.java b/src/org/codehaus/janino/ClassBodyEvaluator.java deleted file mode 100644 index 04efc2f2..00000000 --- a/src/org/codehaus/janino/ClassBodyEvaluator.java +++ /dev/null @@ -1,445 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; - -import org.codehaus.commons.compiler.CompileException; -import org.codehaus.commons.compiler.CompilerFactoryFactory; -import org.codehaus.commons.compiler.Cookable; -import org.codehaus.commons.compiler.IClassBodyEvaluator; -import org.codehaus.commons.compiler.ICompilerFactory; -import org.codehaus.commons.compiler.Location; - -/** - * The optionalClassLoader serves two purposes: - *

- * A number of "convenience constructors" exist that execute the setup steps instantly. - */ -@SuppressWarnings("rawtypes") public -class ClassBodyEvaluator extends SimpleCompiler implements IClassBodyEvaluator { - - private static final Class[] ZERO_CLASSES = new Class[0]; - - private String[] optionalDefaultImports; - private String className = IClassBodyEvaluator.DEFAULT_CLASS_NAME; - private Class optionalExtendedType; - private Class[] implementedTypes = ClassBodyEvaluator.ZERO_CLASSES; - private Class result; // null=uncooked - - /** - * Equivalent to
-     * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
-     * cbe.cook(classBody);
- * - * @see #ClassBodyEvaluator() - * @see Cookable#cook(String) - */ - public - ClassBodyEvaluator(String classBody) throws CompileException { this.cook(classBody); } - - /** - * Equivalent to
-     * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
-     * cbe.cook(optionalFileName, is);
- * - * @see #ClassBodyEvaluator() - * @see Cookable#cook(String, InputStream) - */ - public - ClassBodyEvaluator(String optionalFileName, InputStream is) throws CompileException, IOException { - this.cook(optionalFileName, is); - } - - /** - * Equivalent to
-     * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
-     * cbe.cook(optionalFileName, reader);
- * - * @see #ClassBodyEvaluator() - * @see Cookable#cook(String, Reader) - */ - public - ClassBodyEvaluator(String optionalFileName, Reader reader) throws CompileException, IOException { - this.cook(optionalFileName, reader); - } - - /** - * Equivalent to
-     * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
-     * cbe.setParentClassLoader(optionalParentClassLoader);
-     * cbe.cook(scanner);
- * - * @see #ClassBodyEvaluator() - * @see SimpleCompiler#setParentClassLoader(ClassLoader) - * @see Cookable#cook(Reader) - */ - public - ClassBodyEvaluator(Scanner scanner, ClassLoader optionalParentClassLoader) throws CompileException, IOException { - this.setParentClassLoader(optionalParentClassLoader); - this.cook(scanner); - } - - /** - * Equivalent to
-     * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
-     * cbe.setExtendedType(optionalExtendedType);
-     * cbe.setImplementedTypes(implementedTypes);
-     * cbe.setParentClassLoader(optionalParentClassLoader);
-     * cbe.cook(scanner);
- * - * @see #ClassBodyEvaluator() - * @see #setExtendedClass(Class) - * @see #setImplementedInterfaces(Class[]) - * @see SimpleCompiler#setParentClassLoader(ClassLoader) - * @see Cookable#cook(Reader) - */ - public - ClassBodyEvaluator( - Scanner scanner, - Class optionalExtendedType, - Class[] implementedTypes, - ClassLoader optionalParentClassLoader - ) throws CompileException, IOException { - this.setExtendedClass(optionalExtendedType); - this.setImplementedInterfaces(implementedTypes); - this.setParentClassLoader(optionalParentClassLoader); - this.cook(scanner); - } - - /** - * Equivalent to
-     * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
-     * cbe.setClassName(className);
-     * cbe.setExtendedType(optionalExtendedType);
-     * cbe.setImplementedTypes(implementedTypes);
-     * cbe.setParentClassLoader(optionalParentClassLoader);
-     * cbe.cook(scanner);
- * - * @see #ClassBodyEvaluator() - * @see #setClassName(String) - * @see #setExtendedClass(Class) - * @see #setImplementedInterfaces(Class[]) - * @see SimpleCompiler#setParentClassLoader(ClassLoader) - * @see Cookable#cook(Reader) - */ - public - ClassBodyEvaluator( - Scanner scanner, - String className, - Class optionalExtendedType, - Class[] implementedTypes, - ClassLoader optionalParentClassLoader - ) throws CompileException, IOException { - this.setClassName(className); - this.setExtendedClass(optionalExtendedType); - this.setImplementedInterfaces(implementedTypes); - this.setParentClassLoader(optionalParentClassLoader); - this.cook(scanner); - } - - public ClassBodyEvaluator() {} - - @Override public void - setDefaultImports(String[] optionalDefaultImports) { - this.assertNotCooked(); - this.optionalDefaultImports = optionalDefaultImports; - } - - @Override public void - setClassName(String className) { - if (className == null) throw new NullPointerException(); - this.assertNotCooked(); - this.className = className; - } - - @Override public void - setExtendedClass(Class optionalExtendedType) { - this.assertNotCooked(); - this.optionalExtendedType = optionalExtendedType; - } - - /** @deprecated */ - @Deprecated @Override public void - setExtendedType(Class optionalExtendedClass) { - this.setExtendedClass(optionalExtendedClass); - } - - @Override public void - setImplementedInterfaces(Class[] implementedTypes) { - if (implementedTypes == null) { - throw new NullPointerException( - "Zero implemented types must be specified as 'new Class[0]', not 'null'" - ); - } - this.assertNotCooked(); - this.implementedTypes = implementedTypes; - } - - /** @deprecated */ - @Deprecated @Override public void - setImplementedTypes(Class[] implementedInterfaces) { - this.setImplementedInterfaces(implementedInterfaces); - } - - @Override public void - cook(Scanner scanner) throws CompileException, IOException { - - Parser parser = new Parser(scanner); - Java.CompilationUnit compilationUnit = this.makeCompilationUnit(parser); - - // Add class declaration. - Java.ClassDeclaration cd = this.addPackageMemberClassDeclaration(scanner.location(), compilationUnit); - - // Parse class body declarations (member declarations) until EOF. - while (!parser.peekEof()) { - parser.parseClassBodyDeclaration(cd); - } - - // Compile and load it. - this.result = this.compileToClass(compilationUnit); - } - - /** - * Create a {@link Java.CompilationUnit}, set the default imports, and parse the import declarations. - *

- * If the optionalParser is given, a sequence of IMPORT directives is parsed from it and added to the - * compilation unit. - */ - protected final Java.CompilationUnit - makeCompilationUnit(Parser optionalParser) throws CompileException, IOException { - Java.CompilationUnit cu = ( - new Java.CompilationUnit(optionalParser == null - ? null - : optionalParser.getScanner().getFileName()) - ); - - // Set default imports. - if (this.optionalDefaultImports != null) { - for (String defaultImport : this.optionalDefaultImports) { - Scanner s = new Scanner(null, new StringReader(defaultImport)); - Parser parser2 = new Parser(s); - cu.addImportDeclaration(parser2.parseImportDeclarationBody()); - if (!parser2.peekEof()) { - throw new CompileException( - "Unexpected token '" + parser2.peek() + "' in default import", - s.location() - ); - } - } - } - - // Parse all available IMPORT declarations. - if (optionalParser != null) { - while (optionalParser.peek("import")) { - cu.addImportDeclaration(optionalParser.parseImportDeclaration()); - } - } - - return cu; - } - - /** - * To the given {@link Java.CompilationUnit}, add - *

- * - * @return The created {@link Java.ClassDeclaration} object - */ - protected Java.PackageMemberClassDeclaration - addPackageMemberClassDeclaration(Location location, Java.CompilationUnit compilationUnit) throws CompileException { - String cn = this.className; - int idx = cn.lastIndexOf('.'); - if (idx != -1) { - compilationUnit.setPackageDeclaration(new Java.PackageDeclaration(location, cn.substring(0, idx))); - cn = cn.substring(idx + 1); - } - Java.PackageMemberClassDeclaration tlcd = new Java.PackageMemberClassDeclaration( - location, // location - null, // optionalDocComment - new Java.Modifiers(Mod.PUBLIC), // modifiers - cn, // name - null, // optionalTypeParameters - this.classToType(location, this.optionalExtendedType), // optionalExtendedType - this.classesToTypes(location, this.implementedTypes) // implementedTypes - ); - compilationUnit.addPackageMemberTypeDeclaration(tlcd); - return tlcd; - } - - /** - * Compile the given compilation unit, load all generated classes, and return the class with the given name. - * - * @param compilationUnit - * @return The loaded class - */ - protected final Class - compileToClass(Java.CompilationUnit compilationUnit) throws CompileException { - - // Compile and load the compilation unit. - ClassLoader cl = this.compileToClassLoader(compilationUnit); - - // Find the generated class by name. - try { - return cl.loadClass(this.className); - } catch (ClassNotFoundException ex) { - throw new JaninoRuntimeException(( - "SNO: Generated compilation unit does not declare class '" - + this.className - + "'" - ), ex); - } - } - - @Override public Class - getClazz() { - if (this.getClass() != ClassBodyEvaluator.class) { - throw new IllegalStateException("Must not be called on derived instances"); - } - if (this.result == null) throw new IllegalStateException("Must only be called after 'cook()'"); - return this.result; - } - - @Override public Object - createInstance(Reader reader) throws CompileException, IOException { - this.cook(reader); - - try { - return this.getClazz().newInstance(); - } catch (InstantiationException ie) { - CompileException ce = new CompileException(( - "Class is abstract, an interface, an array class, a primitive type, or void; " - + "or has no zero-parameter constructor" - ), null); - ce.initCause(ie); - throw ce; // SUPPRESS CHECKSTYLE AvoidHidingCause - } catch (IllegalAccessException iae) { - CompileException ce = new CompileException( - "The class or its zero-parameter constructor is not accessible", - null - ); - ce.initCause(iae); - throw ce; // SUPPRESS CHECKSTYLE AvoidHidingCause - } - } - - /** - * Use {@link #createInstance(Reader)} instead: - *
-     * IClassBodyEvaluator cbe = {@link CompilerFactoryFactory}.{@link
-     * CompilerFactoryFactory#getDefaultCompilerFactory() getDefaultCompilerFactory}().{@link
-     * ICompilerFactory#newClassBodyEvaluator() newClassBodyEvaluator}();
-     * if (optionalBaseType != null) {
-     *     if (optionalBaseType.isInterface()) {
-     *         cbe.{@link #setImplementedInterfaces setImplementedInterfaces}(new Class[] { optionalBaseType });
-     *     } else {
-     *         cbe.{@link #setExtendedClass(Class) setExtendedClass}(optionalBaseType);
-     *     }
-     * }
-     * cbe.{@link #setParentClassLoader(ClassLoader) setParentClassLoader}(optionalParentClassLoader);
-     * cbe.{@link IClassBodyEvaluator#createInstance(Reader) createInstance}(reader);
-     * 
- * - * @see #createInstance(Reader) - */ - public static Object - createFastClassBodyEvaluator( - Scanner scanner, - Class optionalBaseType, - ClassLoader optionalParentClassLoader - ) throws CompileException, IOException { - return ClassBodyEvaluator.createFastClassBodyEvaluator( - scanner, // scanner - IClassBodyEvaluator.DEFAULT_CLASS_NAME, // className - ( // optionalExtendedType - optionalBaseType != null && !optionalBaseType.isInterface() - ? optionalBaseType - : null - ), - ( // implementedTypes - optionalBaseType != null && optionalBaseType.isInterface() - ? new Class[] { optionalBaseType } - : new Class[0] - ), - optionalParentClassLoader // optionalParentClassLoader - ); - } - - /** - * Use {@link #createInstance(Reader)} instead: - *
-     * IClassBodyEvaluator cbe = {@link CompilerFactoryFactory}.{@link
-     * CompilerFactoryFactory#getDefaultCompilerFactory() getDefaultCompilerFactory}().{@link
-     * ICompilerFactory#newClassBodyEvaluator() newClassBodyEvaluator}();
-     * cbe.{@link #setExtendedClass(Class) setExtendedClass}(optionalExtendedClass);
-     * cbe.{@link #setImplementedInterfaces(Class[]) setImplementedInterfaces}(implementedInterfaces);
-     * cbe.{@link #setParentClassLoader(ClassLoader) setParentClassLoader}(optionalParentClassLoader);
-     * cbe.{@link IClassBodyEvaluator#createInstance(Reader) createInstance}(reader);
-     * 
- * - * @see #createInstance(Reader) - * @deprecated Use {@link #createInstance(Reader)} instead. - */ - @Deprecated public static Object - createFastClassBodyEvaluator( - Scanner scanner, - String className, - Class optionalExtendedClass, - Class[] implementedInterfaces, - ClassLoader optionalParentClassLoader - ) throws CompileException, IOException { - ClassBodyEvaluator cbe = new ClassBodyEvaluator(); - cbe.setClassName(className); - cbe.setExtendedClass(optionalExtendedClass); - cbe.setImplementedInterfaces(implementedInterfaces); - cbe.setParentClassLoader(optionalParentClassLoader); - cbe.cook(scanner); - Class c = cbe.getClazz(); - try { - return c.newInstance(); - } catch (InstantiationException e) { - throw new CompileException( // SUPPRESS CHECKSTYLE AvoidHidingCause - e.getMessage(), - null - ); - } catch (IllegalAccessException e) { - // SNO - type and default constructor of generated class are PUBLIC. - throw new JaninoRuntimeException(e.toString(), e); - } - } -} diff --git a/src/org/codehaus/janino/ClassFileIClass.java b/src/org/codehaus/janino/ClassFileIClass.java deleted file mode 100644 index c00abe37..00000000 --- a/src/org/codehaus/janino/ClassFileIClass.java +++ /dev/null @@ -1,438 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.codehaus.commons.compiler.CompileException; -import org.codehaus.janino.util.ClassFile; -import org.codehaus.janino.util.ClassFile.ConstantClassInfo; - -/** A wrapper object that turns a {@link ClassFile} object into an {@link IClass}. */ -@SuppressWarnings({ "rawtypes", "unchecked" }) public -class ClassFileIClass extends IClass { - private static final boolean DEBUG = false; - - private final ClassFile classFile; - private final IClassLoader iClassLoader; - private final short accessFlags; - - private final Map resolvedFields = new HashMap(); - - /** - * @param classFile Source of data - * @param iClassLoader {@link IClassLoader} through which to load other classes - */ - public - ClassFileIClass(ClassFile classFile, IClassLoader iClassLoader) { - this.classFile = classFile; - this.iClassLoader = iClassLoader; - - // Determine class access flags. - this.accessFlags = classFile.accessFlags; - } - - // Implement IClass. - - @Override protected IConstructor[] - getDeclaredIConstructors2() { - List iConstructors = new ArrayList(); - - for (ClassFile.MethodInfo mi : this.classFile.methodInfos) { - IInvocable ii; - try { - ii = this.resolveMethod(mi); - } catch (ClassNotFoundException ex) { - throw new JaninoRuntimeException(ex.getMessage(), ex); - } - if (ii instanceof IConstructor) iConstructors.add(ii); - } - - return (IConstructor[]) iConstructors.toArray(new IConstructor[iConstructors.size()]); - } - - @Override protected IMethod[] - getDeclaredIMethods2() { - List iMethods = new ArrayList(); - - for (ClassFile.MethodInfo mi : this.classFile.methodInfos) { - - // Skip JDK 1.5 synthetic methods (e.g. those generated for - // covariant return values). - if (Mod.isSynthetic(mi.getModifierFlags())) continue; - - IInvocable ii; - try { - ii = this.resolveMethod(mi); - } catch (ClassNotFoundException ex) { - throw new JaninoRuntimeException(ex.getMessage(), ex); - } - if (ii instanceof IMethod) iMethods.add((IMethod) ii); - } - - return (IMethod[]) iMethods.toArray(new IMethod[iMethods.size()]); - } - - @Override protected IField[] - getDeclaredIFields2() { - IField[] ifs = new IClass.IField[this.classFile.fieldInfos.size()]; - for (int i = 0; i < this.classFile.fieldInfos.size(); ++i) { - try { - ifs[i] = this.resolveField((ClassFile.FieldInfo) this.classFile.fieldInfos.get(i)); - } catch (ClassNotFoundException ex) { - throw new JaninoRuntimeException(ex.getMessage(), ex); - } - } - return ifs; - } - - @Override protected IClass[] - getDeclaredIClasses2() throws CompileException { - ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute(); - if (ica == null) return new IClass[0]; - - List res = new ArrayList(); - for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) { - if (e.outerClassInfoIndex == this.classFile.thisClass) { - try { - res.add(this.resolveClass(e.innerClassInfoIndex)); - } catch (ClassNotFoundException ex) { - throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause - } - } - } - return (IClass[]) res.toArray(new IClass[res.size()]); - } - - @Override protected IClass - getDeclaringIClass2() throws CompileException { - ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute(); - if (ica == null) return null; - - for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) { - if (e.innerClassInfoIndex == this.classFile.thisClass) { - // Is this an anonymous class? - if (e.outerClassInfoIndex == 0) return null; - try { - return this.resolveClass(e.outerClassInfoIndex); - } catch (ClassNotFoundException ex) { - throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause - } - } - } - return null; - } - - @Override protected IClass - getOuterIClass2() throws CompileException { - ClassFile.InnerClassesAttribute ica = this.classFile.getInnerClassesAttribute(); - if (ica == null) return null; - - for (ClassFile.InnerClassesAttribute.Entry e : ica.getEntries()) { - if (e.innerClassInfoIndex == this.classFile.thisClass) { - if (e.outerClassInfoIndex == 0) { - - // Anonymous class or local class. - // TODO: Determine enclosing instance of anonymous class or local class - return null; - } else { - - // Member type. - if (Mod.isStatic(e.innerClassAccessFlags)) return null; - try { - return this.resolveClass(e.outerClassInfoIndex); - } catch (ClassNotFoundException ex) { - throw new CompileException(ex.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause - } - } - } - } - return null; - } - - @Override protected IClass - getSuperclass2() throws CompileException { - if (this.classFile.superclass == 0) return null; - try { - return this.resolveClass(this.classFile.superclass); - } catch (ClassNotFoundException e) { - throw new CompileException(e.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause - } - } - - @Override public Access - getAccess() { return ClassFileIClass.accessFlags2Access(this.accessFlags); } - - @Override public boolean - isFinal() { return Mod.isFinal(this.accessFlags); } - - @Override protected IClass[] - getInterfaces2() throws CompileException { return this.resolveClasses(this.classFile.interfaces); } - - @Override public boolean - isAbstract() { return Mod.isAbstract(this.accessFlags); } - - @Override protected String - getDescriptor2() { return Descriptor.fromClassName(this.classFile.getThisClassName()); } - - @Override public boolean - isInterface() { return Mod.isInterface(this.accessFlags); } - - @Override public boolean - isArray() { return false; } - - @Override public boolean - isPrimitive() { return false; } - - @Override public boolean - isPrimitiveNumeric() { return false; } - - @Override protected IClass - getComponentType2() { return null; } - - /** Resolves all classes referenced by this class file. */ - public void - resolveAllClasses() throws ClassNotFoundException { - for (short i = 0; i < this.classFile.getConstantPoolSize(); ++i) { - ClassFile.ConstantPoolInfo cpi = this.classFile.getConstantPoolInfo(i); - if (cpi instanceof ClassFile.ConstantClassInfo) { - this.resolveClass(i); - } else - if (cpi instanceof ClassFile.ConstantNameAndTypeInfo) { - String descriptor = ((ClassFile.ConstantNameAndTypeInfo) cpi).getDescriptor(this.classFile); - if (descriptor.charAt(0) == '(') { - MethodDescriptor md = new MethodDescriptor(descriptor); - this.resolveClass(md.returnFd); - for (String parameterFd : md.parameterFds) this.resolveClass(parameterFd); - } else { - this.resolveClass(descriptor); - } - } - } - } - - /** @param index Index of the CONSTANT_Class_info to resolve (JVMS 4.4.1) */ - private IClass - resolveClass(short index) throws ClassNotFoundException { - if (ClassFileIClass.DEBUG) System.out.println("index=" + index); - ConstantClassInfo cci = (ConstantClassInfo) this.classFile.getConstantPoolInfo(index); - return this.resolveClass(Descriptor.fromInternalForm(cci.getName(this.classFile))); - } - - private IClass - resolveClass(String descriptor) throws ClassNotFoundException { - if (ClassFileIClass.DEBUG) System.out.println("descriptor=" + descriptor); - - IClass result = (IClass) this.resolvedClasses.get(descriptor); - if (result != null) return result; - - result = this.iClassLoader.loadIClass(descriptor); - if (result == null) throw new ClassNotFoundException(descriptor); - - this.resolvedClasses.put(descriptor, result); - return result; - } - private final Map resolvedClasses = new HashMap(); - - private IClass[] - resolveClasses(short[] ifs) throws CompileException { - IClass[] result = new IClass[ifs.length]; - for (int i = 0; i < result.length; ++i) { - try { - result[i] = this.resolveClass(ifs[i]); - } catch (ClassNotFoundException e) { - throw new CompileException(e.getMessage(), null); // SUPPRESS CHECKSTYLE AvoidHidingCause - } - } - return result; - } - - /** - * Turn a {@link ClassFile.MethodInfo} into an {@link IInvocable}. This includes the checking and the - * removal of the magic first parameter of an inner class constructor. - * - * @param methodInfo - * @throws ClassNotFoundException - */ - private IInvocable - resolveMethod(final ClassFile.MethodInfo methodInfo) throws ClassNotFoundException { - IInvocable result = (IInvocable) this.resolvedMethods.get(methodInfo); - if (result != null) return result; - - // Determine method name. - final String name = methodInfo.getName(); - - // Determine return type. - MethodDescriptor md = new MethodDescriptor(methodInfo.getDescriptor()); - - final IClass returnType = this.resolveClass(md.returnFd); - - // Determine parameter types. - final IClass[] parameterTypes = new IClass[md.parameterFds.length]; - for (int i = 0; i < parameterTypes.length; ++i) parameterTypes[i] = this.resolveClass(md.parameterFds[i]); - - // Determine thrown exceptions. - IClass[] tes = null; - ClassFile.AttributeInfo[] ais = methodInfo.getAttributes(); - for (ClassFile.AttributeInfo ai : ais) { - if (ai instanceof ClassFile.ExceptionsAttribute) { - ConstantClassInfo[] ccis = ((ClassFile.ExceptionsAttribute) ai).getExceptions(this.classFile); - tes = new IClass[ccis.length]; - for (int i = 0; i < tes.length; ++i) { - tes[i] = this.resolveClass(Descriptor.fromInternalForm(ccis[i].getName(this.classFile))); - } - } - } - final IClass[] thrownExceptions = tes == null ? new IClass[0] : tes; - - // Determine access. - final Access access = ClassFileIClass.accessFlags2Access(methodInfo.getModifierFlags()); - - if ("".equals(name)) { - result = new IClass.IConstructor() { - - @Override public boolean - isVarargs() { return Mod.isVarargs(methodInfo.getModifierFlags()); } - - @Override public IClass[] - getParameterTypes2() throws CompileException { - - // Process magic first parameter of inner class constructor. - IClass outerIClass = ClassFileIClass.this.getOuterIClass(); - if (outerIClass != null) { - if (parameterTypes.length < 1) { - throw new JaninoRuntimeException("Inner class constructor lacks magic first parameter"); - } - if (parameterTypes[0] != outerIClass) { - throw new JaninoRuntimeException( - "Magic first parameter of inner class constructor has type \"" - + parameterTypes[0].toString() - + "\" instead of that of its enclosing instance (\"" - + outerIClass.toString() - + "\")" - ); - } - IClass[] tmp = new IClass[parameterTypes.length - 1]; - System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length); - return tmp; - } - - return parameterTypes; - } - - @Override public IClass[] getThrownExceptions2() { return thrownExceptions; } - @Override public Access getAccess() { return access; } - @Override public Java.Annotation[] getAnnotations() { return methodInfo.getAnnotations(); } - }; - } else { - result = new IClass.IMethod() { - - @Override public String - getName() { return name; } - - @Override public IClass - getReturnType() { return returnType; } - - @Override public boolean - isStatic() { return Mod.isStatic(methodInfo.getModifierFlags()); } - - @Override public boolean - isAbstract() { return Mod.isAbstract(methodInfo.getModifierFlags()); } - - @Override public boolean - isVarargs() { return Mod.isVarargs(methodInfo.getModifierFlags()); } - - @Override public IClass[] - getParameterTypes2() { return parameterTypes; } - - @Override public IClass[] - getThrownExceptions2() { return thrownExceptions; } - - @Override public Access - getAccess() { return access; } - - @Override public Java.Annotation[] - getAnnotations() { return methodInfo.getAnnotations(); } - }; - } - this.resolvedMethods.put(methodInfo, result); - return result; - } - private final Map resolvedMethods = new HashMap(); - - private IField - resolveField(final ClassFile.FieldInfo fieldInfo) throws ClassNotFoundException { - IField result = (IField) this.resolvedFields.get(fieldInfo); - if (result != null) return result; - - // Determine field name. - final String name = fieldInfo.getName(this.classFile); - - // Determine field type. - final String descriptor = fieldInfo.getDescriptor(this.classFile); - final IClass type = this.resolveClass(descriptor); - - // Determine optional "constant value" of the field (JLS7 15.28, bullet 14). If a field has a "ConstantValue" - // attribute, we assume that it has a constant value. Notice that this assumption is not always correct, - // because typical Java™ compilers do not generate a "ConstantValue" attribute for fields like - // "int RED = 0", because "0" is the default value for an integer field. - ClassFile.ConstantValueAttribute cva = null; - for (ClassFile.AttributeInfo ai : fieldInfo.getAttributes()) { - if (ai instanceof ClassFile.ConstantValueAttribute) { - cva = (ClassFile.ConstantValueAttribute) ai; - break; - } - } - - final Object optionalConstantValue = cva == null ? IClass.NOT_CONSTANT : cva.getConstantValue(this.classFile); - final Access access = ClassFileIClass.accessFlags2Access(fieldInfo.getModifierFlags()); - - result = new IField() { - @Override public Object getConstantValue() { return optionalConstantValue; } - @Override public String getName() { return name; } - @Override public IClass getType() { return type; } - @Override public boolean isStatic() { return Mod.isStatic(fieldInfo.getModifierFlags()); } - @Override public Access getAccess() { return access; } - @Override public Java.Annotation[] getAnnotations() { return fieldInfo.getAnnotations(); } - }; - this.resolvedFields.put(fieldInfo, result); - return result; - } - - private static Access - accessFlags2Access(short accessFlags) { - return ( - Mod.isPublicAccess(accessFlags) ? Access.PUBLIC - : Mod.isProtectedAccess(accessFlags) ? Access.PROTECTED - : Mod.isPrivateAccess(accessFlags) ? Access.PRIVATE - : Access.DEFAULT - ); - } -} diff --git a/src/org/codehaus/janino/ClassLoaderIClassLoader.java b/src/org/codehaus/janino/ClassLoaderIClassLoader.java deleted file mode 100644 index 225278c6..00000000 --- a/src/org/codehaus/janino/ClassLoaderIClassLoader.java +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -/** An {@link IClassLoader} that loads {@link IClass}es through a reflection {@link ClassLoader}. */ -@SuppressWarnings("rawtypes") public -class ClassLoaderIClassLoader extends IClassLoader { - private static final boolean DEBUG = false; - - /** @param classLoader The delegate that loads the classes. */ - public - ClassLoaderIClassLoader(ClassLoader classLoader) { - super( - null // optionalParentIClassLoader - ); - - if (classLoader == null) throw new NullPointerException(); - - this.classLoader = classLoader; - super.postConstruct(); - } - - /** - * Equivalent to - *
-     *   ClassLoaderIClassLoader(Thread.currentThread().getContextClassLoader())
-     * 
- */ - public - ClassLoaderIClassLoader() { this(Thread.currentThread().getContextClassLoader()); } - - /** @return The delegate {@link ClassLoader} */ - public ClassLoader - getClassLoader() { return this.classLoader; } - - @Override protected IClass - findIClass(String descriptor) throws ClassNotFoundException { - - Class clazz; - try { - - // - // See also [ 931385 ] Janino 2.0 throwing exception on arrays of java.io.File: - // - // "ClassLoader.loadClass()" and "Class.forName()" should be identical, - // but "ClassLoader.loadClass("[Ljava.lang.Object;")" throws a - // ClassNotFoundException under JDK 1.5.0 beta. - // Unclear whether this a beta version bug and SUN will fix this in the final - // release, but "Class.forName()" seems to work fine in all cases, so we - // use that. - // - -// clazz = this.classLoader.loadClass(Descriptor.toClassName(descriptor)); - clazz = Class.forName(Descriptor.toClassName(descriptor), false, this.classLoader); - } catch (ClassNotFoundException e) { - if (e.getException() == null) { - return null; - } else - { - throw e; - } - } - if (ClassLoaderIClassLoader.DEBUG) System.out.println("clazz = " + clazz); - - IClass result = new ReflectionIClass(clazz, this); - this.defineIClass(result); - return result; - } - - private final ClassLoader classLoader; -} diff --git a/src/org/codehaus/janino/CodeContext.java b/src/org/codehaus/janino/CodeContext.java deleted file mode 100644 index 0016b478..00000000 --- a/src/org/codehaus/janino/CodeContext.java +++ /dev/null @@ -1,1371 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.codehaus.janino.util.ClassFile; - -/** - * The context of the compilation of a function (constructor or method). Manages generation of - * byte code, the exception table, generation of line number tables, allocation of local variables, - * determining of stack size and local variable table size and flow analysis. - */ -@SuppressWarnings({ "rawtypes", "unchecked" }) public -class CodeContext { - private static final boolean DEBUG = false; - - private static final int INITIAL_SIZE = 128; - private static final byte UNEXAMINED = -1; - private static final byte INVALID_OFFSET = -2; - private static final int MAX_STACK_SIZE = 254; - - private final ClassFile classFile; - private final String functionName; - - private short maxStack; - private short maxLocals; - private byte[] code; - private final Offset beginning; - private final Inserter end; - private Inserter currentInserter; - private final List exceptionTableEntries; - - /** All the local variables that are allocated in any block in this {@link CodeContext}. */ - private final List allLocalVars = new ArrayList(); - - /** - * List of List of Java.LocalVariableSlot objects. Each List of Java.LocalVariableSlot is - * the local variables allocated for a block. They are pushed and poped onto the list together - * to make allocation of the next local variable slot easy. - */ - private final List> scopedVars = new ArrayList(); - - private short nextLocalVariableSlot; - private final List relocatables = new ArrayList(); - - /** Creates an empty "Code" attribute. */ - public - CodeContext(ClassFile classFile, String functionName) { - this.classFile = classFile; - this.functionName = functionName; - - this.maxStack = 0; - this.maxLocals = 0; - this.code = new byte[CodeContext.INITIAL_SIZE]; - this.beginning = new Offset(); - this.end = new Inserter(); - this.currentInserter = this.end; - this.exceptionTableEntries = new ArrayList(); - - this.beginning.offset = 0; - this.end.offset = 0; - this.beginning.next = this.end; - this.end.prev = this.beginning; - } - - /** The {@link ClassFile} this context is related to. */ - public ClassFile - getClassFile() { return this.classFile; } - - - /** - * Allocate space for a local variable of the given size (1 or 2) - * on the local variable array. - * - * As a side effect, the "max_locals" field of the "Code" attribute - * is updated. - * - * The only way to deallocate local variables is to - * {@link #saveLocalVariables()} and later {@link - * #restoreLocalVariables()}. - * - * @param size The number of slots to allocate (1 or 2) - * @return The slot index of the allocated variable - */ - public short - allocateLocalVariable(short size) { return this.allocateLocalVariable(size, null, null).getSlotIndex(); } - - /** - * Allocate space for a local variable of the given size (1 or 2) - * on the local variable array. - * - * As a side effect, the "max_locals" field of the "Code" attribute - * is updated. - * - * The only way to deallocate local variables is to - * {@link #saveLocalVariables()} and later {@link - * #restoreLocalVariables()}. - * @param size Number of slots to use (1 or 2) - * @param name The variable name, if it's null, the variable won't be written to the localvariabletable - * @param type The variable type. if the name isn't null, the type is needed to write to the localvariabletable - */ - public Java.LocalVariableSlot - allocateLocalVariable(short size, String name, IClass type) { - List currentVars = null; - - if (this.scopedVars.size() == 0) { - throw new Error("saveLocalVariables must be called first"); - } else { - currentVars = (List) this.scopedVars.get(this.scopedVars.size() - 1); - } - - Java.LocalVariableSlot slot = new Java.LocalVariableSlot(name, this.nextLocalVariableSlot, type); - - if (slot.getName() != null) { - slot.setStart(this.newOffset()); - } - - this.nextLocalVariableSlot += size; - currentVars.add(slot); - this.allLocalVars.add(slot); - - if (this.nextLocalVariableSlot > this.maxLocals) { - this.maxLocals = this.nextLocalVariableSlot; - } - - return slot; - } - - /** Remembers the current size of the local variables array. */ - public List - saveLocalVariables() { - - // Push empty list on the stack to hold a new block's local vars. - List l = new ArrayList(); - this.scopedVars.add(l); - - return l; - } - - /** - * Restore the previous size of the local variables array. This MUST to be called for every call - * to saveLocalVariables as it closes the variable extent for all the active local variables in - * the current block. - */ - public void - restoreLocalVariables() { - - // Pop the list containing the current block's local vars. - List slots = ( - (List) this.scopedVars.remove(this.scopedVars.size() - 1) - ); - for (Java.LocalVariableSlot slot : slots) { - if (slot.getName() != null) { - slot.setEnd(this.newOffset()); - } - } - } - - /** - * - * @param dos - * @param lineNumberTableAttributeNameIndex 0 == don't generate a "LineNumberTable" attribute - * @throws IOException - */ - protected void - storeCodeAttributeBody( - DataOutputStream dos, - short lineNumberTableAttributeNameIndex, - short localVariableTableAttributeNameIndex - ) throws IOException { - dos.writeShort(this.maxStack); // max_stack - dos.writeShort(this.maxLocals); // max_locals - dos.writeInt(this.end.offset); // code_length - dos.write(this.code, 0, this.end.offset); // code - dos.writeShort(this.exceptionTableEntries.size()); // exception_table_length - for (ExceptionTableEntry exceptionTableEntry : this.exceptionTableEntries) { // exception_table - dos.writeShort(exceptionTableEntry.startPC.offset); - dos.writeShort(exceptionTableEntry.endPC.offset); - dos.writeShort(exceptionTableEntry.handlerPC.offset); - dos.writeShort(exceptionTableEntry.catchType); - } - - List attributes = new ArrayList(); - - // Add "LineNumberTable" attribute. - if (lineNumberTableAttributeNameIndex != 0) { - List lnt = new ArrayList(); - for (Offset o = this.beginning; o != null; o = o.next) { - if (o instanceof LineNumberOffset) { - lnt.add(new ClassFile.LineNumberTableAttribute.Entry(o.offset, ((LineNumberOffset) o).lineNumber)); - } - } - ClassFile.LineNumberTableAttribute.Entry[] lnte = (ClassFile.LineNumberTableAttribute.Entry[]) lnt.toArray( - new ClassFile.LineNumberTableAttribute.Entry[lnt.size()] - ); - attributes.add(new ClassFile.LineNumberTableAttribute( - lineNumberTableAttributeNameIndex, // attributeNameIndex - lnte // lineNumberTableEntries - )); - } - - // Add "LocalVariableTable" attribute. - if (localVariableTableAttributeNameIndex != 0) { - ClassFile.AttributeInfo ai = this.storeLocalVariableTable(dos, localVariableTableAttributeNameIndex); - - if (ai != null) attributes.add(ai); - } - - dos.writeShort(attributes.size()); // attributes_count - for (ClassFile.AttributeInfo attribute : attributes) { // attributes; - attribute.store(dos); - } - } - - /** - * @return A {@link org.codehaus.janino.util.ClassFile.LocalVariableTableAttribute} for this {@link CodeContext} - */ - protected ClassFile.AttributeInfo - storeLocalVariableTable(DataOutputStream dos, short localVariableTableAttributeNameIndex) { - ClassFile cf = this.getClassFile(); - final List entryList = new ArrayList(); - - for (Java.LocalVariableSlot slot : this.getAllLocalVars()) { - - if (slot.getName() != null) { - String typeName = slot.getType().getDescriptor(); - short classSlot = cf.addConstantUtf8Info(typeName); - short varNameSlot = cf.addConstantUtf8Info(slot.getName()); - -// System.out.println("slot: " + slot + ", typeSlot: " + classSlot + ", varSlot: " + varNameSlot); - - ClassFile.LocalVariableTableAttribute.Entry entry = new ClassFile.LocalVariableTableAttribute.Entry( - (short) slot.getStart().offset, - (short) (slot.getEnd().offset - slot.getStart().offset), - varNameSlot, - classSlot, - slot.getSlotIndex() - ); - entryList.add(entry); - } - } - - if (entryList.size() > 0) { - Object entries = entryList.toArray(new ClassFile.LocalVariableTableAttribute.Entry[entryList.size()]); - - return new ClassFile.LocalVariableTableAttribute( - localVariableTableAttributeNameIndex, - (ClassFile.LocalVariableTableAttribute.Entry[]) entries - ); - } else { - return null; - } - } - - /** - * Checks the code for consistency; updates the "maxStack" member. - * - * Notice: On inconsistencies, a "RuntimeException" is thrown (KLUDGE). - */ - public void - flowAnalysis(String functionName) { - if (CodeContext.DEBUG) { - System.err.println("flowAnalysis(" + functionName + ")"); - } - - short[] stackSizes = new short[this.end.offset]; - Arrays.fill(stackSizes, CodeContext.UNEXAMINED); - - // Analyze flow from offset zero. - this.flowAnalysis( - functionName, - this.code, // code - this.end.offset, // codeSize - 0, // offset - (short) 0, // stackSize - stackSizes // stackSizes - ); - - // Analyze flow from exception handler entry points. - int analyzedExceptionHandlers = 0; - while (analyzedExceptionHandlers != this.exceptionTableEntries.size()) { - for (ExceptionTableEntry exceptionTableEntry : this.exceptionTableEntries) { - if (stackSizes[exceptionTableEntry.startPC.offset] != CodeContext.UNEXAMINED) { - this.flowAnalysis( - functionName, - this.code, // code - this.end.offset, // codeSize - exceptionTableEntry.handlerPC.offset, // offset - (short) (stackSizes[exceptionTableEntry.startPC.offset] + 1), // stackSize - stackSizes // stackSizes - ); - ++analyzedExceptionHandlers; - } - } - } - - // Check results and determine maximum stack size. - this.maxStack = 0; - for (int i = 0; i < stackSizes.length; ++i) { - short ss = stackSizes[i]; - if (ss == CodeContext.UNEXAMINED) { - if (CodeContext.DEBUG) { - System.out.println(functionName + ": Unexamined code at offset " + i); - return; - } else { - throw new JaninoRuntimeException(functionName + ": Unexamined code at offset " + i); - } - } - if (ss > this.maxStack) this.maxStack = ss; - } - } - - private void - flowAnalysis( - String functionName, - byte[] code, // Bytecode - int codeSize, // Size - int offset, // Current PC - short stackSize, // Stack size on entry - short[] stackSizes // Stack sizes in code - ) { - for (;;) { - if (CodeContext.DEBUG) System.out.println("Offset = " + offset + ", stack size = " + stackSize); - - // Check current bytecode offset. - if (offset < 0 || offset >= codeSize) { - throw new JaninoRuntimeException(functionName + ": Offset out of range"); - } - - // Have we hit an area that has already been analyzed? - int css = stackSizes[offset]; - if (css == stackSize) return; // OK. - if (css == CodeContext.INVALID_OFFSET) throw new JaninoRuntimeException(functionName + ": Invalid offset"); - if (css != CodeContext.UNEXAMINED) { - if (CodeContext.DEBUG) { - System.err.println( - functionName - + ": Operand stack inconsistent at offset " - + offset - + ": Previous size " - + css - + ", now " - + stackSize - ); - return; - } else { - throw new JaninoRuntimeException( - functionName - + ": Operand stack inconsistent at offset " - + offset - + ": Previous size " - + css - + ", now " - + stackSize - ); - } - } - stackSizes[offset] = stackSize; - - // Analyze current opcode. - byte opcode = code[offset]; - int operandOffset = offset + 1; - short props; - if (opcode == Opcode.WIDE) { - opcode = code[operandOffset++]; - props = Opcode.WIDE_OPCODE_PROPERTIES[0xff & opcode]; - } else { - props = Opcode.OPCODE_PROPERTIES[0xff & opcode]; - } - if (props == Opcode.INVALID_OPCODE) { - throw new JaninoRuntimeException( - functionName - + ": Invalid opcode " - + (0xff & opcode) - + " at offset " - + offset - ); - } - - switch (props & Opcode.SD_MASK) { - - case Opcode.SD_M4: - case Opcode.SD_M3: - case Opcode.SD_M2: - case Opcode.SD_M1: - case Opcode.SD_P0: - case Opcode.SD_P1: - case Opcode.SD_P2: - stackSize += (props & Opcode.SD_MASK) - Opcode.SD_P0; - break; - - case Opcode.SD_0: - stackSize = 0; - break; - - case Opcode.SD_GETFIELD: - --stackSize; - /* FALL THROUGH */ - case Opcode.SD_GETSTATIC: - stackSize += this.determineFieldSize((short) ( - CodeContext.extract16BitValue(0, operandOffset, code) - )); - break; - - case Opcode.SD_PUTFIELD: - --stackSize; - /* FALL THROUGH */ - case Opcode.SD_PUTSTATIC: - stackSize -= this.determineFieldSize((short) ( - CodeContext.extract16BitValue(0, operandOffset, code) - )); - break; - - case Opcode.SD_INVOKEVIRTUAL: - case Opcode.SD_INVOKESPECIAL: - case Opcode.SD_INVOKEINTERFACE: - --stackSize; - /* FALL THROUGH */ - case Opcode.SD_INVOKESTATIC: - stackSize -= this.determineArgumentsSize((short) ( - CodeContext.extract16BitValue(0, operandOffset, code) - )); - break; - - case Opcode.SD_MULTIANEWARRAY: - stackSize -= code[operandOffset + 2] - 1; - break; - - default: - throw new JaninoRuntimeException(functionName + ": Invalid stack delta"); - } - - if (stackSize < 0) { - String msg = ( - this.classFile.getThisClassName() - + '.' - + functionName - + ": Operand stack underrun at offset " - + offset - ); - if (CodeContext.DEBUG) { - System.err.println(msg); - return; - } else { - throw new JaninoRuntimeException(msg); - } - } - - if (stackSize > CodeContext.MAX_STACK_SIZE) { - String msg = ( - this.classFile.getThisClassName() - + '.' - + functionName - + ": Operand stack overflow at offset " - + offset - ); - if (CodeContext.DEBUG) { - System.err.println(msg); - return; - } else { - throw new JaninoRuntimeException(msg); - } - } - - switch (props & Opcode.OP1_MASK) { - - case 0: - ; - break; - - case Opcode.OP1_SB: - case Opcode.OP1_UB: - case Opcode.OP1_CP1: - case Opcode.OP1_LV1: - ++operandOffset; - break; - - case Opcode.OP1_SS: - case Opcode.OP1_CP2: - case Opcode.OP1_LV2: - operandOffset += 2; - break; - - case Opcode.OP1_BO2: - if (CodeContext.DEBUG) { - System.out.println("Offset = " + offset); - System.out.println("Operand offset = " + operandOffset); - System.out.println(code[operandOffset]); - System.out.println(code[operandOffset + 1]); - } - this.flowAnalysis( - functionName, - code, codeSize, - CodeContext.extract16BitValue(offset, operandOffset, code), - stackSize, - stackSizes - ); - operandOffset += 2; - break; - - case Opcode.OP1_JSR: - if (CodeContext.DEBUG) { - System.out.println("Offset = " + offset); - System.out.println("Operand offset = " + operandOffset); - System.out.println(code[operandOffset]); - System.out.println(code[operandOffset + 1]); - } - int targetOffset = CodeContext.extract16BitValue(offset, operandOffset, code); - operandOffset += 2; - if (stackSizes[targetOffset] == CodeContext.UNEXAMINED) { - this.flowAnalysis( - functionName, - code, codeSize, - targetOffset, - (short) (stackSize + 1), - stackSizes - ); - } - break; - - case Opcode.OP1_BO4: - this.flowAnalysis( - functionName, - code, codeSize, - CodeContext.extract32BitValue(offset, operandOffset, code), - stackSize, stackSizes - ); - operandOffset += 4; - break; - - case Opcode.OP1_LOOKUPSWITCH: - while ((operandOffset & 3) != 0) ++operandOffset; - this.flowAnalysis( - functionName, - code, codeSize, - CodeContext.extract32BitValue(offset, operandOffset, code), - stackSize, stackSizes - ); - operandOffset += 4; - - int npairs = CodeContext.extract32BitValue(0, operandOffset, code); - operandOffset += 4; - - for (int i = 0; i < npairs; ++i) { - operandOffset += 4; //skip match value - this.flowAnalysis( - functionName, - code, codeSize, - CodeContext.extract32BitValue(offset, operandOffset, code), - stackSize, stackSizes - ); - operandOffset += 4; //advance over offset - } - break; - - case Opcode.OP1_TABLESWITCH: - while ((operandOffset & 3) != 0) ++operandOffset; - this.flowAnalysis( - functionName, - code, codeSize, - CodeContext.extract32BitValue(offset, operandOffset, code), - stackSize, stackSizes - ); - operandOffset += 4; - int low = CodeContext.extract32BitValue(offset, operandOffset, code); - operandOffset += 4; - int hi = CodeContext.extract32BitValue(offset, operandOffset, code); - operandOffset += 4; - for (int i = low; i <= hi; ++i) { - this.flowAnalysis( - functionName, - code, codeSize, - CodeContext.extract32BitValue(offset, operandOffset, code), - stackSize, stackSizes - ); - operandOffset += 4; - } - break; - - default: - throw new JaninoRuntimeException(functionName + ": Invalid OP1"); - } - - switch (props & Opcode.OP2_MASK) { - - case 0: - ; - break; - - case Opcode.OP2_SB: - ++operandOffset; - break; - - case Opcode.OP2_SS: - operandOffset += 2; - break; - - default: - throw new JaninoRuntimeException(functionName + ": Invalid OP2"); - } - - switch (props & Opcode.OP3_MASK) { - - case 0: - ; - break; - - case Opcode.OP3_SB: - ++operandOffset; - break; - - default: - throw new JaninoRuntimeException(functionName + ": Invalid OP3"); - } - - Arrays.fill(stackSizes, offset + 1, operandOffset, CodeContext.INVALID_OFFSET); - - if ((props & Opcode.NO_FALLTHROUGH) != 0) return; - offset = operandOffset; - } - } - - /** - * Extract a 16 bit value at offset in code and add bias to it - * - * @param bias An int to skew the final result by (useful for calculating relative offsets) - * @param offset The position in the code array to extract the bytes from - * @param code The array of bytes - * @return An integer that treats the two bytes at position offset as an UNSIGNED SHORT - */ - private static int - extract16BitValue(int bias, int offset, byte[] code) { - int res = bias + ( - ((code[offset]) << 8) - + (code[offset + 1] & 0xff) - ); - if (CodeContext.DEBUG) { - System.out.println("extract16BitValue(bias, offset) = (" + bias + ", " + offset + ")"); - System.out.println("bytes = {" + code[offset] + ", " + code[offset + 1] + "}"); - System.out.println("result = " + res); - } - return res; - } - - /** - * Extract a 32 bit value at offset in code and add bias to it - * - * @param bias An int to skew the final result by (useful for calculating relative offsets) - * @param offset The position in the code array to extract the bytes from - * @param code The array of bytes - * @return The 4 bytes at position offset + bias - */ - private static int - extract32BitValue(int bias, int offset, byte[] code) { - int res = bias + ( - (code[offset] << 24) - + ((0xff & code[offset + 1]) << 16) - + ((0xff & code[offset + 2]) << 8) - + (0xff & code[offset + 3]) - ); - if (CodeContext.DEBUG) { - System.out.println("extract32BitValue(bias, offset) = (" + bias + ", " + offset + ")"); - System.out.println( - "" - + "bytes = {" - + code[offset] - + ", " - + code[offset + 1] - + ", " - + code[offset + 2] - + ", " - + code[offset + 3] - + "}" - ); - System.out.println("result = " + res); - } - return res; - } - - /** Fixes up all of the offsets and relocate() all relocatables. */ - public void - fixUpAndRelocate() { - - // We do this in a loop to allow relocatables to adjust the size - // of things in the byte stream. It is extremely unlikely, but possible - // that a late relocatable will grow the size of the bytecode, and require - // an earlier relocatable to switch from 32K mode to 64K mode branching - do { - this.fixUp(); - } while (!this.relocate()); - } - - /** Fixes up all offsets. */ - private void - fixUp() { - for (Offset o = this.beginning; o != this.end; o = o.next) { - if (o instanceof FixUp) ((FixUp) o).fixUp(); - } - } - - /** - * Relocate all relocatables and aggregate their response into a single one - * @return true if all of them relocated successfully - * false if any of them needed to change size - */ - private boolean - relocate() { - boolean finished = true; - for (Relocatable relocatable : this.relocatables) { - - // Do not terminate earlier so that everything gets a chance to grow in the first pass changes the common - // case for this to be O(n) instead of O(n**2). - finished &= relocatable.relocate(); - } - return finished; - } - - /** Analyses the descriptor of the Fieldref and return its size. */ - private int - determineFieldSize(short idx) { - ClassFile.ConstantFieldrefInfo cfi = ( - (ClassFile.ConstantFieldrefInfo) this.classFile.getConstantPoolInfo(idx) - ); - return Descriptor.size(cfi.getNameAndType(this.classFile).getDescriptor(this.classFile)); - } - - /** - * Analyse the descriptor of the Methodref and return the sum of the - * arguments' sizes minus the return value's size. - */ - private int - determineArgumentsSize(short idx) { - ClassFile.ConstantPoolInfo cpi = this.classFile.getConstantPoolInfo(idx); - ClassFile.ConstantNameAndTypeInfo nat = ( - cpi instanceof ClassFile.ConstantInterfaceMethodrefInfo - ? ((ClassFile.ConstantInterfaceMethodrefInfo) cpi).getNameAndType(this.classFile) - : ((ClassFile.ConstantMethodrefInfo) cpi).getNameAndType(this.classFile) - ); - String desc = nat.getDescriptor(this.classFile); - - if (desc.charAt(0) != '(') throw new JaninoRuntimeException("Method descriptor does not start with \"(\""); - int i = 1; - int res = 0; - for (;;) { - switch (desc.charAt(i++)) { - case ')': - return res - Descriptor.size(desc.substring(i)); - case 'B': case 'C': case 'F': case 'I': case 'S': case 'Z': - res += 1; - break; - case 'D': case 'J': - res += 2; - break; - case '[': - res += 1; - while (desc.charAt(i) == '[') ++i; - if ("BCFISZDJ".indexOf(desc.charAt(i)) != -1) { ++i; break; } - if (desc.charAt(i) != 'L') throw new JaninoRuntimeException("Invalid char after \"[\""); - ++i; - while (desc.charAt(i++) != ';'); - break; - case 'L': - res += 1; - while (desc.charAt(i++) != ';'); - break; - default: - throw new JaninoRuntimeException("Invalid method descriptor"); - } - } - } - - /** - * Inserts a sequence of bytes at the current insertion position. Creates - * {@link LineNumberOffset}s as necessary. - * - * @param lineNumber The line number that corresponds to the byte code, or -1 - * @param b - */ - public void - write(short lineNumber, byte[] b) { - if (b.length == 0) return; - - int ico = this.currentInserter.offset; - this.makeSpace(lineNumber, b.length); - System.arraycopy(b, 0, this.code, ico, b.length); - } - - /** - * Inserts a byte at the current insertion position. Creates - * {@link LineNumberOffset}s as necessary. - *

- * This method is an optimization to avoid allocating small byte[] and ease - * GC load. - * - * @param lineNumber The line number that corresponds to the byte code, or -1 - * @param b1 - */ - public void - write(short lineNumber, byte b1) { - int ico = this.currentInserter.offset; - this.makeSpace(lineNumber, 1); - this.code[ico] = b1; - } - - /** - * Inserts bytes at the current insertion position. Creates - * {@link LineNumberOffset}s as necessary. - *

- * This method is an optimization to avoid allocating small byte[] and ease - * GC load. - * - * @param lineNumber The line number that corresponds to the byte code, or -1 - * @param b1 - * @param b2 - */ - public void - write(short lineNumber, byte b1, byte b2) { - int ico = this.currentInserter.offset; - this.makeSpace(lineNumber, 2); - this.code[ico++] = b1; - this.code[ico] = b2; - } - - /** - * Inserts bytes at the current insertion position. Creates - * {@link LineNumberOffset}s as necessary. - *

- * This method is an optimization to avoid allocating small byte[] and ease - * GC load. - * - * @param lineNumber The line number that corresponds to the byte code, or -1 - * @param b1 - * @param b2 - * @param b3 - */ - public void - write(short lineNumber, byte b1, byte b2, byte b3) { - int ico = this.currentInserter.offset; - this.makeSpace(lineNumber, 3); - this.code[ico++] = b1; - this.code[ico++] = b2; - this.code[ico] = b3; - } - - /** - * Inserts bytes at the current insertion position. Creates - * {@link LineNumberOffset}s as necessary. - *

- * This method is an optimization to avoid allocating small byte[] and ease - * GC load. - * - * @param lineNumber The line number that corresponds to the byte code, or -1 - * @param b1 - * @param b2 - * @param b3 - * @param b4 - */ - public void - write(short lineNumber, byte b1, byte b2, byte b3, byte b4) { - int ico = this.currentInserter.offset; - this.makeSpace(lineNumber, 4); - this.code[ico++] = b1; - this.code[ico++] = b2; - this.code[ico++] = b3; - this.code[ico] = b4; - } - - /** - * Add space for {@code size} bytes at current offset. Creates {@link LineNumberOffset}s as necessary. - * - * @param lineNumber The line number that corresponds to the byte code, or -1 - * @param size The size in bytes to inject - */ - public void - makeSpace(short lineNumber, int size) { - if (size == 0) return; - - INSERT_LINE_NUMBER_OFFSET: - if (lineNumber != -1) { - Offset o; - for (o = this.currentInserter.prev; o != this.beginning; o = o.prev) { - if (o instanceof LineNumberOffset) { - if (((LineNumberOffset) o).lineNumber == lineNumber) break INSERT_LINE_NUMBER_OFFSET; - break; - } - } - LineNumberOffset lno = new LineNumberOffset(this.currentInserter.offset, lineNumber); - lno.prev = this.currentInserter.prev; - lno.next = this.currentInserter; - - this.currentInserter.prev.next = lno; - this.currentInserter.prev = lno; - } - - int ico = this.currentInserter.offset; - if (this.end.offset + size <= this.code.length) { - // Optimization to avoid a trivial method call in the common case - if (ico != this.end.offset) { - System.arraycopy(this.code, ico, this.code, ico + size, this.end.offset - ico); - } - } else { - byte[] oldCode = this.code; - //double size to avoid horrible performance, but don't grow over our limit - int newSize = Math.max(Math.min(oldCode.length * 2, 0xffff), oldCode.length + size); - if (newSize > 0xffff) { - throw new JaninoRuntimeException( - "Code of method \"" - + this.functionName - + "\" of class \"" - + this.classFile.getThisClassName() - + "\" grows beyond 64 KB" - ); - } - this.code = new byte[newSize]; - System.arraycopy(oldCode, 0, this.code, 0, ico); - System.arraycopy(oldCode, ico, this.code, ico + size, this.end.offset - ico); - } - Arrays.fill(this.code, ico, ico + size, (byte) 0); - for (Offset o = this.currentInserter; o != null; o = o.next) o.offset += size; - } - - /** @param lineNumber The line number that corresponds to the byte code, or -1 */ - public void - writeShort(short lineNumber, int v) { this.write(lineNumber, (byte) (v >> 8), (byte) v); } - - /** @param lineNumber The line number that corresponds to the byte code, or -1 */ - public void - writeBranch(short lineNumber, int opcode, final Offset dst) { - this.relocatables.add(new Branch(opcode, dst)); - this.write(lineNumber, (byte) opcode, (byte) -1, (byte) -1); - } - - private - class Branch extends Relocatable { - - public - Branch(int opcode, Offset destination) { - this.opcode = opcode; - this.source = CodeContext.this.newInserter(); - this.destination = destination; - if (opcode == Opcode.JSR_W || opcode == Opcode.GOTO_W) { - //no need to expand wide opcodes - this.expanded = true; - } else { - this.expanded = false; - } - } - - @Override public boolean - relocate() { - if (this.destination.offset == Offset.UNSET) { - throw new JaninoRuntimeException("Cannot relocate branch to unset destination offset"); - } - int offset = this.destination.offset - this.source.offset; - - if (!this.expanded && (offset > Short.MAX_VALUE || offset < Short.MIN_VALUE)) { - //we want to insert the data without skewing our source position, - //so we will cache it and then restore it later. - final int pos = this.source.offset; - CodeContext.this.pushInserter(this.source); - { - // promotion to a wide instruction only requires 2 extra bytes - // everything else requires a new GOTO_W instruction after a negated if - CodeContext.this.makeSpace( - (short) -1, - this.opcode == Opcode.GOTO ? 2 : this.opcode == Opcode.JSR ? 2 : 5 - ); - } - CodeContext.this.popInserter(); - this.source.offset = pos; - this.expanded = true; - return false; - } - - final byte[] ba; - if (!this.expanded) { - //we fit in a 16-bit jump - ba = new byte[] { (byte) this.opcode, (byte) (offset >> 8), (byte) offset }; - } else { - if (this.opcode == Opcode.GOTO || this.opcode == Opcode.JSR) { - ba = new byte[] { - (byte) (this.opcode + 33), // GOTO => GOTO_W; JSR => JSR_W - (byte) (offset >> 24), - (byte) (offset >> 16), - (byte) (offset >> 8), - (byte) offset - }; - } else - { - //exclude the if-statement from jump target - //if jumping backwards this will increase the jump to go over it - //if jumping forwards this will decrease the jump by it - offset -= 3; - - // [if cond offset] - //expands to - // [if !cond skip_goto] - // [GOTO_W offset] - ba = new byte[] { - CodeContext.invertBranchOpcode((byte) this.opcode), - 0, - 8, // Jump from this instruction past the GOTO_W - Opcode.GOTO_W, - (byte) (offset >> 24), - (byte) (offset >> 16), - (byte) (offset >> 8), - (byte) offset - }; - } - } - System.arraycopy(ba, 0, CodeContext.this.code, this.source.offset, ba.length); - return true; - } - - private boolean expanded; //marks whether this has been expanded to account for a wide branch - private final int opcode; - private final Inserter source; - private final Offset destination; - } - - /** E.g. {@link Opcode#IFLT} ("less than") inverts to {@link Opcode#IFGE} ("greater than or equal to"). */ - private static byte - invertBranchOpcode(byte branchOpcode) { - return ((Byte) CodeContext.BRANCH_OPCODE_INVERSION.get(new Byte(branchOpcode))).byteValue(); - } - - private static final Map - BRANCH_OPCODE_INVERSION = CodeContext.createBranchOpcodeInversion(); - private static Map - createBranchOpcodeInversion() { - Map m = new HashMap(); - m.put(new Byte(Opcode.IF_ACMPEQ), new Byte(Opcode.IF_ACMPNE)); - m.put(new Byte(Opcode.IF_ACMPNE), new Byte(Opcode.IF_ACMPEQ)); - m.put(new Byte(Opcode.IF_ICMPEQ), new Byte(Opcode.IF_ICMPNE)); - m.put(new Byte(Opcode.IF_ICMPNE), new Byte(Opcode.IF_ICMPEQ)); - m.put(new Byte(Opcode.IF_ICMPGE), new Byte(Opcode.IF_ICMPLT)); - m.put(new Byte(Opcode.IF_ICMPLT), new Byte(Opcode.IF_ICMPGE)); - m.put(new Byte(Opcode.IF_ICMPGT), new Byte(Opcode.IF_ICMPLE)); - m.put(new Byte(Opcode.IF_ICMPLE), new Byte(Opcode.IF_ICMPGT)); - m.put(new Byte(Opcode.IFEQ), new Byte(Opcode.IFNE)); - m.put(new Byte(Opcode.IFNE), new Byte(Opcode.IFEQ)); - m.put(new Byte(Opcode.IFGE), new Byte(Opcode.IFLT)); - m.put(new Byte(Opcode.IFLT), new Byte(Opcode.IFGE)); - m.put(new Byte(Opcode.IFGT), new Byte(Opcode.IFLE)); - m.put(new Byte(Opcode.IFLE), new Byte(Opcode.IFGT)); - m.put(new Byte(Opcode.IFNULL), new Byte(Opcode.IFNONNULL)); - m.put(new Byte(Opcode.IFNONNULL), new Byte(Opcode.IFNULL)); - return Collections.unmodifiableMap(m); - } - - /** Writes a four-byte offset (as it is used in TABLESWITCH and LOOKUPSWITCH) into this code context. */ - public void - writeOffset(short lineNumber, Offset src, final Offset dst) { - this.relocatables.add(new OffsetBranch(this.newOffset(), src, dst)); - this.write(lineNumber, (byte) -1, (byte) -1, (byte) -1, (byte) -1); - } - - private - class OffsetBranch extends Relocatable { - - public - OffsetBranch(Offset where, Offset source, Offset destination) { - this.where = where; - this.source = source; - this.destination = destination; - } - - @Override public boolean - relocate() { - if (this.source.offset == Offset.UNSET || this.destination.offset == Offset.UNSET) { - throw new JaninoRuntimeException("Cannot relocate offset branch to unset destination offset"); - } - int offset = this.destination.offset - this.source.offset; - byte[] ba = new byte[] { - (byte) (offset >> 24), - (byte) (offset >> 16), - (byte) (offset >> 8), - (byte) offset - }; - System.arraycopy(ba, 0, CodeContext.this.code, this.where.offset, 4); - return true; - } - private final Offset where, source, destination; - } - - /** Creates and inserts an {@link CodeContext.Offset} at the current inserter's current position. */ - public Offset - newOffset() { - Offset o = new Offset(); - o.set(); - return o; - } - - /** - * Allocate an {@link Inserter}, set it to the current offset, and - * insert it before the current offset. - * - * In clear text, this means that you can continue writing to the - * "Code" attribute, then {@link #pushInserter(CodeContext.Inserter)} the - * {@link Inserter}, then write again (which inserts bytes into the - * "Code" attribute at the previously remembered position), and then - * {@link #popInserter()}. - */ - public Inserter - newInserter() { Inserter i = new Inserter(); i.set(); return i; } - - /** @return The current inserter */ - public Inserter - currentInserter() { return this.currentInserter; } - - /** Remember the current {@link Inserter}, then replace it with the new one. */ - public void - pushInserter(Inserter ins) { - if (ins.nextInserter != null) throw new JaninoRuntimeException("An Inserter can only be pushed once at a time"); - ins.nextInserter = this.currentInserter; - this.currentInserter = ins; - } - - /** - * Replace the current {@link Inserter} with the remembered one (see - * {@link #pushInserter(CodeContext.Inserter)}). - */ - public void - popInserter() { - Inserter ni = this.currentInserter.nextInserter; - if (ni == null) throw new JaninoRuntimeException("Code inserter stack underflow"); - this.currentInserter.nextInserter = null; // Mark it as "unpushed". - this.currentInserter = ni; - } - - /** - * A class that represents an offset within a "Code" attribute. - * - * The concept of an "offset" is that if one writes into the middle of - * a "Code" attribute, all offsets behind the insertion point are - * automatically shifted. - */ - public - class Offset { - - /** The offset in the code attribute that this object represents. */ - int offset = Offset.UNSET; - - /** Links to preceding and succeding offsets. */ - Offset prev, next; - - /** - * Special value for {@link #offset} which indicates that this {@link Offset} has not yet been {@link #set()} - */ - static final int UNSET = -1; - - /** - * Sets this "Offset" to the offset of the current inserter; inserts this "Offset" before the current inserter. - */ - public void - set() { - if (this.offset != Offset.UNSET) throw new JaninoRuntimeException("Cannot \"set()\" Offset more than once"); - - this.offset = CodeContext.this.currentInserter.offset; - - this.prev = CodeContext.this.currentInserter.prev; - this.next = CodeContext.this.currentInserter; - this.prev.next = this; - this.next.prev = this; - } - - /** @return The {@link CodeContext} that this {@link Offset} belongs to */ - public final CodeContext getCodeContext() { return CodeContext.this; } - - @Override public String - toString() { return CodeContext.this.classFile.getThisClassName() + ": " + this.offset; } - } - - /** - * Add another entry to the "exception_table" of this code attribute (see JVMS 4.7.3). - * - * @param catchTypeFd null == "finally" clause - */ - public void - addExceptionTableEntry(Offset startPc, Offset endPc, Offset handlerPc, String catchTypeFd) { - this.exceptionTableEntries.add(new ExceptionTableEntry( - startPc, - endPc, - handlerPc, - catchTypeFd == null ? (short) 0 : this.classFile.addConstantClassInfo(catchTypeFd) - )); - } - - /** Representation of an entry in the "exception_table" of a "Code" attribute (see JVMS 4.7.3). */ - private static - class ExceptionTableEntry { - ExceptionTableEntry(Offset startPc, Offset endPc, Offset handlerPc, short catchType) { - this.startPC = startPc; - this.endPC = endPc; - this.handlerPC = handlerPc; - this.catchType = catchType; - } - final Offset startPC, endPC, handlerPC; - final short catchType; // 0 == "finally" clause - } - - /** A class that implements an insertion point into a "Code" attribute. */ - public - class Inserter extends Offset { - private Inserter nextInserter; // null == not in "currentInserter" stack - } - - /** An {@link Offset} who#s sole purpose is to later create a 'LneNumberTable' attribute. */ - public - class LineNumberOffset extends Offset { - private final int lineNumber; - - public - LineNumberOffset(int offset, int lineNumber) { - this.lineNumber = lineNumber; - this.offset = offset; - } - } - - private abstract - class Relocatable { - - /** - * Relocate this object. - * @return true if the relocation succeeded in place - * false if the relocation grew the number of bytes required - */ - public abstract boolean relocate(); - } - - /** - * A throw-in interface that marks {@link CodeContext.Offset}s - * as "fix-ups": During the execution of - * {@link CodeContext#fixUp}, all "fix-ups" are invoked and - * can do last touches to the code attribute. - *

- * This is currently used for inserting the "padding bytes" into the - * TABLESWITCH and LOOKUPSWITCH instructions. - */ - public - interface FixUp { - - /** @see FixUp */ - void fixUp(); - } - - /** @return All the local variables that are allocated in any block in this {@link CodeContext} */ - public List - getAllLocalVars() { return this.allLocalVars; } - - /** - * Removes all code between {@code from} and {@code to}. Also removes any {@link CodeContext.Relocatable}s existing - * in that range. - */ - public void - removeCode(Offset from, Offset to) { - - if (from == to) return; - - int size = to.offset - from.offset; - assert size >= 0; - - if (size == 0) return; // Short circuit. - - // Shift down the bytecode past 'to'. - System.arraycopy(this.code, to.offset, this.code, from.offset, this.end.offset - to.offset); - - // Invalidate all offsets between 'from' and 'to'. - // Remove all relocatables that originate between 'from' and 'to'. - Set invalidOffsets = new HashSet(); - { - Offset o = from.next; - - for (; o != to;) { - if (o == null) { - System.currentTimeMillis(); - } - invalidOffsets.add(o); - - // Invalidate the offset for fast failure. - o.offset = -77; - o.prev = null; - o = o.next; - o.prev.next = null; - } - - for (;; o = o.next) { - o.offset -= size; - if (o == this.end) break; - } - } - - // Invalidate all relocatables which originate or target a removed offset. - for (Iterator it = this.relocatables.iterator(); it.hasNext();) { - Relocatable r = (Relocatable) it.next(); - - if (r instanceof Branch) { - Branch b = (Branch) r; - - if (invalidOffsets.contains(b.source)) { - it.remove(); - } else { - assert !invalidOffsets.contains(b.destination); - } - } - - if (r instanceof OffsetBranch) { - OffsetBranch ob = (OffsetBranch) r; - - if (invalidOffsets.contains(ob.source)) { - it.remove(); - } else { - assert !invalidOffsets.contains(ob.destination); - } - } - } - - for (Iterator it = this.exceptionTableEntries.iterator(); it.hasNext();) { - ExceptionTableEntry ete = (ExceptionTableEntry) it.next(); - - // Start, end and handler must either ALL lie IN the range to remove or ALL lie outside. - - if (invalidOffsets.contains(ete.startPC)) { - assert invalidOffsets.contains(ete.endPC); - assert invalidOffsets.contains(ete.handlerPC); - it.remove(); - } else { - assert !invalidOffsets.contains(ete.endPC); - assert !invalidOffsets.contains(ete.handlerPC); - } - } - - from.next = to; - to.prev = from; - } -} diff --git a/src/org/codehaus/janino/Compiler.java b/src/org/codehaus/janino/Compiler.java deleted file mode 100644 index 8335608f..00000000 --- a/src/org/codehaus/janino/Compiler.java +++ /dev/null @@ -1,830 +0,0 @@ - -/* - * Janino - An embedded Java[TM] compiler - * - * Copyright (c) 2001-2010, Arno Unkrig - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - * following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.codehaus.janino; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; - -import org.codehaus.commons.compiler.CompileException; -import org.codehaus.commons.compiler.ErrorHandler; -import org.codehaus.commons.compiler.Location; -import org.codehaus.commons.compiler.WarningHandler; -import org.codehaus.janino.Java.CompilationUnit; -import org.codehaus.janino.util.Benchmark; -import org.codehaus.janino.util.ClassFile; -import org.codehaus.janino.util.StringPattern; -import org.codehaus.janino.util.resource.DirectoryResourceCreator; -import org.codehaus.janino.util.resource.DirectoryResourceFinder; -import org.codehaus.janino.util.resource.FileResource; -import org.codehaus.janino.util.resource.FileResourceCreator; -import org.codehaus.janino.util.resource.PathResourceFinder; -import org.codehaus.janino.util.resource.Resource; -import org.codehaus.janino.util.resource.ResourceCreator; -import org.codehaus.janino.util.resource.ResourceFinder; - - -/** - * A simplified substitute for the javac tool. - * - * Usage: - *

- * java org.codehaus.janino.Compiler \
- *           [ -d destination-dir ] \
- *           [ -sourcepath dirlist ] \
- *           [ -classpath dirlist ] \
- *           [ -extdirs dirlist ] \
- *           [ -bootclasspath dirlist ] \
- *           [ -encoding encoding ] \
- *           [ -verbose ] \
- *           [ -g:none ] \
- *           [ -g:{source,lines,vars} ] \
- *           [ -warn:pattern-list ] \
- *           source-file ...
- * java org.codehaus.janino.Compiler -help
- * 
- */ -@SuppressWarnings({ "rawtypes", "unchecked" }) public -class Compiler { - private static final boolean DEBUG = false; - - /** Command line interface. */ - public static void BCV(String[] args) throws Exception { - File destinationDirectory = Compiler.NO_DESTINATION_DIRECTORY; - File[] optionalSourcePath = null; - File[] classPath = { new File(".") }; - File[] optionalExtDirs = null; - File[] optionalBootClassPath = null; - String optionalCharacterEncoding = null; - boolean verbose = false; - boolean debugSource = true; - boolean debugLines = true; - boolean debugVars = false; - StringPattern[] warningHandlePatterns = Compiler.DEFAULT_WARNING_HANDLE_PATTERNS; - boolean rebuild = false; - - // Process command line options. - int i; - for (i = 0; i < args.length; ++i) { - String arg = args[i]; - if (arg.charAt(0) != '-') break; - if ("-d".equals(arg)) { - destinationDirectory = new File(args[++i]); - } else - if ("-sourcepath".equals(arg)) { - optionalSourcePath = PathResourceFinder.parsePath(args[++i]); - } else - if ("-classpath".equals(arg)) { - classPath = PathResourceFinder.parsePath(args[++i]); - } else - if ("-extdirs".equals(arg)) { - optionalExtDirs = PathResourceFinder.parsePath(args[++i]); - } else - if ("-bootclasspath".equals(arg)) { - optionalBootClassPath = PathResourceFinder.parsePath(args[++i]); - } else - if ("-encoding".equals(arg)) { - optionalCharacterEncoding = args[++i]; - } else - if ("-verbose".equals(arg)) { - verbose = true; - } else - if ("-g".equals(arg)) { - debugSource = true; - debugLines = true; - debugVars = true; - } else - if (arg.startsWith("-g:")) { - if (arg.indexOf("none") != -1) debugSource = (debugLines = (debugVars = false)); - if (arg.indexOf("source") != -1) debugSource = true; - if (arg.indexOf("lines") != -1) debugLines = true; - if (arg.indexOf("vars") != -1) debugVars = true; - } else - if (arg.startsWith("-warn:")) { - warningHandlePatterns = StringPattern.parseCombinedPattern(arg.substring(6)); - } else - if ("-rebuild".equals(arg)) { - rebuild = true; - } else - if ("-help".equals(arg)) { - System.out.printf(Compiler.USAGE, (Object[]) null); - } else - { - System.err.println("Unrecognized command line option \"" + arg + "\"; try \"-help\"."); - } - } - - // Get source file names. - if (i == args.length) { - System.err.println("No source files given on command line; try \"-help\"."); - } - File[] sourceFiles = new File[args.length - i]; - for (int j = i; j < args.length; ++j) sourceFiles[j - i] = new File(args[j]); - - // Create the compiler object. - final Compiler compiler = new Compiler( - optionalSourcePath, - classPath, - optionalExtDirs, - optionalBootClassPath, - destinationDirectory, - optionalCharacterEncoding, - verbose, - debugSource, - debugLines, - debugVars, - warningHandlePatterns, - rebuild - ); - - // Compile source files. - compiler.compile(sourceFiles); - } - - private static final String USAGE = ( - "" - + "Usage:%n" - + "%n" - + " java " + Compiler.class.getName() + " [