1 /*
2 * Copyright (c) 2022, 2024, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26 package jdk.internal.classfile.impl.verifier;
27
28 import java.lang.classfile.Attributes;
29 import java.lang.classfile.ClassModel;
30 import java.lang.classfile.MethodModel;
31 import java.lang.classfile.attribute.LocalVariableInfo;
32 import java.lang.classfile.constantpool.ClassEntry;
33 import java.lang.classfile.constantpool.ConstantPool;
34 import java.lang.classfile.constantpool.DynamicConstantPoolEntry;
35 import java.lang.classfile.constantpool.MemberRefEntry;
36 import java.lang.classfile.constantpool.NameAndTypeEntry;
37 import java.lang.constant.ClassDesc;
38 import java.lang.reflect.AccessFlag;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.stream.Collectors;
42
43 import jdk.internal.classfile.impl.BoundAttribute;
44 import jdk.internal.classfile.impl.CodeImpl;
45 import jdk.internal.classfile.impl.Util;
46
47 public final class VerificationWrapper {
48 private final ClassModel clm;
49 private final ConstantPoolWrapper cp;
50
51 public VerificationWrapper(ClassModel clm) {
52 this.clm = clm;
53 this.cp = new ConstantPoolWrapper(clm.constantPool());
54 }
55
56 String thisClassName() {
57 return clm.thisClass().asInternalName();
58 }
59
60 int majorVersion() {
61 return clm.majorVersion();
62 }
63
64 String superclassName() {
65 return clm.superclass().map(ClassEntry::asInternalName).orElse(null);
66 }
67
68 Iterable<String> interfaceNames() {
69 return Util.mappedList(clm.interfaces(), ClassEntry::asInternalName);
70 }
71
72 Iterable<MethodWrapper> methods() {
73 return clm.methods().stream().map(m -> new MethodWrapper(m)).toList();
74 }
75
76 boolean findField(String name, String sig) {
77 for (var f : clm.fields())
78 if (f.fieldName().stringValue().equals(name) && f.fieldType().stringValue().equals(sig))
79 return true;
80 return false;
81 }
82
83 class MethodWrapper {
84
85 final MethodModel m;
86 private final CodeImpl c;
87 private final List<int[]> exc;
88
89 MethodWrapper(MethodModel m) {
90 this.m = m;
91 this.c = (CodeImpl)m.code().orElse(null);
92 exc = new LinkedList<>();
93 if (c != null) c.iterateExceptionHandlers((start, end, handler, catchType) -> {
94 exc.add(new int[] {start, end, handler, catchType});
95 });
96 }
97
98 ConstantPoolWrapper constantPool() {
99 return cp;
100 }
101
102 boolean isNative() {
103 return m.flags().has(AccessFlag.NATIVE);
104 }
105
106 boolean isAbstract() {
107 return m.flags().has(AccessFlag.ABSTRACT);
108 }
109
110 boolean isBridge() {
111 return m.flags().has(AccessFlag.BRIDGE);
112 }
113
114 boolean isStatic() {
115 return m.flags().has(AccessFlag.STATIC);
116 }
117
118 String name() {
119 return m.methodName().stringValue();
120 }
121
122 int maxStack() {
123 return c == null ? 0 : c.maxStack();
124 }
125
126 int maxLocals() {
127 return c == null ? 0 : c.maxLocals();
128 }
129
130 String descriptor() {
131 return m.methodType().stringValue();
132 }
133
134 String parameters() {
135 return m.methodTypeSymbol().parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(","));
136 }
137
138 int codeLength() {
139 return c == null ? 0 : c.codeLength();
140 }
141
142 byte[] codeArray() {
143 return c == null ? null : c.codeArray();
144 }
145
146 List<int[]> exceptionTable() {
147 return exc;
148 }
149
150 List<LocalVariableInfo> localVariableTable() {
151 var attro = c.findAttribute(Attributes.localVariableTable());
152 return attro.map(lvta -> lvta.localVariables()).orElse(List.of());
153 }
154
155 byte[] stackMapTableRawData() {
156 var attro = c.findAttribute(Attributes.stackMapTable());
157 return attro.map(attr -> ((BoundAttribute) attr).contents()).orElse(null);
158 }
159
160 }
161
162 static class ConstantPoolWrapper {
163
164 private final ConstantPool cp;
165
166 ConstantPoolWrapper(ConstantPool cp) {
167 this.cp = cp;
168 }
169
170 int entryCount() {
171 return cp.size();
172 }
173
174 String classNameAt(int index) {
175 return cp.entryByIndex(index, ClassEntry.class).asInternalName();
176 }
177
178 String dynamicConstantSignatureAt(int index) {
179 return cp.entryByIndex(index, DynamicConstantPoolEntry.class).type().stringValue();
180 }
181
182 int tagAt(int index) {
183 return cp.entryByIndex(index).tag();
184 }
185
186 private NameAndTypeEntry _refNameType(int index) {
187 var e = cp.entryByIndex(index);
188 return (e instanceof DynamicConstantPoolEntry de) ? de.nameAndType() :
189 e != null ? ((MemberRefEntry)e).nameAndType() : null;
190 }
191
192 String refNameAt(int index) {
193 return _refNameType(index).name().stringValue();
194 }
195
196 String refSignatureAt(int index) {
197 return _refNameType(index).type().stringValue();
198 }
199
200 int refClassIndexAt(int index) {
201 return cp.entryByIndex(index, MemberRefEntry.class).owner().index();
202 }
203 }
204 }