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