--- /dev/null 2015-04-06 08:40:03.942185037 -0400 +++ new/test/runtime/SelectionResolution/Method.java 2015-04-17 16:07:57.488439068 -0400 @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; + +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +class Method { + public static final String defaultMethodName = "m"; + public static final String defaultMethodDescriptor = "()Ljava/lang/Integer;"; + public static final String methodDescriptorTemplate = "(L%s;)Ljava/lang/Integer;"; + private final ClassConstruct ownerClass; + private final String ownerClassName; + private final ClassVisitor cv; + private final MethodVisitor mv; + private final boolean isInterface; + private final ClassBuilder.ExecutionMode execMode; + + public Method(ClassConstruct ownerClass, ClassVisitor cv, String name, String descriptor, int access, + ClassBuilder.ExecutionMode execMode) { + this.ownerClassName = ownerClass.getName(); + this.ownerClass = ownerClass; + this.isInterface = ownerClass.isInterface(); + this.execMode = execMode; + this.cv = cv; + mv = cv.visitMethod(access, name, descriptor, null, null); + mv.visitCode(); + } + /** + * Add code for the m()Ljava/lang/Integer; method, always returns null + */ + public void makeDefaultMethod() { + mv.visitTypeInsn(NEW, "java/lang/Integer"); + mv.visitInsn(DUP); + mv.visitLdcInsn(ownerClass.getIndex()); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "", "(I)V"); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void makePrivateCallMethod(String className) { + makeSuperCallMethod(INVOKESPECIAL, className); + } + + public void makeSuperCallMethod(int invokeInstruction, String className) { + mv.visitVarInsn(ALOAD, 0); + makeCall(invokeInstruction, className); + mv.visitInsn(POP); + done(); + } + + public void defaultInvoke(int instr, String className, String objectRef) { + switch (instr) { + case INVOKEVIRTUAL: + defaultInvokeVirtual(className, objectRef); + break; + case INVOKEINTERFACE: + defaultInvokeInterface(className, objectRef); + break; + case INVOKESTATIC: + defaultInvokeStatic(className); + break; + case INVOKESPECIAL: + defaultInvokeSpecial(className, objectRef); + break; + default: + break; + } + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void defaultInvokeVirtual(String className, String objectRef) { + String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/")); + makeNewObject(objectRef, objectRefPackageName); + makeCall(INVOKEVIRTUAL, className, false); + } + + public void defaultInvokeInterface(String className, String objectRef) { + String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/")); + makeNewObject(objectRef, objectRefPackageName); + makeCall(INVOKEINTERFACE, className, true); + } + + public void defaultInvokeSpecial(String className, String objectRef) { + String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/")); + makeNewObject(objectRef, objectRefPackageName); + makeCall(INVOKESPECIAL, className, false); + } + + public void defaultInvokeStatic(String className) { + makeCall(INVOKESTATIC, className); + } + + private Method makeCall(int invokeInstruction, String className) { + return makeCall(invokeInstruction, className, isInterface); + } + + private Method makeCall(int invokeInstruction, String className, boolean isInterface) { + switch(execMode) { + case DIRECT: { + mv.visitMethodInsn(invokeInstruction, className, defaultMethodName, defaultMethodDescriptor, isInterface); + break; + } + case INDY: { + Handle m = convertToHandle(invokeInstruction, className, defaultMethodName, defaultMethodDescriptor); + Handle bsm = generateBootstrapMethod(m); + mv.visitInvokeDynamicInsn(defaultMethodName, defaultMethodDescriptor, bsm); + break; + } + case MH_INVOKE_EXACT: + case MH_INVOKE_GENERIC: { + String invokerName = execMode == ClassBuilder.ExecutionMode.MH_INVOKE_GENERIC + ? "invoke" : "invokeExact"; + + Handle m = convertToHandle(invokeInstruction, className, defaultMethodName, defaultMethodDescriptor); + mv.visitLdcInsn(m); + mv.visitInsn(SWAP); + mv.visitMethodInsn(INVOKEVIRTUAL, + "java/lang/invoke/MethodHandle", + invokerName, + String.format(methodDescriptorTemplate, className), + false); + break; + } + default: + throw new Error("Unknown execution mode: " + execMode); + + } + return this; + } + + private Handle generateBootstrapMethod(Handle h) { + String bootstrapName = "bootstrapMethod"; + MethodType bootstrapType = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); + + MethodVisitor bmv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, bootstrapName, bootstrapType.toMethodDescriptorString(), null, null); + bmv.visitCode(); + + String constCallSite = "java/lang/invoke/ConstantCallSite"; + bmv.visitTypeInsn(NEW, constCallSite); + bmv.visitInsn(DUP); + + bmv.visitLdcInsn(h); + + bmv.visitMethodInsn(INVOKESPECIAL, constCallSite, "", "(Ljava/lang/invoke/MethodHandle;)V", false); + bmv.visitInsn(ARETURN); + + bmv.visitMaxs(0,0); + bmv.visitEnd(); + + return new Handle(H_INVOKESTATIC, ownerClassName, bootstrapName, bootstrapType.toMethodDescriptorString()); + } + + + private static Handle convertToHandle(int invokeInstruction, String className, String methodName, String methodDesc) { + int tag; + switch (invokeInstruction) { + case INVOKEVIRTUAL: tag = H_INVOKEVIRTUAL; break; + case INVOKEINTERFACE: tag = H_INVOKEINTERFACE; break; + case INVOKESPECIAL: tag = H_INVOKESPECIAL; break; + case INVOKESTATIC: tag = H_INVOKESTATIC; break; + default: + throw new Error("Unknown invoke instruction: "+invokeInstruction); + } + + return new Handle(tag, className, methodName, methodDesc); + } + + private void makeNewObject(String objectRef, String objectRefPackageName) { + String className = objectRef.substring(objectRef.lastIndexOf("/") + 1); + makeStaticCall( objectRefPackageName + "/Helper", + "get" + className, + "()L" + objectRef + ";"); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + } + + public void makeTestCall(String className) { + mv.visitTypeInsn(NEW, className); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, className, "test", "()Ljava/lang/Integer;", false); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + public Method makeStaticCall(String classname, String method, String descriptor) { + mv.visitMethodInsn(INVOKESTATIC, classname, method, descriptor, isInterface); + return this; + } + + public void makeConstructor(String extending) { + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, extending == null ? "java/lang/Object" : extending, "", "()V", isInterface); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void makeInstantiateMethod(String className) { + mv.visitTypeInsn(NEW, className); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + public void done() { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } +}