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 package compiler.jvmci.compilerToVM;
25 
26 import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses;
27 import jdk.internal.reflect.ConstantPool;
28 import jdk.internal.reflect.ConstantPool.Tag;
29 import jdk.vm.ci.hotspot.CompilerToVMHelper;
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<>();
TAG_TO_TYPE_MAP.put(Tag.CLASS, CONSTANT_CLASS)61         TAG_TO_TYPE_MAP.put(Tag.CLASS, CONSTANT_CLASS);
TAG_TO_TYPE_MAP.put(Tag.FIELDREF, CONSTANT_FIELDREF)62         TAG_TO_TYPE_MAP.put(Tag.FIELDREF, CONSTANT_FIELDREF);
TAG_TO_TYPE_MAP.put(Tag.METHODREF, CONSTANT_METHODREF)63         TAG_TO_TYPE_MAP.put(Tag.METHODREF, CONSTANT_METHODREF);
TAG_TO_TYPE_MAP.put(Tag.INTERFACEMETHODREF, CONSTANT_INTERFACEMETHODREF)64         TAG_TO_TYPE_MAP.put(Tag.INTERFACEMETHODREF, CONSTANT_INTERFACEMETHODREF);
TAG_TO_TYPE_MAP.put(Tag.STRING, CONSTANT_STRING)65         TAG_TO_TYPE_MAP.put(Tag.STRING, CONSTANT_STRING);
TAG_TO_TYPE_MAP.put(Tag.INTEGER, CONSTANT_INTEGER)66         TAG_TO_TYPE_MAP.put(Tag.INTEGER, CONSTANT_INTEGER);
TAG_TO_TYPE_MAP.put(Tag.FLOAT, CONSTANT_FLOAT)67         TAG_TO_TYPE_MAP.put(Tag.FLOAT, CONSTANT_FLOAT);
TAG_TO_TYPE_MAP.put(Tag.LONG, CONSTANT_LONG)68         TAG_TO_TYPE_MAP.put(Tag.LONG, CONSTANT_LONG);
TAG_TO_TYPE_MAP.put(Tag.DOUBLE, CONSTANT_DOUBLE)69         TAG_TO_TYPE_MAP.put(Tag.DOUBLE, CONSTANT_DOUBLE);
TAG_TO_TYPE_MAP.put(Tag.NAMEANDTYPE, CONSTANT_NAMEANDTYPE)70         TAG_TO_TYPE_MAP.put(Tag.NAMEANDTYPE, CONSTANT_NAMEANDTYPE);
TAG_TO_TYPE_MAP.put(Tag.UTF8, CONSTANT_UTF8)71         TAG_TO_TYPE_MAP.put(Tag.UTF8, CONSTANT_UTF8);
TAG_TO_TYPE_MAP.put(Tag.METHODHANDLE, CONSTANT_METHODHANDLE)72         TAG_TO_TYPE_MAP.put(Tag.METHODHANDLE, CONSTANT_METHODHANDLE);
TAG_TO_TYPE_MAP.put(Tag.METHODTYPE, CONSTANT_METHODTYPE)73         TAG_TO_TYPE_MAP.put(Tag.METHODTYPE, CONSTANT_METHODTYPE);
TAG_TO_TYPE_MAP.put(Tag.INVOKEDYNAMIC, CONSTANT_INVOKEDYNAMIC)74         TAG_TO_TYPE_MAP.put(Tag.INVOKEDYNAMIC, CONSTANT_INVOKEDYNAMIC);
TAG_TO_TYPE_MAP.put(Tag.INVALID, CONSTANT_INVALID)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
getTestedCPEntry(DummyClasses dummyClass, int index)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
getTestedCPEntry(DummyClasses dummyClass, int index)99             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
100                 return this.getTestedCPEntryForMethodAndField(dummyClass, index);
101             }
102         },
103         CONSTANT_METHODREF {
104             @Override
getTestedCPEntry(DummyClasses dummyClass, int index)105             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
106                 return this.getTestedCPEntryForMethodAndField(dummyClass, index);
107             }
108         },
109         CONSTANT_INTERFACEMETHODREF {
110             @Override
getTestedCPEntry(DummyClasses dummyClass, int index)111             public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
112                 return this.getTestedCPEntryForMethodAndField(dummyClass, index);
113             }
114         },
115         CONSTANT_STRING {
116             @Override
getTestedCPEntry(DummyClasses dummyClass, int index)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
getTestedCPEntry(DummyClasses dummyClass, int index)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 
getTestedCPEntry(DummyClasses dummyClass, int index)156         public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) {
157             return null; // returning null by default
158         }
159 
getAllCPEntriesForType(DummyClasses dummyClass)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 
getTestedCPEntryForMethodAndField(DummyClasses dummyClass, int index)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 
checkIndex(ConstantPool constantPoolSS, int index)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 {
validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM, ConstantTypes cpType, DummyClasses dummyClass, int index)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 int accFlags;
207 
TestedCPEntry(String klass, String name, String type, byte[] opcodes, int accFlags)208         public TestedCPEntry(String klass, String name, String type, byte[] opcodes, int accFlags) {
209                 this(klass, name, type, null, opcodes, accFlags);
210         }
211 
TestedCPEntry(String klass, String name, String type, ResolvedJavaMethod[] methods, byte[] opcodes, int accFlags)212         public TestedCPEntry(String klass, String name, String type, ResolvedJavaMethod[] methods, byte[] opcodes, int 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 
TestedCPEntry(String klass, String name, String type, byte[] opcodes)231         public TestedCPEntry(String klass, String name, String type, byte[] opcodes) {
232             this(klass, name, type, opcodes, 0);
233         }
234 
TestedCPEntry(String klass, String name, String type)235         public TestedCPEntry(String klass, String name, String type) {
236             this(klass, name, type, null, 0);
237         }
238     }
239 
mapTagToCPType(Tag tag)240     public static ConstantTypes mapTagToCPType(Tag tag) {
241         return TAG_TO_TYPE_MAP.get(tag);
242     }
243 
ConstantPoolTestCase(Map<ConstantTypes, Validator> typeTests)244     public ConstantPoolTestCase(Map<ConstantTypes, Validator> typeTests) {
245         this.typeTests = new HashMap<>();
246         this.typeTests.putAll(typeTests);
247     }
248 
test()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 = CompilerToVMHelper.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 }
269