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.FieldModel;
 31 import java.lang.classfile.MethodModel;
 32 import java.lang.classfile.attribute.LocalVariableInfo;
 33 import java.lang.classfile.constantpool.ClassEntry;
 34 import java.lang.classfile.constantpool.ConstantPool;
 35 import java.lang.classfile.constantpool.DynamicConstantPoolEntry;
 36 import java.lang.classfile.constantpool.MemberRefEntry;
 37 import java.lang.classfile.constantpool.NameAndTypeEntry;
 38 import java.lang.constant.ClassDesc;
 39 import java.lang.reflect.AccessFlag;
 40 import java.util.LinkedList;
 41 import java.util.List;
 42 import java.util.stream.Collectors;
 43 
 44 import jdk.internal.classfile.impl.BoundAttribute;
 45 import jdk.internal.classfile.impl.CodeImpl;
 46 import jdk.internal.classfile.impl.Util;
 47 
 48 public final class VerificationWrapper {
 49     final ClassModel clm;
 50     private final ConstantPoolWrapper cp;
 51 
 52     public VerificationWrapper(ClassModel clm) {
 53         this.clm = clm;
 54         this.cp = new ConstantPoolWrapper(clm.constantPool());
 55      }
 56 
 57     String thisClassName() {
 58         return clm.thisClass().asInternalName();
 59     }
 60 
 61     int majorVersion() {
 62         return clm.majorVersion();
 63     }
 64 
 65     String superclassName() {
 66         return clm.superclass().map(ClassEntry::asInternalName).orElse(null);
 67     }
 68 
 69     Iterable<String> interfaceNames() {
 70         return Util.mappedList(clm.interfaces(), ClassEntry::asInternalName);
 71     }
 72 
 73     Iterable<MethodWrapper> methods() {
 74         return clm.methods().stream().map(m -> new MethodWrapper(m)).toList();
 75     }
 76 
 77     FieldModel findField(String name, String sig) {
 78         for (var f : clm.fields())
 79             if (f.fieldName().stringValue().equals(name) && f.fieldType().stringValue().equals(sig))
 80                 return f;
 81         return null;
 82     }
 83 
 84     class MethodWrapper {
 85 
 86         final MethodModel m;
 87         private final CodeImpl c;
 88         private final List<int[]> exc;
 89 
 90         MethodWrapper(MethodModel m) {
 91             this.m = m;
 92             this.c = (CodeImpl)m.code().orElse(null);
 93             exc = new LinkedList<>();
 94             if (c != null) c.iterateExceptionHandlers((start, end, handler, catchType) -> {
 95                 exc.add(new int[] {start, end, handler, catchType});
 96             });
 97         }
 98 
 99         ConstantPoolWrapper constantPool() {
100             return cp;
101         }
102 
103         boolean isNative() {
104             return m.flags().has(AccessFlag.NATIVE);
105         }
106 
107         boolean isAbstract() {
108             return m.flags().has(AccessFlag.ABSTRACT);
109         }
110 
111         boolean isBridge() {
112             return m.flags().has(AccessFlag.BRIDGE);
113         }
114 
115         boolean isStatic() {
116             return m.flags().has(AccessFlag.STATIC);
117         }
118 
119         String name() {
120             return m.methodName().stringValue();
121         }
122 
123         int maxStack() {
124             return c == null ? 0 : c.maxStack();
125         }
126 
127         int maxLocals() {
128             return c == null ? 0 : c.maxLocals();
129         }
130 
131         String descriptor() {
132             return m.methodType().stringValue();
133         }
134 
135         String parameters() {
136             return m.methodTypeSymbol().parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(","));
137         }
138 
139         int codeLength() {
140             return c == null ? 0 : c.codeLength();
141         }
142 
143         byte[] codeArray() {
144             return c == null ? null : c.codeArray();
145         }
146 
147         List<int[]> exceptionTable() {
148             return exc;
149         }
150 
151         List<LocalVariableInfo> localVariableTable() {
152             var attro = c.findAttribute(Attributes.localVariableTable());
153             return attro.map(lvta -> lvta.localVariables()).orElse(List.of());
154         }
155 
156         byte[] stackMapTableRawData() {
157             var attro = c.findAttribute(Attributes.stackMapTable());
158             return attro.map(attr -> ((BoundAttribute) attr).contents()).orElse(null);
159         }
160 
161     }
162 
163     static class ConstantPoolWrapper {
164 
165         final ConstantPool cp;
166 
167         ConstantPoolWrapper(ConstantPool cp) {
168             this.cp = cp;
169         }
170 
171         int entryCount() {
172             return cp.size();
173         }
174 
175         String classNameAt(int index) {
176             return cp.entryByIndex(index, ClassEntry.class).asInternalName();
177         }
178 
179         String dynamicConstantSignatureAt(int index) {
180             return cp.entryByIndex(index, DynamicConstantPoolEntry.class).type().stringValue();
181         }
182 
183         int tagAt(int index) {
184             return cp.entryByIndex(index).tag();
185         }
186 
187         private NameAndTypeEntry _refNameType(int index) {
188             var e = cp.entryByIndex(index);
189             return (e instanceof DynamicConstantPoolEntry de) ? de.nameAndType() :
190                     e != null ? ((MemberRefEntry)e).nameAndType() : null;
191         }
192 
193         String refNameAt(int index) {
194             return _refNameType(index).name().stringValue();
195         }
196 
197         String refSignatureAt(int index) {
198             return _refNameType(index).type().stringValue();
199         }
200 
201         int refClassIndexAt(int index) {
202             return cp.entryByIndex(index, MemberRefEntry.class).owner().index();
203         }
204 
205         boolean is_within_bounds(int i) {
206             return i >= 1 && i <= cp.size();
207         }
208     }
209 }