package org.enumerable.lambda.weaving.tree;
import org.enumerable.lambda.weaving.ClassFilter;
import org.enumerable.lambda.weaving.ClassInjector;
import org.enumerable.lambda.weaving.InMemoryCompiler;
import org.enumerable.lambda.weaving.tree.LambdaTreeWeaver.MethodAnalyzer.LambdaAnalyzer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import static org.enumerable.lambda.weaving.Debug.debug;
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.Type.getObjectType;
public class LambdaTreeTransformer implements Opcodes {
Map<String, byte[]> lambdasByClassName = new HashMap<String, byte[]>();
ClassInjector injector = new ClassInjector();
public LambdaTreeTransformer() {
debug("current class loader is " + getClass().getClassLoader());
}
public Map<String, byte[]> getLambdasByClassName() {
return lambdasByClassName;
}
public byte[] transform(ClassLoader loader, ClassFilter filter, String name, InputStream in) throws Exception {
if (lambdasByClassName.containsKey(name)) {
debug("generated lambda requested by the class loader " + name);
return lambdasByClassName.get(name);
}
ClassReader cr = new ClassReader(in);
name = cr.getClassName();
LambdaTreeWeaver weaver = new LambdaTreeWeaver(loader, filter, cr);
ClassNode cn = weaver.analyze().transform();
if (!weaver.hasLambdas())
return null;
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
cn.accept(cw);
byte[] bs = cw.toByteArray();
injector.dump(name, bs);
injector.verifyIfAsmUtilIsAvailable(bs);
for (LambdaAnalyzer la : weaver.getLambdas()) {
cw = new ClassWriter(COMPUTE_FRAMES);
la.lambda.accept(cw);
newLambdaClass(loader, getObjectType(la.lambdaClass()).getClassName(), cw.toByteArray());
}
return bs;
}
void newLambdaClass(ClassLoader loader, String name, byte[] bs) {
lambdasByClassName.put(name, bs);
InMemoryCompiler.registerLambda(name, bs);
injector.dump(name, bs);
injector.verifyIfAsmUtilIsAvailable(bs);
if (loader != null)
injector.inject(loader, name, bs);
}
}