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 
  25 package compiler.jvmci.compilerToVM;
  26 
  27 import java.util.HashMap;
  28 import java.util.Map;
  29 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
  30 import sun.hotspot.WhiteBox;
  31 import jdk.internal.reflect.ConstantPool;
  32 import jdk.internal.reflect.ConstantPool.Tag;
  33 import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses;
  34 import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*;
  35 
  36 /**
  37  * Common class for jdk.vm.ci.hotspot.CompilerToVM constant pool tests
  38  */
  39 public class ConstantPoolTestCase {
  40 
  41     private static final Map<Tag, ConstantTypes> TAG_TO_TYPE_MAP;
  42     static {
  43         TAG_TO_TYPE_MAP = new HashMap<>();
  44         TAG_TO_TYPE_MAP.put(Tag.CLASS, CONSTANT_CLASS);
  45         TAG_TO_TYPE_MAP.put(Tag.FIELDREF, CONSTANT_FIELDREF);
  46         TAG_TO_TYPE_MAP.put(Tag.METHODREF, CONSTANT_METHODREF);
  47         TAG_TO_TYPE_MAP.put(Tag.INTERFACEMETHODREF, CONSTANT_INTERFACEMETHODREF);
  48         TAG_TO_TYPE_MAP.put(Tag.STRING, CONSTANT_STRING);
  49         TAG_TO_TYPE_MAP.put(Tag.INTEGER, CONSTANT_INTEGER);
  50         TAG_TO_TYPE_MAP.put(Tag.FLOAT, CONSTANT_FLOAT);
  51         TAG_TO_TYPE_MAP.put(Tag.LONG, CONSTANT_LONG);
  52         TAG_TO_TYPE_MAP.put(Tag.DOUBLE, CONSTANT_DOUBLE);
  53         TAG_TO_TYPE_MAP.put(Tag.NAMEANDTYPE, CONSTANT_NAMEANDTYPE);
  54         TAG_TO_TYPE_MAP.put(Tag.UTF8, CONSTANT_UTF8);
  55         TAG_TO_TYPE_MAP.put(Tag.METHODHANDLE, CONSTANT_METHODHANDLE);
  56         TAG_TO_TYPE_MAP.put(Tag.METHODTYPE, CONSTANT_METHODTYPE);
  57         TAG_TO_TYPE_MAP.put(Tag.INVOKEDYNAMIC, CONSTANT_INVOKEDYNAMIC);
  58         TAG_TO_TYPE_MAP.put(Tag.INVALID, CONSTANT_INVALID);
  59     }
  60     private static final WhiteBox WB = WhiteBox.getWhiteBox();
  61     private final Map<ConstantTypes, Validator> typeTests;
  62 
  63     public static enum ConstantTypes {
  64         CONSTANT_CLASS {
  65             @Override
  66             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
  67                 ConstantPool constantPoolSS = dummyClass.constantPoolSS;
  68                 checkIndex(constantPoolSS, index);
  69                 Class<?> klass = constantPoolSS.getClassAt(index);
  70                 String klassName = klass.getName();
  71                 TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this);
  72                 for (TestedCPEntry entry : testedEntries) {
  73                     if (entry.klass.replaceAll("/", "\\.").equals(klassName)) {
  74                         return entry;
  75                     }
  76                 }
  77                 return null;
  78             }
  79         },
  80         CONSTANT_FIELDREF {
  81             @Override
  82             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
  83                 return this.getTestedCPEntryForMethodAndField(dummyClass, index);
  84             }
  85         },
  86         CONSTANT_METHODREF {
  87             @Override
  88             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
  89                 return this.getTestedCPEntryForMethodAndField(dummyClass, index);
  90             }
  91         },
  92         CONSTANT_INTERFACEMETHODREF {
  93             @Override
  94             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
  95                 return this.getTestedCPEntryForMethodAndField(dummyClass, index);
  96             }
  97         },
  98         CONSTANT_STRING {
  99             @Override
 100             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
 101                 ConstantPool constantPoolSS = dummyClass.constantPoolSS;
 102                 checkIndex(constantPoolSS, index);
 103                 String value = constantPoolSS.getStringAt(index);
 104                 TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this);
 105                 for (TestedCPEntry entry : testedEntries) {
 106                     if (entry.name.equals(value)) {
 107                         return entry;
 108                     }
 109                 }
 110                 return null;
 111             }
 112         },
 113         CONSTANT_INTEGER,
 114         CONSTANT_FLOAT,
 115         CONSTANT_LONG,
 116         CONSTANT_DOUBLE,
 117         CONSTANT_NAMEANDTYPE,
 118         CONSTANT_UTF8,
 119         CONSTANT_METHODHANDLE,
 120         CONSTANT_METHODTYPE,
 121         CONSTANT_INVOKEDYNAMIC {
 122             @Override
 123             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
 124                 ConstantPool constantPoolSS = dummyClass.constantPoolSS;
 125                 checkIndex(constantPoolSS, index);
 126                 int nameAndTypeIndex = constantPoolSS.getNameAndTypeRefIndexAt(index);
 127                 String[] info = constantPoolSS.getNameAndTypeRefInfoAt(nameAndTypeIndex);
 128                 TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this);
 129                 for (TestedCPEntry entry : testedEntries) {
 130                     if (info[0].equals(entry.name) && info[1].equals(entry.type)) {
 131                         return entry;
 132                     }
 133                 }
 134                 return null;
 135             }
 136         },
 137         CONSTANT_INVALID;
 138 
 139         public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
 140             return null; // returning null by default
 141         }
 142 
 143         public TestedCPEntry[] getAllCPEntriesForType(DummyClasses dummyClass) {
 144             TestedCPEntry[] toReturn = dummyClass.testedCP.get(this);
 145             if (toReturn == null) {
 146                 return new TestedCPEntry[0];
 147             }
 148             return dummyClass.testedCP.get(this);
 149         }
 150 
 151         protected TestedCPEntry getTestedCPEntryForMethodAndField(DummyClasses dummyClass, int index) {
 152             ConstantPool constantPoolSS = dummyClass.constantPoolSS;
 153             checkIndex(constantPoolSS, index);
 154             String[] info = constantPoolSS.getMemberRefInfoAt(index);
 155             TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this);
 156             for (TestedCPEntry entry : testedEntries) {
 157                 if (info[0].equals(entry.klass) && info[1].equals(entry.name) && info[2].equals(entry.type)) {
 158                     return entry;
 159                 }
 160             }
 161             return null;
 162         }
 163 
 164         protected void checkIndex(ConstantPool constantPoolSS, int index) {
 165             ConstantPool.Tag tag = constantPoolSS.getTagAt(index);
 166             ConstantTypes type = mapTagToCPType(tag);
 167             if (!this.equals(type)) {
 168                 String msg = String.format("TESTBUG: CP tag should be a %s, but is %s",
 169                                            this.name(),
 170                                            type.name());
 171                throw new Error(msg);
 172             }
 173         }
 174     }
 175 
 176     public static interface Validator {
 177         void validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM,
 178                       ConstantTypes cpType,
 179                       DummyClasses dummyClass,
 180                       int index);
 181     }
 182 
 183     public static class TestedCPEntry {
 184         public final String klass;
 185         public final String name;
 186         public final String type;
 187         public final byte[] opcodes;
 188         public final long accFlags;
 189 
 190         public TestedCPEntry(String klass, String name, String type, byte[] opcodes, long accFlags) {
 191             this.klass = klass;
 192             this.name = name;
 193             this.type = type;
 194             if (opcodes != null) {
 195                 this.opcodes = new byte[opcodes.length];
 196                 System.arraycopy(opcodes, 0, this.opcodes, 0, opcodes.length);
 197             } else {
 198                 this.opcodes = null;
 199             }
 200             this.accFlags = accFlags;
 201         }
 202 
 203         public TestedCPEntry(String klass, String name, String type, byte[] opcodes) {
 204             this(klass, name, type, opcodes, 0);
 205         }
 206 
 207         public TestedCPEntry(String klass, String name, String type) {
 208             this(klass, name, type, null, 0);
 209         }
 210     }
 211 
 212     public static ConstantTypes mapTagToCPType(Tag tag) {
 213         return TAG_TO_TYPE_MAP.get(tag);
 214     }
 215 
 216     public ConstantPoolTestCase(Map<ConstantTypes, Validator> typeTests) {
 217         this.typeTests = new HashMap<>();
 218         this.typeTests.putAll(typeTests);
 219     }
 220 
 221     public void test() {
 222         for (DummyClasses dummyClass : DummyClasses.values()) {
 223             boolean isCPCached = WB.getConstantPoolCacheLength(dummyClass.klass) > -1;
 224             System.out.printf("Testing dummy %s with constant pool cached = %b%n",
 225                               dummyClass.klass,
 226                               isCPCached);
 227             HotSpotResolvedObjectType holder = HotSpotResolvedObjectType.fromObjectClass(dummyClass.klass);
 228             jdk.vm.ci.meta.ConstantPool constantPoolCTVM = holder.getConstantPool();
 229             ConstantPool constantPoolSS = dummyClass.constantPoolSS;
 230             for (int i = 0; i < constantPoolSS.getSize(); i++) {
 231                 Tag tag = constantPoolSS.getTagAt(i);
 232                 ConstantTypes cpType = mapTagToCPType(tag);
 233                 if (!typeTests.keySet().contains(cpType)) {
 234                     continue;
 235                 }
 236                 typeTests.get(cpType).validate(constantPoolCTVM, cpType, dummyClass, i);
 237             }
 238         }
 239     }
 240 }