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