001/*** 002 * ASM: a very small and fast Java bytecode manipulation framework 003 * Copyright (c) 2000-2011 INRIA, France Telecom 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or without 007 * modification, are permitted provided that the following conditions 008 * are met: 009 * 1. Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 2. Redistributions in binary form must reproduce the above copyright 012 * notice, this list of conditions and the following disclaimer in the 013 * documentation and/or other materials provided with the distribution. 014 * 3. Neither the name of the copyright holders nor the names of its 015 * contributors may be used to endorse or promote products derived from 016 * this software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 028 * THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package io.ebean.enhance.asm.tree.analysis; 031 032import io.ebean.enhance.asm.Type; 033 034import java.util.List; 035 036/** 037 * An extended {@link BasicVerifier} that performs more precise verifications. 038 * This verifier computes exact class types, instead of using a single "object 039 * reference" type (as done in the {@link BasicVerifier}). 040 * 041 * @author Eric Bruneton 042 * @author Bing Ran 043 */ 044public class SimpleVerifier extends BasicVerifier { 045 046 /** 047 * The class that is verified. 048 */ 049 private final Type currentClass; 050 051 /** 052 * The super class of the class that is verified. 053 */ 054 private final Type currentSuperClass; 055 056 /** 057 * The interfaces implemented by the class that is verified. 058 */ 059 private final List<Type> currentClassInterfaces; 060 061 /** 062 * If the class that is verified is an interface. 063 */ 064 private final boolean isInterface; 065 066 /** 067 * The loader to use for referenced classes. 068 */ 069 private ClassLoader loader = getClass().getClassLoader(); 070 071 /** 072 * Constructs a new {@link SimpleVerifier}. 073 */ 074 public SimpleVerifier() { 075 this(null, null, false); 076 } 077 078 /** 079 * Constructs a new {@link SimpleVerifier} to verify a specific class. This 080 * class will not be loaded into the JVM since it may be incorrect. 081 * 082 * @param currentClass 083 * the class that is verified. 084 * @param currentSuperClass 085 * the super class of the class that is verified. 086 * @param isInterface 087 * if the class that is verified is an interface. 088 */ 089 public SimpleVerifier(final Type currentClass, 090 final Type currentSuperClass, final boolean isInterface) { 091 this(currentClass, currentSuperClass, null, isInterface); 092 } 093 094 /** 095 * Constructs a new {@link SimpleVerifier} to verify a specific class. This 096 * class will not be loaded into the JVM since it may be incorrect. 097 * 098 * @param currentClass 099 * the class that is verified. 100 * @param currentSuperClass 101 * the super class of the class that is verified. 102 * @param currentClassInterfaces 103 * the interfaces implemented by the class that is verified. 104 * @param isInterface 105 * if the class that is verified is an interface. 106 */ 107 public SimpleVerifier(final Type currentClass, 108 final Type currentSuperClass, 109 final List<Type> currentClassInterfaces, final boolean isInterface) { 110 this(ASM6, currentClass, currentSuperClass, currentClassInterfaces, 111 isInterface); 112 } 113 114 protected SimpleVerifier(final int api, final Type currentClass, 115 final Type currentSuperClass, 116 final List<Type> currentClassInterfaces, final boolean isInterface) { 117 super(api); 118 this.currentClass = currentClass; 119 this.currentSuperClass = currentSuperClass; 120 this.currentClassInterfaces = currentClassInterfaces; 121 this.isInterface = isInterface; 122 } 123 124 /** 125 * Set the <code>ClassLoader</code> which will be used to load referenced 126 * classes. This is useful if you are verifying multiple interdependent 127 * classes. 128 * 129 * @param loader 130 * a <code>ClassLoader</code> to use 131 */ 132 public void setClassLoader(final ClassLoader loader) { 133 this.loader = loader; 134 } 135 136 @Override 137 public BasicValue newValue(final Type type) { 138 if (type == null) { 139 return BasicValue.UNINITIALIZED_VALUE; 140 } 141 142 boolean isArray = type.getSort() == Type.ARRAY; 143 if (isArray) { 144 switch (type.getElementType().getSort()) { 145 case Type.BOOLEAN: 146 case Type.CHAR: 147 case Type.BYTE: 148 case Type.SHORT: 149 return new BasicValue(type); 150 } 151 } 152 153 BasicValue v = super.newValue(type); 154 if (BasicValue.REFERENCE_VALUE.equals(v)) { 155 if (isArray) { 156 v = newValue(type.getElementType()); 157 String desc = v.getType().getDescriptor(); 158 for (int i = 0; i < type.getDimensions(); ++i) { 159 desc = '[' + desc; 160 } 161 v = new BasicValue(Type.getType(desc)); 162 } else { 163 v = new BasicValue(type); 164 } 165 } 166 return v; 167 } 168 169 @Override 170 protected boolean isArrayValue(final BasicValue value) { 171 Type t = value.getType(); 172 return t != null 173 && ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY); 174 } 175 176 @Override 177 protected BasicValue getElementValue(final BasicValue objectArrayValue) 178 throws AnalyzerException { 179 Type arrayType = objectArrayValue.getType(); 180 if (arrayType != null) { 181 if (arrayType.getSort() == Type.ARRAY) { 182 return newValue(Type.getType(arrayType.getDescriptor() 183 .substring(1))); 184 } else if ("Lnull;".equals(arrayType.getDescriptor())) { 185 return objectArrayValue; 186 } 187 } 188 throw new Error("Internal error"); 189 } 190 191 @Override 192 protected boolean isSubTypeOf(final BasicValue value, 193 final BasicValue expected) { 194 Type expectedType = expected.getType(); 195 Type type = value.getType(); 196 switch (expectedType.getSort()) { 197 case Type.INT: 198 case Type.FLOAT: 199 case Type.LONG: 200 case Type.DOUBLE: 201 return type.equals(expectedType); 202 case Type.ARRAY: 203 case Type.OBJECT: 204 if ("Lnull;".equals(type.getDescriptor())) { 205 return true; 206 } else if (type.getSort() == Type.OBJECT 207 || type.getSort() == Type.ARRAY) { 208 return isAssignableFrom(expectedType, type); 209 } else { 210 return false; 211 } 212 default: 213 throw new Error("Internal error"); 214 } 215 } 216 217 @Override 218 public BasicValue merge(final BasicValue v, final BasicValue w) { 219 if (!v.equals(w)) { 220 Type t = v.getType(); 221 Type u = w.getType(); 222 if (t != null 223 && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) { 224 if (u != null 225 && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) { 226 if ("Lnull;".equals(t.getDescriptor())) { 227 return w; 228 } 229 if ("Lnull;".equals(u.getDescriptor())) { 230 return v; 231 } 232 if (isAssignableFrom(t, u)) { 233 return v; 234 } 235 if (isAssignableFrom(u, t)) { 236 return w; 237 } 238 // TODO case of array classes of the same dimension 239 // TODO should we look also for a common super interface? 240 // problem: there may be several possible common super 241 // interfaces 242 do { 243 if (t == null || isInterface(t)) { 244 return BasicValue.REFERENCE_VALUE; 245 } 246 t = getSuperClass(t); 247 if (isAssignableFrom(t, u)) { 248 return newValue(t); 249 } 250 } while (true); 251 } 252 } 253 return BasicValue.UNINITIALIZED_VALUE; 254 } 255 return v; 256 } 257 258 protected boolean isInterface(final Type t) { 259 if (currentClass != null && t.equals(currentClass)) { 260 return isInterface; 261 } 262 return getClass(t).isInterface(); 263 } 264 265 protected Type getSuperClass(final Type t) { 266 if (currentClass != null && t.equals(currentClass)) { 267 return currentSuperClass; 268 } 269 Class<?> c = getClass(t).getSuperclass(); 270 return c == null ? null : Type.getType(c); 271 } 272 273 protected boolean isAssignableFrom(final Type t, final Type u) { 274 if (t.equals(u)) { 275 return true; 276 } 277 if (currentClass != null && t.equals(currentClass)) { 278 if (getSuperClass(u) == null) { 279 return false; 280 } else { 281 if (isInterface) { 282 return u.getSort() == Type.OBJECT 283 || u.getSort() == Type.ARRAY; 284 } 285 return isAssignableFrom(t, getSuperClass(u)); 286 } 287 } 288 if (currentClass != null && u.equals(currentClass)) { 289 if (isAssignableFrom(t, currentSuperClass)) { 290 return true; 291 } 292 if (currentClassInterfaces != null) { 293 for (int i = 0; i < currentClassInterfaces.size(); ++i) { 294 Type v = currentClassInterfaces.get(i); 295 if (isAssignableFrom(t, v)) { 296 return true; 297 } 298 } 299 } 300 return false; 301 } 302 Class<?> tc = getClass(t); 303 if (tc.isInterface()) { 304 tc = Object.class; 305 } 306 return tc.isAssignableFrom(getClass(u)); 307 } 308 309 protected Class<?> getClass(final Type t) { 310 try { 311 if (t.getSort() == Type.ARRAY) { 312 return Class.forName(t.getDescriptor().replace('/', '.'), 313 false, loader); 314 } 315 return Class.forName(t.getClassName(), false, loader); 316 } catch (ClassNotFoundException e) { 317 throw new RuntimeException(e.toString()); 318 } 319 } 320}