Search in sources :

Example 1 with CompileException

use of org.codehaus.commons.compiler.CompileException in project drill by apache.

the class ClassTransformer method getImplementationClass.

public Class<?> getImplementationClass(final QueryClassLoader classLoader, final TemplateClassDefinition<?> templateDefinition, final String entireClass, final String materializedClassName) throws ClassTransformationException {
    // unfortunately, this hasn't been set up at construction time, so we have to do it here
    final ScalarReplacementOption scalarReplacementOption = ScalarReplacementOption.fromString(optionManager.getOption(SCALAR_REPLACEMENT_VALIDATOR));
    try {
        final long t1 = System.nanoTime();
        final ClassSet set = new ClassSet(null, templateDefinition.getTemplateClassName(), materializedClassName);
        final byte[][] implementationClasses = classLoader.getClassByteCode(set.generated, entireClass);
        long totalBytecodeSize = 0;
        Map<String, Pair<byte[], ClassNode>> classesToMerge = Maps.newHashMap();
        for (byte[] clazz : implementationClasses) {
            totalBytecodeSize += clazz.length;
            final ClassNode node = AsmUtil.classFromBytes(clazz, ClassReader.EXPAND_FRAMES);
            if (!AsmUtil.isClassOk(logger, "implementationClasses", node)) {
                throw new IllegalStateException("Problem found with implementationClasses");
            }
            classesToMerge.put(node.name, Pair.of(clazz, node));
        }
        final LinkedList<ClassSet> names = Lists.newLinkedList();
        final Set<ClassSet> namesCompleted = Sets.newHashSet();
        names.add(set);
        while (!names.isEmpty()) {
            final ClassSet nextSet = names.removeFirst();
            if (namesCompleted.contains(nextSet)) {
                continue;
            }
            final ClassNames nextPrecompiled = nextSet.precompiled;
            final byte[] precompiledBytes = byteCodeLoader.getClassByteCodeFromPath(nextPrecompiled.clazz);
            final ClassNames nextGenerated = nextSet.generated;
            // keeps only classes that have not be merged
            Pair<byte[], ClassNode> classNodePair = classesToMerge.remove(nextGenerated.slash);
            final ClassNode generatedNode;
            if (classNodePair != null) {
                generatedNode = classNodePair.getValue();
            } else {
                generatedNode = null;
            }
            /*
         * TODO
         * We're having a problem with some cases of scalar replacement, but we want to get
         * the code in so it doesn't rot anymore.
         *
         *  Here, we use the specified replacement option. The loop will allow us to retry if
         *  we're using TRY.
         */
            MergedClassResult result = null;
            boolean scalarReplace = scalarReplacementOption != ScalarReplacementOption.OFF && entireClass.length() < MAX_SCALAR_REPLACE_CODE_SIZE;
            while (true) {
                try {
                    result = MergeAdapter.getMergedClass(nextSet, precompiledBytes, generatedNode, scalarReplace);
                    break;
                } catch (RuntimeException e) {
                    // if we had a problem without using scalar replacement, then rethrow
                    if (!scalarReplace) {
                        throw e;
                    }
                    // if we did try to use scalar replacement, decide if we need to retry or not
                    if (scalarReplacementOption == ScalarReplacementOption.ON) {
                        // option is forced on, so this is a hard error
                        throw e;
                    }
                    /*
             * We tried to use scalar replacement, with the option to fall back to not using it.
             * Log this failure before trying again without scalar replacement.
             */
                    logger.info("scalar replacement failure (retrying)\n", e);
                    scalarReplace = false;
                }
            }
            for (String s : result.innerClasses) {
                s = s.replace(FileUtils.separatorChar, '.');
                names.add(nextSet.getChild(s));
            }
            classLoader.injectByteCode(nextGenerated.dot, result.bytes);
            namesCompleted.add(nextSet);
        }
        // adds byte code of the classes that have not been merged to make them accessible for outer class
        for (Map.Entry<String, Pair<byte[], ClassNode>> clazz : classesToMerge.entrySet()) {
            classLoader.injectByteCode(clazz.getKey().replace(FileUtils.separatorChar, '.'), clazz.getValue().getKey());
        }
        Class<?> c = classLoader.findClass(set.generated.dot);
        if (templateDefinition.getExternalInterface().isAssignableFrom(c)) {
            logger.debug("Compiled and merged {}: bytecode size = {}, time = {} ms.", c.getSimpleName(), DrillStringUtils.readable(totalBytecodeSize), (System.nanoTime() - t1 + 500_000) / 1_000_000);
            return c;
        }
        throw new ClassTransformationException("The requested class did not implement the expected interface.");
    } catch (CompileException | IOException | ClassNotFoundException e) {
        throw new ClassTransformationException(String.format("Failure generating transformation classes for value: \n %s", entireClass), e);
    }
}
Also used : CompileException(org.codehaus.commons.compiler.CompileException) Pair(org.apache.commons.lang3.tuple.Pair) ClassNode(org.objectweb.asm.tree.ClassNode) ClassTransformationException(org.apache.drill.exec.exception.ClassTransformationException) IOException(java.io.IOException) Map(java.util.Map) MergedClassResult(org.apache.drill.exec.compile.MergeAdapter.MergedClassResult)

Example 2 with CompileException

use of org.codehaus.commons.compiler.CompileException in project drill by apache.

the class DrillDiagnosticListener method report.

@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
    if (diagnostic.getKind() == javax.tools.Diagnostic.Kind.ERROR) {
        String message = diagnostic.toString() + " (" + diagnostic.getCode() + ")";
        logger.error(message);
        Location loc = new //
        Location(//
        diagnostic.getSource().toString(), //
        (short) diagnostic.getLineNumber(), //
        (short) diagnostic.getColumnNumber());
        // does not declare checked exceptions.
        throw new RuntimeException(new CompileException(message, loc));
    } else if (logger.isTraceEnabled()) {
        logger.trace(diagnostic.toString() + " (" + diagnostic.getCode() + ")");
    }
}
Also used : CompileException(org.codehaus.commons.compiler.CompileException) Location(org.codehaus.commons.compiler.Location)

Example 3 with CompileException

use of org.codehaus.commons.compiler.CompileException in project drill by apache.

the class FunctionInitializer method convertToCompilationUnit.

/**
   * Using class name generates path to class source code (*.java),
   * reads its content as string and parses it into {@link org.codehaus.janino.Java.CompilationUnit}.
   *
   * @param clazz function class
   * @return compilation unit
   * @throws IOException if did not find class or could not load it
   */
private CompilationUnit convertToCompilationUnit(Class<?> clazz) throws IOException {
    String path = clazz.getName();
    path = path.replaceFirst("\\$.*", "");
    path = path.replace(".", FileUtils.separator);
    path = "/" + path + ".java";
    logger.trace("Loading function code from the {}", path);
    try (InputStream is = clazz.getResourceAsStream(path)) {
        if (is == null) {
            throw new IOException(String.format("Failure trying to locate source code for class %s, tried to read on classpath location %s", clazz.getName(), path));
        }
        String body = IO.toString(is);
        // TODO: Hack to remove annotations so Janino doesn't choke. Need to reconsider this problem...
        body = body.replaceAll("@\\w+(?:\\([^\\\\]*?\\))?", "");
        try {
            return new Parser(new Scanner(null, new StringReader(body))).parseCompilationUnit();
        } catch (CompileException e) {
            throw new IOException(String.format("Failure while loading class %s.", clazz.getName()), e);
        }
    }
}
Also used : Scanner(org.codehaus.janino.Scanner) InputStream(java.io.InputStream) StringReader(java.io.StringReader) CompileException(org.codehaus.commons.compiler.CompileException) IOException(java.io.IOException) Parser(org.codehaus.janino.Parser)

Example 4 with CompileException

use of org.codehaus.commons.compiler.CompileException in project drill by apache.

the class JDKClassCompiler method doCompile.

private DrillJavaFileObject doCompile(final ClassNames className, final String sourceCode) throws CompileException, IOException, ClassNotFoundException {
    try {
        // Create one Java source file in memory, which will be compiled later.
        DrillJavaFileObject compilationUnit = new DrillJavaFileObject(className.dot, sourceCode);
        CompilationTask task = compiler.getTask(null, fileManager, listener, compilerOptions, null, Collections.singleton(compilationUnit));
        // Run the compiler.
        if (!task.call()) {
            throw new CompileException("Compilation failed", null);
        } else if (!compilationUnit.isCompiled()) {
            throw new ClassNotFoundException(className + ": Class file not created by compilation.");
        }
        // all good
        return compilationUnit;
    } catch (RuntimeException rte) {
        // Unwrap the compilation exception and throw it.
        Throwable cause = rte.getCause();
        if (cause != null) {
            cause = cause.getCause();
            if (cause instanceof CompileException) {
                throw (CompileException) cause;
            }
            if (cause instanceof IOException) {
                throw (IOException) cause;
            }
        }
        throw rte;
    }
}
Also used : CompileException(org.codehaus.commons.compiler.CompileException) IOException(java.io.IOException) CompilationTask(javax.tools.JavaCompiler.CompilationTask)

Aggregations

CompileException (org.codehaus.commons.compiler.CompileException)4 IOException (java.io.IOException)3 InputStream (java.io.InputStream)1 StringReader (java.io.StringReader)1 Map (java.util.Map)1 CompilationTask (javax.tools.JavaCompiler.CompilationTask)1 Pair (org.apache.commons.lang3.tuple.Pair)1 MergedClassResult (org.apache.drill.exec.compile.MergeAdapter.MergedClassResult)1 ClassTransformationException (org.apache.drill.exec.exception.ClassTransformationException)1 Location (org.codehaus.commons.compiler.Location)1 Parser (org.codehaus.janino.Parser)1 Scanner (org.codehaus.janino.Scanner)1 ClassNode (org.objectweb.asm.tree.ClassNode)1