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;
}
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);
}
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;
}
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);
}
}
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);
}
Aggregations