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 }