1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import com.sun.tools.classfile.*;
  25 import com.sun.tools.classfile.BootstrapMethods_attribute.BootstrapMethodSpecifier;
  26 import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info;
  27 import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info;
  28 
  29 import java.io.File;
  30 
  31 /*
  32  * @test
  33  * @bug     8148483 8151516 8151223
  34  * @summary Test that StringConcat is working for JDK >= 9
  35  * @modules jdk.jdeps/com.sun.tools.classfile
  36  *
  37  * @clean TestIndyStringConcat*
  38  * @compile -source 7 -target 7 TestIndyStringConcat.java
  39  * @run main TestIndyStringConcat false
  40  *
  41  * @clean TestIndyStringConcat*
  42  * @compile -source 8 -target 8 TestIndyStringConcat.java
  43  * @run main TestIndyStringConcat false
  44  *
  45  * @clean TestIndyStringConcat*
  46  * @compile -XDstringConcat=inline -source 9 -target 9 TestIndyStringConcat.java
  47  * @run main TestIndyStringConcat false
  48  *
  49  * @clean TestIndyStringConcat*
  50  * @compile -XDstringConcat=indy -source 9 -target 9 TestIndyStringConcat.java
  51  * @run main TestIndyStringConcat true
  52  *
  53  * @clean TestIndyStringConcat*
  54  * @compile -XDstringConcat=indyWithConstants -source 9 -target 9 TestIndyStringConcat.java
  55  * @run main TestIndyStringConcat true
  56  */
  57 public class TestIndyStringConcat {
  58 
  59     static String other;
  60 
  61     public static String test() {
  62         return "Foo" + other;
  63     }
  64 
  65     public static void main(String[] args) throws Exception {
  66         boolean expected = Boolean.valueOf(args[0]);
  67         boolean actual = hasStringConcatFactoryCall("test");
  68         if (expected != actual) {
  69             throw new AssertionError("expected = " + expected + ", actual = " + actual);
  70         }
  71     }
  72 
  73     public static boolean hasStringConcatFactoryCall(String methodName) throws Exception {
  74         ClassFile classFile = ClassFile.read(new File(System.getProperty("test.classes", "."),
  75                 TestIndyStringConcat.class.getName() + ".class"));
  76         ConstantPool constantPool = classFile.constant_pool;
  77 
  78         BootstrapMethods_attribute bsm_attr =
  79                 (BootstrapMethods_attribute)classFile
  80                         .getAttribute(Attribute.BootstrapMethods);
  81 
  82         for (Method method : classFile.methods) {
  83             if (method.getName(constantPool).equals(methodName)) {
  84                 Code_attribute code = (Code_attribute) method.attributes
  85                         .get(Attribute.Code);
  86                 for (Instruction i : code.getInstructions()) {
  87                     if (i.getOpcode() == Opcode.INVOKEDYNAMIC) {
  88                         CONSTANT_InvokeDynamic_info indyInfo =
  89                                 (CONSTANT_InvokeDynamic_info) constantPool.get(i.getUnsignedShort(1));
  90 
  91                         BootstrapMethodSpecifier bsmSpec =
  92                                 bsm_attr.bootstrap_method_specifiers[indyInfo.bootstrap_method_attr_index];
  93 
  94                         CONSTANT_MethodHandle_info bsmInfo =
  95                                 (CONSTANT_MethodHandle_info) constantPool.get(bsmSpec.bootstrap_method_ref);
  96 
  97                         if (bsmInfo.getCPRefInfo().getClassName().equals("java/lang/invoke/StringConcatFactory")) {
  98                             return true;
  99                         }
 100                     }
 101                 }
 102             }
 103         }
 104         return false;
 105     }
 106 
 107 }