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