# HG changeset patch # User mcimadamore # Date 1287425676 -3600 # Node ID 258e5f06880fb01f80970dce37ab56edb2a16423 # Parent 6b9085d37f01d6bed0af57b79e15eb6697da6be3 6991980: polymorphic signature calls don't share the same CP entries Summary: wrong use of attr env in Infer.java prevents sharing of CP entries for PS calls Reviewed-by: darcy, jrose diff -r 6b9085d37f01 -r 258e5f06880f langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Wed Oct 13 17:52:29 2010 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Mon Oct 18 19:14:36 2010 +0100 @@ -553,12 +553,24 @@ //the enclosing tree E, as follows: if E is a cast, then use the //target type of the cast expression as a return type; if E is an //expression statement, the return type is 'void' - otherwise the - //return type is simply 'Object'. - switch (env.outer.tree.getTag()) { + //return type is simply 'Object'. A correctness check ensures that + //env.next refers to the lexically enclosing environment in which + //the polymorphic signature call environment is nested. + + switch (env.next.tree.getTag()) { case JCTree.TYPECAST: - restype = ((JCTypeCast)env.outer.tree).clazz.type; break; + JCTypeCast castTree = (JCTypeCast)env.next.tree; + restype = (castTree.expr == env.tree) ? + castTree.clazz.type : + syms.objectType; + break; case JCTree.EXEC: - restype = syms.voidType; break; + JCTree.JCExpressionStatement execTree = + (JCTree.JCExpressionStatement)env.next.tree; + restype = (execTree.expr == env.tree) ? + syms.voidType : + syms.objectType; + break; default: restype = syms.objectType; } diff -r 6b9085d37f01 -r 258e5f06880f langtools/test/tools/javac/meth/TestCP.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/meth/TestCP.java Mon Oct 18 19:14:36 2010 +0100 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010, 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. + */ + +/* + * @test + * @bug 6991980 + * @summary polymorphic signature calls don't share the same CP entries + * @run main TestCP + */ + +import com.sun.tools.classfile.Instruction; +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.Method; + +import java.dyn.*; +import java.io.*; + +public class TestCP { + + static class TestClass { + void test(MethodHandle mh) throws Throwable { + Number n = mh.invokeExact("daddy",1,'n'); + n = (Number)mh.invokeExact("bunny",1,'d'); + } + } + + static final String PS_TYPE = "(Ljava/lang/String;IC)Ljava/lang/Number;"; + static final int PS_CALLS_COUNT = 2; + static final String SUBTEST_NAME = TestClass.class.getName() + ".class"; + static final String TEST_METHOD_NAME = "test"; + + public static void main(String... args) throws Exception { + new TestCP().run(); + } + + public void run() throws Exception { + String workDir = System.getProperty("test.classes"); + File compiledTest = new File(workDir, SUBTEST_NAME); + verifyMethodHandleInvocationDescriptors(compiledTest); + } + + void verifyMethodHandleInvocationDescriptors(File f) { + System.err.println("verify: " + f); + try { + int count = 0; + ClassFile cf = ClassFile.read(f); + Method testMethod = null; + for (Method m : cf.methods) { + if (m.getName(cf.constant_pool).equals(TEST_METHOD_NAME)) { + testMethod = m; + break; + } + } + if (testMethod == null) { + throw new Error("Test method not found"); + } + Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code); + if (testMethod == null) { + throw new Error("Code attribute for test() method not found"); + } + int instr_count = 0; + int cp_entry = -1; + + for (Instruction i : ea.getInstructions()) { + if (i.getMnemonic().equals("invokevirtual")) { + instr_count++; + if (cp_entry == -1) { + cp_entry = i.getUnsignedShort(1); + } else if (cp_entry != i.getUnsignedShort(1)) { + throw new Error("Unexpected CP entry in polymorphic signature call"); + } + CONSTANT_Methodref_info methRef = + (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry); + String type = methRef.getNameAndTypeInfo().getType(); + if (!type.equals(PS_TYPE)) { + throw new Error("Unexpected type in polymorphic signature call: " + type); + } + } + } + if (instr_count != PS_CALLS_COUNT) { + throw new Error("Wrong number of polymorphic signature call found: " + instr_count); + } + } catch (Exception e) { + e.printStackTrace(); + throw new Error("error reading " + f +": " + e); + } + } +}