Search in sources :

Example 1 with ClassData

use of com.google.template.soy.jbcsrc.internal.ClassData in project closure-templates by google.

the class ExpressionTester method createClass.

public static ClassData createClass(Class<? extends Invoker> targetInterface, Expression expr) {
    java.lang.reflect.Method invokeMethod;
    try {
        invokeMethod = targetInterface.getMethod("invoke");
    } catch (NoSuchMethodException | SecurityException e) {
        throw new RuntimeException(e);
    }
    Class<?> returnType = invokeMethod.getReturnType();
    if (!Type.getType(returnType).equals(expr.resultType())) {
        if (!returnType.equals(Object.class) || expr.resultType().getSort() != Type.OBJECT) {
            throw new IllegalArgumentException(targetInterface + " is not appropriate for this expression");
        }
    }
    TypeInfo generatedType = TypeInfo.create(Names.CLASS_PREFIX + targetInterface.getSimpleName() + "Impl");
    SoyClassWriter cw = SoyClassWriter.builder(generatedType).setAccess(Opcodes.ACC_FINAL | Opcodes.ACC_SUPER | Opcodes.ACC_PUBLIC).implementing(TypeInfo.create(targetInterface)).build();
    BytecodeUtils.defineDefaultConstructor(cw, generatedType);
    Method invoke = Method.getMethod(invokeMethod);
    Statement.returnExpression(expr).writeMethod(Opcodes.ACC_PUBLIC, invoke, cw);
    Method voidInvoke;
    try {
        voidInvoke = Method.getMethod(Invoker.class.getMethod("voidInvoke"));
    } catch (NoSuchMethodException | SecurityException e) {
        // this method definitely exists
        throw new RuntimeException(e);
    }
    Statement.concat(LocalVariable.createThisVar(generatedType, new Label(), new Label()).invoke(MethodRef.create(invokeMethod)).toStatement(), new Statement() {

        @Override
        protected void doGen(CodeBuilder adapter) {
            adapter.visitInsn(Opcodes.RETURN);
        }
    }).writeMethod(Opcodes.ACC_PUBLIC, voidInvoke, cw);
    ClassData data = cw.toClassData();
    checkClassData(data);
    return data;
}
Also used : Statement(com.google.template.soy.jbcsrc.restricted.Statement) Label(org.objectweb.asm.Label) Method(org.objectweb.asm.commons.Method) TypeInfo(com.google.template.soy.jbcsrc.restricted.TypeInfo) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder) ClassData(com.google.template.soy.jbcsrc.internal.ClassData) SoyClassWriter(com.google.template.soy.jbcsrc.internal.SoyClassWriter)

Example 2 with ClassData

use of com.google.template.soy.jbcsrc.internal.ClassData in project closure-templates by google.

the class BytecodeCompiler method compile.

/**
 * Compiles all the templates in the given registry.
 *
 * @param registry All the templates to compile
 * @param developmentMode Whether or not we are in development mode. In development mode we
 *     compile classes lazily
 * @param reporter The error reporter
 * @return CompiledTemplates or {@code absent()} if compilation fails, in which case errors will
 *     have been reported to the error reporter.
 */
public static Optional<CompiledTemplates> compile(final TemplateRegistry registry, boolean developmentMode, ErrorReporter reporter) {
    final Stopwatch stopwatch = Stopwatch.createStarted();
    ErrorReporter.Checkpoint checkpoint = reporter.checkpoint();
    if (reporter.errorsSince(checkpoint)) {
        return Optional.absent();
    }
    CompiledTemplateRegistry compilerRegistry = new CompiledTemplateRegistry(registry);
    if (developmentMode) {
        CompiledTemplates templates = new CompiledTemplates(compilerRegistry.getDelegateTemplateNames(), new CompilingClassLoader(compilerRegistry));
        // TODO(lukes): consider spawning a thread to load all the generated classes in the background
        return Optional.of(templates);
    }
    // TODO(lukes): once most internal users have moved to precompilation eliminate this and just
    // use the 'developmentMode' path above.  This hybrid only makes sense for production services
    // that are doing runtime compilation.  Hopefully, this will become an anomaly.
    List<ClassData> classes = compileTemplates(compilerRegistry, reporter, new CompilerListener<List<ClassData>>() {

        final List<ClassData> compiledClasses = new ArrayList<>();

        int numBytes = 0;

        int numFields = 0;

        int numDetachStates = 0;

        @Override
        public void onCompile(ClassData clazz) {
            numBytes += clazz.data().length;
            numFields += clazz.numberOfFields();
            numDetachStates += clazz.numberOfDetachStates();
            compiledClasses.add(clazz);
        }

        @Override
        public List<ClassData> getResult() {
            logger.log(Level.INFO, "Compilation took {0}\n" + "     templates: {1}\n" + "       classes: {2}\n" + "         bytes: {3}\n" + "        fields: {4}\n" + "  detachStates: {5}", new Object[] { stopwatch.toString(), registry.getAllTemplates().size(), compiledClasses.size(), numBytes, numFields, numDetachStates });
            return compiledClasses;
        }
    });
    if (reporter.errorsSince(checkpoint)) {
        return Optional.absent();
    }
    CompiledTemplates templates = new CompiledTemplates(compilerRegistry.getDelegateTemplateNames(), new MemoryClassLoader(classes));
    stopwatch.reset().start();
    templates.loadAll(compilerRegistry.getTemplateNames());
    logger.log(Level.INFO, "Loaded all classes in {0}", stopwatch);
    return Optional.of(templates);
}
Also used : Stopwatch(com.google.common.base.Stopwatch) ArrayList(java.util.ArrayList) ErrorReporter(com.google.template.soy.error.ErrorReporter) ClassData(com.google.template.soy.jbcsrc.internal.ClassData) MemoryClassLoader(com.google.template.soy.jbcsrc.internal.MemoryClassLoader) ArrayList(java.util.ArrayList) List(java.util.List) CompiledTemplates(com.google.template.soy.jbcsrc.shared.CompiledTemplates)

Example 3 with ClassData

use of com.google.template.soy.jbcsrc.internal.ClassData in project closure-templates by google.

the class CompilingClassLoader method getClassData.

@Override
protected ClassData getClassData(String name) {
    ClassData classDef = classesByName.get(name);
    if (classDef != null) {
        return classDef;
    }
    // We haven't already compiled it (and haven't already loaded it) so try to find the matching
    // template.
    // For each template we compile there are only two 'public' classes that could be loaded prior
    // to compiling the template. The CompiledTemplate.Factory class and the CompiledTemplate itself
    boolean isFactory = name.endsWith("$" + StandardNames.FACTORY_CLASS);
    String compiledTemplateName = isFactory ? name.substring(0, name.length() - (StandardNames.FACTORY_CLASS.length() + 1)) : name;
    CompiledTemplateMetadata meta = registry.getTemplateInfoByClassName(compiledTemplateName);
    if (meta == null) {
        return null;
    }
    ClassData clazzToLoad = null;
    for (ClassData clazz : new TemplateCompiler(registry, meta).compile()) {
        String className = clazz.type().className();
        if (className.equals(name)) {
            clazzToLoad = clazz;
        } else {
            classesByName.put(className, clazz);
        }
    }
    return clazzToLoad;
}
Also used : ClassData(com.google.template.soy.jbcsrc.internal.ClassData)

Example 4 with ClassData

use of com.google.template.soy.jbcsrc.internal.ClassData in project closure-templates by google.

the class AnnotationRefTest method createClassWithAnnotation.

@SuppressWarnings("unchecked")
private static <T extends Annotation> Class<?> createClassWithAnnotation(T ann) {
    TypeInfo generatedType = TypeInfo.create(AnnotationRefTest.class.getPackage().getName() + ".Tmp");
    SoyClassWriter cw = SoyClassWriter.builder(generatedType).setAccess(Opcodes.ACC_FINAL | Opcodes.ACC_SUPER | Opcodes.ACC_PUBLIC).build();
    AnnotationRef.forType((Class<T>) ann.annotationType()).write(ann, cw);
    cw.visitEnd();
    ClassData cd = cw.toClassData();
    try {
        return new MemoryClassLoader(ImmutableList.of(cd)).loadClass(cd.type().className());
    } catch (ClassNotFoundException e) {
        // this should be impossible
        throw new RuntimeException(e);
    }
}
Also used : ClassData(com.google.template.soy.jbcsrc.internal.ClassData) MemoryClassLoader(com.google.template.soy.jbcsrc.internal.MemoryClassLoader) SoyClassWriter(com.google.template.soy.jbcsrc.internal.SoyClassWriter)

Example 5 with ClassData

use of com.google.template.soy.jbcsrc.internal.ClassData in project closure-templates by google.

the class ExpressionTester method createInvoker.

public static <T> T createInvoker(Class<T> clazz, Expression expr) {
    Class<? extends Invoker> expected = invokerForType(expr.resultType());
    checkArgument(clazz.equals(expected), "%s isn't an appropriate invoker type for %s, expected %s", clazz, expr.resultType(), expected);
    ClassData data = createClass(clazz.asSubclass(Invoker.class), expr);
    return load(clazz, data);
}
Also used : ClassData(com.google.template.soy.jbcsrc.internal.ClassData)

Aggregations

ClassData (com.google.template.soy.jbcsrc.internal.ClassData)7 ErrorReporter (com.google.template.soy.error.ErrorReporter)2 MemoryClassLoader (com.google.template.soy.jbcsrc.internal.MemoryClassLoader)2 SoyClassWriter (com.google.template.soy.jbcsrc.internal.SoyClassWriter)2 Statement (com.google.template.soy.jbcsrc.restricted.Statement)2 ArrayList (java.util.ArrayList)2 Stopwatch (com.google.common.base.Stopwatch)1 SoyJarFileWriter (com.google.template.soy.base.internal.SoyJarFileWriter)1 CodeBuilder (com.google.template.soy.jbcsrc.restricted.CodeBuilder)1 FieldRef (com.google.template.soy.jbcsrc.restricted.FieldRef)1 TypeInfo (com.google.template.soy.jbcsrc.restricted.TypeInfo)1 CompiledTemplates (com.google.template.soy.jbcsrc.shared.CompiledTemplates)1 IOException (java.io.IOException)1 List (java.util.List)1 Label (org.objectweb.asm.Label)1 Method (org.objectweb.asm.commons.Method)1