@@ -68,7 +68,7 @@ import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
public abstract class FieldOrMethod extends InstructionCP { | |||
protected String signature; | |||
private String name; | |||
protected String name; | |||
private String classname; | |||
protected FieldOrMethod(short opcode, int index) { |
@@ -58,6 +58,7 @@ import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantCP; | |||
import org.aspectj.apache.bcel.classfile.ConstantInvokeDynamic; | |||
import org.aspectj.apache.bcel.classfile.ConstantNameAndType; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
@@ -108,9 +109,23 @@ public final class InvokeDynamic extends InvokeInstruction { | |||
if (signature == null) { | |||
ConstantInvokeDynamic cid = (ConstantInvokeDynamic)cp.getConstant(index); | |||
ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cid.getNameAndTypeIndex()); | |||
signature = ((ConstantUtf8) cp.getConstant(cnat.getSignatureIndex())).getValue(); | |||
signature = cp.getConstantUtf8(cnat.getSignatureIndex()).getValue(); | |||
} | |||
return signature; | |||
} | |||
@Override | |||
public String getName(ConstantPool cp) { | |||
if (name == null) { | |||
ConstantInvokeDynamic cid = (ConstantInvokeDynamic) cp.getConstant(index); | |||
ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cid.getNameAndTypeIndex()); | |||
name = cp.getConstantUtf8(cnat.getNameIndex()).getValue(); | |||
} | |||
return name; | |||
} | |||
public String getClassName(ConstantPool cp) { | |||
throw new IllegalStateException("nyi"); | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
aspect Aspect { | |||
before(): call(* *.*(..)) && !within(Aspect) { | |||
System.out.println(thisJoinPointStaticPart); | |||
} | |||
} |
@@ -0,0 +1,21 @@ | |||
import java.lang.invoke.CallSite; | |||
import java.lang.invoke.ConstantCallSite; | |||
import java.lang.invoke.MethodHandle; | |||
import java.lang.invoke.MethodHandles; | |||
import java.lang.invoke.MethodType; | |||
public class Code1 { | |||
// Called via invokedynamic from a generated class | |||
private static void foo() { | |||
System.out.println("foo() is running"); | |||
} | |||
public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { | |||
MethodHandles.Lookup lookup = MethodHandles.lookup(); | |||
Class<?> thisClass = lookup.lookupClass(); | |||
MethodHandle mh = lookup.findStatic(thisClass, name, type); | |||
return new ConstantCallSite(mh);//mh.asType(type)); | |||
} | |||
} |
@@ -0,0 +1,101 @@ | |||
import java.io.File; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.lang.invoke.CallSite; | |||
import java.lang.invoke.MethodHandles; | |||
import java.lang.invoke.MethodType; | |||
import org.objectweb.asm.*; | |||
public class Generator implements Opcodes { | |||
private String generatedRunnerTypename,linkClassName,dynMethodName,dynMethodDescriptor; | |||
private byte[] bytes; | |||
/** | |||
* Main entry point generates a default thing, in this case a class called 'Invoker' that will use the bootstrap method on Code1 to run 'foo()' | |||
* @param args | |||
* @throws Throwable | |||
*/ | |||
public static void main(String[] args) throws Throwable { | |||
Generator g = new Generator("Invoker","Code1","foo","()V"); | |||
g.dump(); | |||
} | |||
public byte[] getBytes() { | |||
return bytes; | |||
} | |||
public Generator(String generatedRunnerTypename, String linkClassName, String dynMethodName, String dynMethodDescriptor) { | |||
this.generatedRunnerTypename = generatedRunnerTypename; | |||
this.linkClassName = linkClassName; | |||
this.dynMethodName = dynMethodName; | |||
this.dynMethodDescriptor = dynMethodDescriptor; | |||
this.bytes = generateClass(); | |||
} | |||
public void dump() { | |||
try { | |||
FileOutputStream fos | |||
= new FileOutputStream(new File(generatedRunnerTypename+".class")); | |||
fos.write(bytes); | |||
fos.close(); | |||
} catch (FileNotFoundException e) { | |||
e.printStackTrace(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
public byte[] generateClass() { | |||
ClassWriter cw = new ClassWriter(0); | |||
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, generatedRunnerTypename, null, "java/lang/Object", null); | |||
createConstructor(cw); | |||
createMain(cw); | |||
cw.visitEnd(); | |||
return cw.toByteArray(); | |||
} | |||
private void createMain(ClassWriter cw) { | |||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); | |||
mv.visitCode(); | |||
MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, | |||
MethodType.class); | |||
Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, this.linkClassName, "bootstrap", | |||
mt.toMethodDescriptorString()); | |||
int maxStackSize = 0;//addMethodParameters(mv); | |||
mv.visitInvokeDynamicInsn(dynMethodName, dynMethodDescriptor, bootstrap); | |||
mv.visitInsn(RETURN); | |||
mv.visitMaxs(maxStackSize, 1); | |||
mv.visitEnd(); | |||
} | |||
// public byte[] dump(String dynamicInvokerClassName, String dynamicLinkageClassName, String bootstrapMethodName, String targetMethodDescriptor) | |||
// throws Exception { | |||
// ClassWriter cw = new ClassWriter(0); | |||
// cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, dynamicInvokerClassName, null, "java/lang/Object", null); | |||
// createConstructor(cw); | |||
// createMain(dynamicLinkageClassName, bootstrapMethodName, targetMethodDescriptor, cw); | |||
// cw.visitEnd(); | |||
// return cw.toByteArray(); | |||
// } | |||
// protected int addMethodParameters(MethodVisitor mv) { | |||
// return 0; | |||
// } | |||
private void createConstructor(ClassWriter cw) { | |||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); | |||
mv.visitCode(); | |||
mv.visitVarInsn(ALOAD, 0); | |||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); | |||
mv.visitInsn(RETURN); | |||
mv.visitMaxs(1, 1); | |||
mv.visitEnd(); | |||
} | |||
} |
@@ -15,12 +15,7 @@ import java.io.IOException; | |||
import junit.framework.Test; | |||
import org.aspectj.apache.bcel.classfile.ClassParser; | |||
import org.aspectj.apache.bcel.classfile.Field; | |||
import org.aspectj.apache.bcel.classfile.JavaClass; | |||
import org.aspectj.testing.XMLBasedAjcTestCase; | |||
import org.aspectj.weaver.TypeFactory; | |||
import org.aspectj.weaver.UnresolvedType; | |||
/** | |||
* @author Andy Clement | |||
@@ -36,6 +31,11 @@ public class IndyTests extends org.aspectj.testing.XMLBasedAjcTestCase { | |||
public void testInvokeDynamic_execution() throws IOException { | |||
runTest("indy - 2"); | |||
} | |||
// call pointcuts on same bytecode | |||
public void testInvokeDynamic_call() throws IOException { | |||
runTest("indy - 3"); | |||
} | |||
// --- | |||
@@ -24,5 +24,18 @@ | |||
</stdout> | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="indy/three" title="indy - 3"> | |||
<compile files="Code1.java,Asp.java" inpath="indy.jar" options="-1.7"/> | |||
<run class="Invoker"> | |||
<stdout> | |||
<line text="call(MethodHandles.Lookup java.lang.invoke.MethodHandles.lookup())"/> | |||
<line text="call(Class java.lang.invoke.MethodHandles.Lookup.lookupClass())"/> | |||
<line text="call(MethodHandle java.lang.invoke.MethodHandles.Lookup.findStatic(Class, String, MethodType))"/> | |||
<line text="call(void java.io.PrintStream.println(String))"/> | |||
<line text="foo() is running"/> | |||
</stdout> | |||
</run> | |||
</ajc-test> | |||
</suite> |