1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.tree.analysis; 29 30 import java.util.HashSet; 31 import java.util.List; 32 import java.util.Set; 33 import org.objectweb.asm.Opcodes; 34 import org.objectweb.asm.Type; 35 import org.objectweb.asm.tree.AbstractInsnNode; 36 import org.objectweb.asm.tree.FieldInsnNode; 37 import org.objectweb.asm.tree.InvokeDynamicInsnNode; 38 import org.objectweb.asm.tree.LdcInsnNode; 39 import org.objectweb.asm.tree.MethodInsnNode; 40 41 /** 42 * An {@link Interpreter} for {@link SourceValue} values. 43 * 44 * @author Eric Bruneton 45 */ 46 public class SourceInterpreter extends Interpreter<SourceValue> implements Opcodes { 47 48 /** 49 * Constructs a new {@link SourceInterpreter} for the latest ASM API version. <i>Subclasses must 50 * not use this constructor</i>. Instead, they must use the {@link #SourceInterpreter(int)} 51 * version. 52 */ SourceInterpreter()53 public SourceInterpreter() { 54 super(/* latest api = */ ASM9); 55 if (getClass() != SourceInterpreter.class) { 56 throw new IllegalStateException(); 57 } 58 } 59 60 /** 61 * Constructs a new {@link SourceInterpreter}. 62 * 63 * @param api the ASM API version supported by this interpreter. Must be one of the {@code 64 * ASM}<i>x</i> values in {@link Opcodes}. 65 */ SourceInterpreter(final int api)66 protected SourceInterpreter(final int api) { 67 super(api); 68 } 69 70 @Override newValue(final Type type)71 public SourceValue newValue(final Type type) { 72 if (type == Type.VOID_TYPE) { 73 return null; 74 } 75 return new SourceValue(type == null ? 1 : type.getSize()); 76 } 77 78 @Override newOperation(final AbstractInsnNode insn)79 public SourceValue newOperation(final AbstractInsnNode insn) { 80 int size; 81 switch (insn.getOpcode()) { 82 case LCONST_0: 83 case LCONST_1: 84 case DCONST_0: 85 case DCONST_1: 86 size = 2; 87 break; 88 case LDC: 89 Object value = ((LdcInsnNode) insn).cst; 90 size = value instanceof Long || value instanceof Double ? 2 : 1; 91 break; 92 case GETSTATIC: 93 size = Type.getType(((FieldInsnNode) insn).desc).getSize(); 94 break; 95 default: 96 size = 1; 97 break; 98 } 99 return new SourceValue(size, insn); 100 } 101 102 @Override copyOperation(final AbstractInsnNode insn, final SourceValue value)103 public SourceValue copyOperation(final AbstractInsnNode insn, final SourceValue value) { 104 return new SourceValue(value.getSize(), insn); 105 } 106 107 @Override unaryOperation(final AbstractInsnNode insn, final SourceValue value)108 public SourceValue unaryOperation(final AbstractInsnNode insn, final SourceValue value) { 109 int size; 110 switch (insn.getOpcode()) { 111 case LNEG: 112 case DNEG: 113 case I2L: 114 case I2D: 115 case L2D: 116 case F2L: 117 case F2D: 118 case D2L: 119 size = 2; 120 break; 121 case GETFIELD: 122 size = Type.getType(((FieldInsnNode) insn).desc).getSize(); 123 break; 124 default: 125 size = 1; 126 break; 127 } 128 return new SourceValue(size, insn); 129 } 130 131 @Override binaryOperation( final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2)132 public SourceValue binaryOperation( 133 final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2) { 134 int size; 135 switch (insn.getOpcode()) { 136 case LALOAD: 137 case DALOAD: 138 case LADD: 139 case DADD: 140 case LSUB: 141 case DSUB: 142 case LMUL: 143 case DMUL: 144 case LDIV: 145 case DDIV: 146 case LREM: 147 case DREM: 148 case LSHL: 149 case LSHR: 150 case LUSHR: 151 case LAND: 152 case LOR: 153 case LXOR: 154 size = 2; 155 break; 156 default: 157 size = 1; 158 break; 159 } 160 return new SourceValue(size, insn); 161 } 162 163 @Override ternaryOperation( final AbstractInsnNode insn, final SourceValue value1, final SourceValue value2, final SourceValue value3)164 public SourceValue ternaryOperation( 165 final AbstractInsnNode insn, 166 final SourceValue value1, 167 final SourceValue value2, 168 final SourceValue value3) { 169 return new SourceValue(1, insn); 170 } 171 172 @Override naryOperation( final AbstractInsnNode insn, final List<? extends SourceValue> values)173 public SourceValue naryOperation( 174 final AbstractInsnNode insn, final List<? extends SourceValue> values) { 175 int size; 176 int opcode = insn.getOpcode(); 177 if (opcode == MULTIANEWARRAY) { 178 size = 1; 179 } else if (opcode == INVOKEDYNAMIC) { 180 size = Type.getReturnType(((InvokeDynamicInsnNode) insn).desc).getSize(); 181 } else { 182 size = Type.getReturnType(((MethodInsnNode) insn).desc).getSize(); 183 } 184 return new SourceValue(size, insn); 185 } 186 187 @Override returnOperation( final AbstractInsnNode insn, final SourceValue value, final SourceValue expected)188 public void returnOperation( 189 final AbstractInsnNode insn, final SourceValue value, final SourceValue expected) { 190 // Nothing to do. 191 } 192 193 @Override merge(final SourceValue value1, final SourceValue value2)194 public SourceValue merge(final SourceValue value1, final SourceValue value2) { 195 if (value1.insns instanceof SmallSet && value2.insns instanceof SmallSet) { 196 Set<AbstractInsnNode> setUnion = 197 ((SmallSet<AbstractInsnNode>) value1.insns) 198 .union((SmallSet<AbstractInsnNode>) value2.insns); 199 if (setUnion == value1.insns && value1.size == value2.size) { 200 return value1; 201 } else { 202 return new SourceValue(Math.min(value1.size, value2.size), setUnion); 203 } 204 } 205 if (value1.size != value2.size || !containsAll(value1.insns, value2.insns)) { 206 HashSet<AbstractInsnNode> setUnion = new HashSet<>(); 207 setUnion.addAll(value1.insns); 208 setUnion.addAll(value2.insns); 209 return new SourceValue(Math.min(value1.size, value2.size), setUnion); 210 } 211 return value1; 212 } 213 containsAll(final Set<E> self, final Set<E> other)214 private static <E> boolean containsAll(final Set<E> self, final Set<E> other) { 215 if (self.size() < other.size()) { 216 return false; 217 } 218 return self.containsAll(other); 219 } 220 } 221