# HG changeset patch # User nastaran # Date 1435263650 25200 # Node ID 7be90179bb3ba457e88d844d69079eeeae72e66c # Parent 8aded593a50fd7e6ce786e333f8f5e9830796cad Provided support for double colon operator used for lamabda expressions. Fixed a bug related to generating names for funcation object classes (by supporting double colon operator, a new stragety needed to generate unique names for function objects. To achive that the bootstrap ids are incorporated into names). Finally modified the method that retrieves the SAM from functional interfaces. diff -r 8aded593a50f -r 7be90179bb3b src/main/gov/nasa/jpf/jvm/JVMClassInfo.java --- a/src/main/gov/nasa/jpf/jvm/JVMClassInfo.java Mon May 11 12:17:18 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/JVMClassInfo.java Thu Jun 25 13:20:50 2015 -0700 @@ -93,11 +93,21 @@ int lambdaRefKind = cf.mhRefTypeAt(cpArgs[1]); int mrefIdx = cf.mhMethodRefIndexAt(cpArgs[1]); - String clsName = cf.methodClassNameAt(mrefIdx); + String clsName = cf.methodClassNameAt(mrefIdx).replace('/', '.'); + ClassInfo eclosingLambdaCls; + + if(!clsName.equals(JVMClassInfo.this.getName())) { + eclosingLambdaCls = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); + } else { + eclosingLambdaCls = JVMClassInfo.this; + } + + assert (eclosingLambdaCls!=null); + String mthName = cf.methodNameAt(mrefIdx); String signature = cf.methodDescriptorAt(mrefIdx); - MethodInfo lambdaBody = JVMClassInfo.this.getMethod(mthName + signature, false); + MethodInfo lambdaBody = eclosingLambdaCls.getMethod(mthName + signature, false); String samDescriptor = cf.methodTypeDescriptorAt(cpArgs[2]); @@ -641,7 +651,7 @@ // creating a method corresponding to the single abstract method of the functional interface methods = new HashMap(); - MethodInfo fiMethod = funcInterface.getInterfaceAbstractMethod(samUniqueName); + MethodInfo fiMethod = funcInterface.getInterfaceAbstractMethod(); int modifiers = fiMethod.getModifiers() & (~Modifier.ABSTRACT); int nLocals = fiMethod.getArgumentsSize(); int nOperands = this.nInstanceFields + nLocals; @@ -856,6 +866,10 @@ case ClassFile.REF_INVOKEVIRTUAL: cb.invokevirtual(calleeClass, calleeName, calleeSig); break; + case ClassFile.REF_NEW_INVOKESPECIAL: + cb.new_(calleeClass); + cb.invokespecial(calleeClass, calleeName, calleeSig); + break; case ClassFile.REF_INVOKESPECIAL: cb.invokespecial(calleeClass, calleeName, calleeSig); break; diff -r 8aded593a50f -r 7be90179bb3b src/main/gov/nasa/jpf/jvm/JVMCodeBuilder.java --- a/src/main/gov/nasa/jpf/jvm/JVMCodeBuilder.java Mon May 11 12:17:18 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/JVMCodeBuilder.java Thu Jun 25 13:20:50 2015 -0700 @@ -1171,6 +1171,10 @@ add( insnFactory.new_(cf.classNameAt(cpClassIndex))); pc+=3; } + public void new_(String className) { + add( insnFactory.new_(className)); + pc+=3; + } @Override public void newarray(int typeCode) { add( insnFactory.newarray(typeCode)); diff -r 8aded593a50f -r 7be90179bb3b src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java --- a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java Mon May 11 12:17:18 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java Thu Jun 25 13:20:50 2015 -0700 @@ -116,10 +116,9 @@ VM vm = VM.getVM(); FunctionObjectFactory funcObjFactory = vm.getFunctionObjectFacotry(); - String samUniqueName = samMethodName + bmi.getSamDescriptor(); Object[] freeVariableValues = frame.getArgumentsValues(ti, freeVariableTypes); - funcObjRef = funcObjFactory.getFunctionObject(ti, fiClassInfo, samUniqueName, bmi, freeVariableTypeNames, freeVariableValues); + funcObjRef = funcObjFactory.getFunctionObject(bootstrapMethodIndex, ti, fiClassInfo, samMethodName, bmi, freeVariableTypeNames, freeVariableValues); lastFuncObj = ti.getHeap().get(funcObjRef); } diff -r 8aded593a50f -r 7be90179bb3b src/main/gov/nasa/jpf/vm/BootstrapMethodInfo.java --- a/src/main/gov/nasa/jpf/vm/BootstrapMethodInfo.java Mon May 11 12:17:18 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/BootstrapMethodInfo.java Thu Jun 25 13:20:50 2015 -0700 @@ -47,7 +47,7 @@ @Override public String toString() { - return "BootstrapMethodInfo[" + enclosingClass.getName() + "." + lambdaBody.getName() + + return "BootstrapMethodInfo[" + enclosingClass.getName() + "." + lambdaBody.getBaseName() + "[SAM descriptor:" + samDescriptor + "]]"; } diff -r 8aded593a50f -r 7be90179bb3b src/main/gov/nasa/jpf/vm/ClassInfo.java --- a/src/main/gov/nasa/jpf/vm/ClassInfo.java Mon May 11 12:17:18 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/ClassInfo.java Thu Jun 25 13:20:50 2015 -0700 @@ -1109,19 +1109,34 @@ return mi; } - public MethodInfo getInterfaceAbstractMethod (String uniqueName) { - MethodInfo mi = this.getMethod(uniqueName, true); + /** + * This retrieves the SAM from this functional interface. Note that this is only + * called on functional interface expecting to have a SAM. This shouldn't expect + * this interface to have only one method which is abstract, since: + * 1. functional interface can declare the abstract methods from the java.lang.Object + * class. + * 2. functional interface can extend another interface which is functional, but it + * should not declare any new abstract methods. + * 3. functional interface can have one abstract method and any number of default + * methods. + * + * To retrieve the SAM, this method iterates over the methods of this interface and its + * superinterfaces, and it returns the first method which is abstract and it does not + * declare a method in java.lang.Object. + */ + public MethodInfo getInterfaceAbstractMethod () { + ClassInfo objCi = ClassLoaderInfo.getCurrentResolvedClassInfo("java.lang.Object"); - if(mi != null) { - return mi; + for(MethodInfo mi: this.methods.values()) { + if(mi.isAbstract() && objCi.getMethod(mi.getUniqueName(), false)==null) { + return mi; + } } - for (ClassInfo ci = this; ci != null && mi == null; ci = ci.superClass){ - for (ClassInfo ciIfc : ci.interfaces){ - mi = ciIfc.getMethod(uniqueName, true); - if (mi != null && mi.isAbstract()){ - return mi; - } + for (ClassInfo ifc : this.interfaces){ + MethodInfo mi = ifc.getInterfaceAbstractMethod(); + if(mi!=null) { + return mi; } } diff -r 8aded593a50f -r 7be90179bb3b src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java --- a/src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java Mon May 11 12:17:18 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java Thu Jun 25 13:20:50 2015 -0700 @@ -448,8 +448,8 @@ * This method returns a type which implements the given functional interface * and contains a method that captures the behavior of the lambda expression. */ - public ClassInfo getResolvedFuncObjType (ClassInfo fiClassInfo, String samUniqueName, BootstrapMethodInfo bmi, String[] freeVariableTypeNames) { - String typeName = bmi.enclosingClass.getName() + "$$" + bmi.lambdaBody.getName(); + public ClassInfo getResolvedFuncObjType (int bsIdx, ClassInfo fiClassInfo, String samUniqueName, BootstrapMethodInfo bmi, String[] freeVariableTypeNames) { + String typeName = bmi.enclosingClass.getName() + "$$Lambda$" + bsIdx; ClassInfo funcObjType = resolvedClasses.get( typeName); diff -r 8aded593a50f -r 7be90179bb3b src/main/gov/nasa/jpf/vm/FunctionObjectFactory.java --- a/src/main/gov/nasa/jpf/vm/FunctionObjectFactory.java Mon May 11 12:17:18 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/FunctionObjectFactory.java Thu Jun 25 13:20:50 2015 -0700 @@ -22,12 +22,12 @@ */ public class FunctionObjectFactory { - public int getFunctionObject(ThreadInfo ti, ClassInfo fiClassInfo, String samUniqueName, BootstrapMethodInfo bmi, + public int getFunctionObject(int bsIdx, ThreadInfo ti, ClassInfo fiClassInfo, String samUniqueName, BootstrapMethodInfo bmi, String[] freeVariableTypeNames, Object[] freeVariableValues) { ClassLoaderInfo cli = bmi.enclosingClass.getClassLoaderInfo(); - ClassInfo funcObjType = cli.getResolvedFuncObjType(fiClassInfo, samUniqueName, bmi, freeVariableTypeNames); + ClassInfo funcObjType = cli.getResolvedFuncObjType(bsIdx, fiClassInfo, samUniqueName, bmi, freeVariableTypeNames); funcObjType.registerClass(ti); diff -r 8aded593a50f -r 7be90179bb3b src/tests/java8/LambdaTest.java --- a/src/tests/java8/LambdaTest.java Mon May 11 12:17:18 2015 -0700 +++ b/src/tests/java8/LambdaTest.java Thu Jun 25 13:20:50 2015 -0700 @@ -167,4 +167,92 @@ } } } + + public static class C2 { + public static void throwException() { + throw new EnforcedException(); + } + } + + @Test + public void testDoubleCloneOperator() { + if (verifyUnhandledException(EnforcedException.class.getName())) { + FI1 fi = C2::throwException; + fi.sam(); + } + } + + static class A { + static { + if(true) { + throw new EnforcedException(); + } + } + } + + @Test + public void testInitDoubleCloneOperator() { + if (verifyUnhandledException(EnforcedException.class.getName())) { + new Thread(A::new).start(); + } + } + + static class D { + static final B b = new B(); + } + + static class B { + static final D a = new D(); + } + + @Test + public void testClinitDeadlock() { + if(verifyDeadlock()) { + new Thread(D::new).start(); + new B(); + } + } + + @Test + public void testLambdaTypeName() { + if(verifyNoPropertyViolation()) { + Runnable r1 = (A::new); + Runnable r2 = (B::new); + + assertFalse(r1.getClass().getName().equals(r2.getClass().getName())); + } + } + + public interface FI { + default boolean returnTrue() { + return true; + } + @Override + public String toString(); + public String toString(int i); + } + + @Test + public void testLambdaWithOverridenDefaultMethods() { + if(verifyNoPropertyViolation()) { + FI fi = (int i) -> {return "output:"+ i;}; + assertEquals(fi.toString(10),"output:10"); + } + } + + public interface FI4 { + } + + public interface FI5 extends FI { + @Override + public boolean equals(Object obj); + } + + @Test + public void testLambdaWithMultipleSuperInterfaces() { + if(verifyNoPropertyViolation()) { + FI5 fi = (int i) -> {return "output:"+ i;}; + assertEquals(fi.toString(10),"output:10"); + } + } }