test/tools/javac/lambda/bytecode/TestLambdaBytecode.java

Fri, 22 Mar 2013 12:43:09 +0000

author
mcimadamore
date
Fri, 22 Mar 2013 12:43:09 +0000
changeset 1655
c6728c9addff
parent 1652
cc38a6723663
child 1752
c09b7234cded
permissions
-rw-r--r--

8010303: Graph inference: missing incorporation step causes spurious inference error
Summary: Multiple equality constraints on inference vars are not used to generate new inference constraints
Reviewed-by: jjg

mcimadamore@1652 1 /*
mcimadamore@1652 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
mcimadamore@1652 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@1652 4 *
mcimadamore@1652 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@1652 6 * under the terms of the GNU General Public License version 2 only, as
mcimadamore@1652 7 * published by the Free Software Foundation.
mcimadamore@1652 8 *
mcimadamore@1652 9 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@1652 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@1652 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@1652 12 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@1652 13 * accompanied this code).
mcimadamore@1652 14 *
mcimadamore@1652 15 * You should have received a copy of the GNU General Public License version
mcimadamore@1652 16 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@1652 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@1652 18 *
mcimadamore@1652 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mcimadamore@1652 20 * or visit www.oracle.com if you need additional information or have any
mcimadamore@1652 21 * questions.
mcimadamore@1652 22 */
mcimadamore@1652 23
mcimadamore@1652 24 /*
mcimadamore@1652 25 * @test
mcimadamore@1652 26 * @bug 8009649
mcimadamore@1652 27 * @summary Lambda back-end should generate invokespecial for method handles referring to private instance methods
mcimadamore@1652 28 * @library ../../lib
mcimadamore@1652 29 * @build JavacTestingAbstractThreadedTest
mcimadamore@1652 30 * @run main/othervm TestLambdaBytecode
mcimadamore@1652 31 */
mcimadamore@1652 32
mcimadamore@1652 33 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
mcimadamore@1652 34 // see JDK-8006746
mcimadamore@1652 35
mcimadamore@1652 36 import com.sun.tools.classfile.Attribute;
mcimadamore@1652 37 import com.sun.tools.classfile.BootstrapMethods_attribute;
mcimadamore@1652 38 import com.sun.tools.classfile.ClassFile;
mcimadamore@1652 39 import com.sun.tools.classfile.Code_attribute;
mcimadamore@1652 40 import com.sun.tools.classfile.ConstantPool.*;
mcimadamore@1652 41 import com.sun.tools.classfile.Instruction;
mcimadamore@1652 42 import com.sun.tools.classfile.Method;
mcimadamore@1652 43
mcimadamore@1652 44 import com.sun.tools.javac.api.JavacTaskImpl;
mcimadamore@1652 45
mcimadamore@1652 46
mcimadamore@1652 47 import java.io.File;
mcimadamore@1652 48 import java.net.URI;
mcimadamore@1652 49 import java.util.ArrayList;
mcimadamore@1652 50 import java.util.Arrays;
mcimadamore@1652 51 import java.util.Locale;
mcimadamore@1652 52
mcimadamore@1652 53 import javax.tools.Diagnostic;
mcimadamore@1652 54 import javax.tools.JavaFileObject;
mcimadamore@1652 55 import javax.tools.SimpleJavaFileObject;
mcimadamore@1652 56
mcimadamore@1652 57 import static com.sun.tools.javac.jvm.ClassFile.*;
mcimadamore@1652 58
mcimadamore@1652 59 public class TestLambdaBytecode
mcimadamore@1652 60 extends JavacTestingAbstractThreadedTest
mcimadamore@1652 61 implements Runnable {
mcimadamore@1652 62
mcimadamore@1652 63 enum ClassKind {
mcimadamore@1652 64 CLASS("class"),
mcimadamore@1652 65 INTERFACE("interface");
mcimadamore@1652 66
mcimadamore@1652 67 String classStr;
mcimadamore@1652 68
mcimadamore@1652 69 ClassKind(String classStr) {
mcimadamore@1652 70 this.classStr = classStr;
mcimadamore@1652 71 }
mcimadamore@1652 72 }
mcimadamore@1652 73
mcimadamore@1652 74 enum AccessKind {
mcimadamore@1652 75 PUBLIC("public"),
mcimadamore@1652 76 PRIVATE("private");
mcimadamore@1652 77
mcimadamore@1652 78 String accessStr;
mcimadamore@1652 79
mcimadamore@1652 80 AccessKind(String accessStr) {
mcimadamore@1652 81 this.accessStr = accessStr;
mcimadamore@1652 82 }
mcimadamore@1652 83 }
mcimadamore@1652 84
mcimadamore@1652 85 enum StaticKind {
mcimadamore@1652 86 STATIC("static"),
mcimadamore@1652 87 INSTANCE("");
mcimadamore@1652 88
mcimadamore@1652 89 String staticStr;
mcimadamore@1652 90
mcimadamore@1652 91 StaticKind(String staticStr) {
mcimadamore@1652 92 this.staticStr = staticStr;
mcimadamore@1652 93 }
mcimadamore@1652 94 }
mcimadamore@1652 95
mcimadamore@1652 96 enum DefaultKind {
mcimadamore@1652 97 DEFAULT("default"),
mcimadamore@1652 98 NO_DEFAULT("");
mcimadamore@1652 99
mcimadamore@1652 100 String defaultStr;
mcimadamore@1652 101
mcimadamore@1652 102 DefaultKind(String defaultStr) {
mcimadamore@1652 103 this.defaultStr = defaultStr;
mcimadamore@1652 104 }
mcimadamore@1652 105 }
mcimadamore@1652 106
mcimadamore@1652 107 enum ExprKind {
mcimadamore@1652 108 LAMBDA("Runnable r = ()->{ target(); };");
mcimadamore@1652 109
mcimadamore@1652 110 String exprString;
mcimadamore@1652 111
mcimadamore@1652 112 ExprKind(String exprString) {
mcimadamore@1652 113 this.exprString = exprString;
mcimadamore@1652 114 }
mcimadamore@1652 115 }
mcimadamore@1652 116
mcimadamore@1652 117 static class MethodKind {
mcimadamore@1652 118 ClassKind ck;
mcimadamore@1652 119 AccessKind ak;
mcimadamore@1652 120 StaticKind sk;
mcimadamore@1652 121 DefaultKind dk;
mcimadamore@1652 122
mcimadamore@1652 123 MethodKind(ClassKind ck, AccessKind ak, StaticKind sk, DefaultKind dk) {
mcimadamore@1652 124 this.ck = ck;
mcimadamore@1652 125 this.ak = ak;
mcimadamore@1652 126 this.sk = sk;
mcimadamore@1652 127 this.dk = dk;
mcimadamore@1652 128 }
mcimadamore@1652 129
mcimadamore@1652 130 boolean inInterface() {
mcimadamore@1652 131 return ck == ClassKind.INTERFACE;
mcimadamore@1652 132 }
mcimadamore@1652 133
mcimadamore@1652 134 boolean isPrivate() {
mcimadamore@1652 135 return ak == AccessKind.PRIVATE;
mcimadamore@1652 136 }
mcimadamore@1652 137
mcimadamore@1652 138 boolean isStatic() {
mcimadamore@1652 139 return sk == StaticKind.STATIC;
mcimadamore@1652 140 }
mcimadamore@1652 141
mcimadamore@1652 142 boolean isDefault() {
mcimadamore@1652 143 return dk == DefaultKind.DEFAULT;
mcimadamore@1652 144 }
mcimadamore@1652 145
mcimadamore@1652 146 boolean isOK() {
mcimadamore@1652 147 if (isDefault() && (!inInterface() || isStatic())) {
mcimadamore@1652 148 return false;
mcimadamore@1652 149 } else if (inInterface() &&
mcimadamore@1652 150 ((!isStatic() && !isDefault()) || isPrivate())) {
mcimadamore@1652 151 return false;
mcimadamore@1652 152 } else {
mcimadamore@1652 153 return true;
mcimadamore@1652 154 }
mcimadamore@1652 155 }
mcimadamore@1652 156
mcimadamore@1652 157 String mods() {
mcimadamore@1652 158 StringBuilder buf = new StringBuilder();
mcimadamore@1652 159 buf.append(ak.accessStr);
mcimadamore@1652 160 buf.append(' ');
mcimadamore@1652 161 buf.append(sk.staticStr);
mcimadamore@1652 162 buf.append(' ');
mcimadamore@1652 163 buf.append(dk.defaultStr);
mcimadamore@1652 164 return buf.toString();
mcimadamore@1652 165 }
mcimadamore@1652 166 }
mcimadamore@1652 167
mcimadamore@1652 168 public static void main(String... args) throws Exception {
mcimadamore@1652 169 for (ClassKind ck : ClassKind.values()) {
mcimadamore@1652 170 for (AccessKind ak1 : AccessKind.values()) {
mcimadamore@1652 171 for (StaticKind sk1 : StaticKind.values()) {
mcimadamore@1652 172 for (DefaultKind dk1 : DefaultKind.values()) {
mcimadamore@1652 173 for (AccessKind ak2 : AccessKind.values()) {
mcimadamore@1652 174 for (StaticKind sk2 : StaticKind.values()) {
mcimadamore@1652 175 for (DefaultKind dk2 : DefaultKind.values()) {
mcimadamore@1652 176 for (ExprKind ek : ExprKind.values()) {
mcimadamore@1652 177 pool.execute(new TestLambdaBytecode(ck, ak1, ak2, sk1, sk2, dk1, dk2, ek));
mcimadamore@1652 178 }
mcimadamore@1652 179 }
mcimadamore@1652 180 }
mcimadamore@1652 181 }
mcimadamore@1652 182 }
mcimadamore@1652 183 }
mcimadamore@1652 184 }
mcimadamore@1652 185 }
mcimadamore@1652 186
mcimadamore@1652 187 checkAfterExec();
mcimadamore@1652 188 }
mcimadamore@1652 189
mcimadamore@1652 190 MethodKind mk1, mk2;
mcimadamore@1652 191 ExprKind ek;
mcimadamore@1652 192 DiagChecker dc;
mcimadamore@1652 193
mcimadamore@1652 194 TestLambdaBytecode(ClassKind ck, AccessKind ak1, AccessKind ak2, StaticKind sk1,
mcimadamore@1652 195 StaticKind sk2, DefaultKind dk1, DefaultKind dk2, ExprKind ek) {
mcimadamore@1652 196 mk1 = new MethodKind(ck, ak1, sk1, dk1);
mcimadamore@1652 197 mk2 = new MethodKind(ck, ak2, sk2, dk2);
mcimadamore@1652 198 this.ek = ek;
mcimadamore@1652 199 dc = new DiagChecker();
mcimadamore@1652 200 }
mcimadamore@1652 201
mcimadamore@1652 202 public void run() {
mcimadamore@1652 203 int id = checkCount.incrementAndGet();
mcimadamore@1652 204 JavaSource source = new JavaSource(id);
mcimadamore@1652 205 JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
mcimadamore@1652 206 null, null, Arrays.asList(source));
mcimadamore@1652 207 try {
mcimadamore@1652 208 ct.generate();
mcimadamore@1652 209 } catch (Throwable t) {
mcimadamore@1652 210 t.printStackTrace();
mcimadamore@1652 211 throw new AssertionError(
mcimadamore@1652 212 String.format("Error thrown when compiling following code\n%s",
mcimadamore@1652 213 source.source));
mcimadamore@1652 214 }
mcimadamore@1652 215 if (dc.diagFound) {
mcimadamore@1652 216 boolean errorExpected = !mk1.isOK() || !mk2.isOK();
mcimadamore@1652 217 errorExpected |= mk1.isStatic() && !mk2.isStatic();
mcimadamore@1652 218
mcimadamore@1652 219 if (!errorExpected) {
mcimadamore@1652 220 throw new AssertionError(
mcimadamore@1652 221 String.format("Diags found when compiling following code\n%s\n\n%s",
mcimadamore@1652 222 source.source, dc.printDiags()));
mcimadamore@1652 223 }
mcimadamore@1652 224 return;
mcimadamore@1652 225 }
mcimadamore@1652 226 verifyBytecode(id, source);
mcimadamore@1652 227 }
mcimadamore@1652 228
mcimadamore@1652 229 void verifyBytecode(int id, JavaSource source) {
mcimadamore@1652 230 File compiledTest = new File(String.format("Test%d.class", id));
mcimadamore@1652 231 try {
mcimadamore@1652 232 ClassFile cf = ClassFile.read(compiledTest);
mcimadamore@1652 233 Method testMethod = null;
mcimadamore@1652 234 for (Method m : cf.methods) {
mcimadamore@1652 235 if (m.getName(cf.constant_pool).equals("test")) {
mcimadamore@1652 236 testMethod = m;
mcimadamore@1652 237 break;
mcimadamore@1652 238 }
mcimadamore@1652 239 }
mcimadamore@1652 240 if (testMethod == null) {
mcimadamore@1652 241 throw new Error("Test method not found");
mcimadamore@1652 242 }
mcimadamore@1652 243 Code_attribute ea =
mcimadamore@1652 244 (Code_attribute)testMethod.attributes.get(Attribute.Code);
mcimadamore@1652 245 if (testMethod == null) {
mcimadamore@1652 246 throw new Error("Code attribute for test() method not found");
mcimadamore@1652 247 }
mcimadamore@1652 248
mcimadamore@1652 249 int bsmIdx = -1;
mcimadamore@1652 250
mcimadamore@1652 251 for (Instruction i : ea.getInstructions()) {
mcimadamore@1652 252 if (i.getMnemonic().equals("invokedynamic")) {
mcimadamore@1652 253 CONSTANT_InvokeDynamic_info indyInfo =
mcimadamore@1652 254 (CONSTANT_InvokeDynamic_info)cf
mcimadamore@1652 255 .constant_pool.get(i.getShort(1));
mcimadamore@1652 256 bsmIdx = indyInfo.bootstrap_method_attr_index;
mcimadamore@1652 257 if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType(id))) {
mcimadamore@1652 258 throw new
mcimadamore@1652 259 AssertionError("type mismatch for CONSTANT_InvokeDynamic_info " + source.source + "\n" + indyInfo.getNameAndTypeInfo().getType() + "\n" + makeIndyType(id));
mcimadamore@1652 260 }
mcimadamore@1652 261 }
mcimadamore@1652 262 }
mcimadamore@1652 263 if (bsmIdx == -1) {
mcimadamore@1652 264 throw new Error("Missing invokedynamic in generated code");
mcimadamore@1652 265 }
mcimadamore@1652 266
mcimadamore@1652 267 BootstrapMethods_attribute bsm_attr =
mcimadamore@1652 268 (BootstrapMethods_attribute)cf
mcimadamore@1652 269 .getAttribute(Attribute.BootstrapMethods);
mcimadamore@1652 270 if (bsm_attr.bootstrap_method_specifiers.length != 1) {
mcimadamore@1652 271 throw new Error("Bad number of method specifiers " +
mcimadamore@1652 272 "in BootstrapMethods attribute");
mcimadamore@1652 273 }
mcimadamore@1652 274 BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec =
mcimadamore@1652 275 bsm_attr.bootstrap_method_specifiers[0];
mcimadamore@1652 276
mcimadamore@1652 277 if (bsm_spec.bootstrap_arguments.length != MF_ARITY) {
mcimadamore@1652 278 throw new Error("Bad number of static invokedynamic args " +
mcimadamore@1652 279 "in BootstrapMethod attribute");
mcimadamore@1652 280 }
mcimadamore@1652 281
mcimadamore@1652 282 CONSTANT_MethodHandle_info mh =
mcimadamore@1652 283 (CONSTANT_MethodHandle_info)cf.constant_pool.get(bsm_spec.bootstrap_arguments[1]);
mcimadamore@1652 284
mcimadamore@1652 285 boolean kindOK;
mcimadamore@1652 286 switch (mh.reference_kind) {
mcimadamore@1652 287 case REF_invokeStatic: kindOK = mk2.isStatic(); break;
mcimadamore@1652 288 case REF_invokeSpecial: kindOK = !mk2.isStatic(); break;
mcimadamore@1652 289 case REF_invokeInterface: kindOK = mk2.inInterface(); break;
mcimadamore@1652 290 default:
mcimadamore@1652 291 kindOK = false;
mcimadamore@1652 292 }
mcimadamore@1652 293
mcimadamore@1652 294 if (!kindOK) {
mcimadamore@1652 295 throw new Error("Bad invoke kind in implementation method handle");
mcimadamore@1652 296 }
mcimadamore@1652 297
mcimadamore@1652 298 if (!mh.getCPRefInfo().getNameAndTypeInfo().getType().toString().equals(MH_SIG)) {
mcimadamore@1652 299 throw new Error("Type mismatch in implementation method handle");
mcimadamore@1652 300 }
mcimadamore@1652 301 } catch (Exception e) {
mcimadamore@1652 302 e.printStackTrace();
mcimadamore@1652 303 throw new Error("error reading " + compiledTest +": " + e);
mcimadamore@1652 304 }
mcimadamore@1652 305 }
mcimadamore@1652 306 String makeIndyType(int id) {
mcimadamore@1652 307 StringBuilder buf = new StringBuilder();
mcimadamore@1652 308 buf.append("(");
mcimadamore@1652 309 if (!mk2.isStatic() || mk1.inInterface()) {
mcimadamore@1652 310 buf.append(String.format("LTest%d;", id));
mcimadamore@1652 311 }
mcimadamore@1652 312 buf.append(")Ljava/lang/Runnable;");
mcimadamore@1652 313 return buf.toString();
mcimadamore@1652 314 }
mcimadamore@1652 315
mcimadamore@1652 316 static final int MF_ARITY = 3;
mcimadamore@1652 317 static final String MH_SIG = "()V";
mcimadamore@1652 318
mcimadamore@1652 319 class JavaSource extends SimpleJavaFileObject {
mcimadamore@1652 320
mcimadamore@1652 321 static final String source_template =
mcimadamore@1652 322 "#CK Test#ID {\n" +
mcimadamore@1652 323 " #MOD1 void test() { #EK }\n" +
mcimadamore@1652 324 " #MOD2 void target() { }\n" +
mcimadamore@1652 325 "}\n";
mcimadamore@1652 326
mcimadamore@1652 327 String source;
mcimadamore@1652 328
mcimadamore@1652 329 JavaSource(int id) {
mcimadamore@1652 330 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
mcimadamore@1652 331 source = source_template.replace("#CK", mk1.ck.classStr)
mcimadamore@1652 332 .replace("#MOD1", mk1.mods())
mcimadamore@1652 333 .replace("#MOD2", mk2.mods())
mcimadamore@1652 334 .replace("#EK", ek.exprString)
mcimadamore@1652 335 .replace("#ID", String.valueOf(id));
mcimadamore@1652 336 }
mcimadamore@1652 337
mcimadamore@1652 338 @Override
mcimadamore@1652 339 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
mcimadamore@1652 340 return source;
mcimadamore@1652 341 }
mcimadamore@1652 342 }
mcimadamore@1652 343
mcimadamore@1652 344 static class DiagChecker
mcimadamore@1652 345 implements javax.tools.DiagnosticListener<JavaFileObject> {
mcimadamore@1652 346
mcimadamore@1652 347 boolean diagFound;
mcimadamore@1652 348 ArrayList<String> diags = new ArrayList<>();
mcimadamore@1652 349
mcimadamore@1652 350 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
mcimadamore@1652 351 diags.add(diagnostic.getMessage(Locale.getDefault()));
mcimadamore@1652 352 diagFound = true;
mcimadamore@1652 353 }
mcimadamore@1652 354
mcimadamore@1652 355 String printDiags() {
mcimadamore@1652 356 StringBuilder buf = new StringBuilder();
mcimadamore@1652 357 for (String s : diags) {
mcimadamore@1652 358 buf.append(s);
mcimadamore@1652 359 buf.append("\n");
mcimadamore@1652 360 }
mcimadamore@1652 361 return buf.toString();
mcimadamore@1652 362 }
mcimadamore@1652 363 }
mcimadamore@1652 364
mcimadamore@1652 365 }

mercurial