Thu, 12 Jan 2012 15:28:34 +0000
7123100: javac fails with java.lang.StackOverflowError
Summary: Inference of under-constrained type-variables creates erroneous recursive wildcard types
Reviewed-by: jjg
jjg@255 | 1 | /* |
ohair@554 | 2 | * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. |
jjg@255 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
jjg@255 | 4 | * |
jjg@255 | 5 | * This code is free software; you can redistribute it and/or modify it |
jjg@255 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohair@554 | 7 | * published by the Free Software Foundation. Oracle designates this |
jjg@255 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohair@554 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
jjg@255 | 10 | * |
jjg@255 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
jjg@255 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
jjg@255 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
jjg@255 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
jjg@255 | 15 | * accompanied this code). |
jjg@255 | 16 | * |
jjg@255 | 17 | * You should have received a copy of the GNU General Public License version |
jjg@255 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
jjg@255 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
jjg@255 | 20 | * |
ohair@554 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohair@554 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohair@554 | 23 | * questions. |
jjg@255 | 24 | */ |
jjg@255 | 25 | |
jjg@255 | 26 | package com.sun.tools.classfile; |
jjg@255 | 27 | |
jjg@255 | 28 | /** |
jjh@972 | 29 | * See JVMS, chapter 6. |
jjg@255 | 30 | * |
jjg@581 | 31 | * <p><b>This is NOT part of any supported API. |
jjg@581 | 32 | * If you write code that depends on this, you do so at your own risk. |
jjg@255 | 33 | * This code and its internal interfaces are subject to change or |
jjg@255 | 34 | * deletion without notice.</b> |
jjg@255 | 35 | * |
jjg@255 | 36 | * @see Code_attribute#getInstructions |
jjg@255 | 37 | */ |
jjg@255 | 38 | public class Instruction { |
jjg@255 | 39 | /** The kind of an instruction, as determined by the position, size and |
jjg@255 | 40 | * types of its operands. */ |
jjg@255 | 41 | public static enum Kind { |
jjg@255 | 42 | /** Opcode is not followed by any operands. */ |
jjg@255 | 43 | NO_OPERANDS(1), |
jjg@255 | 44 | /** Opcode is followed by a byte indicating a type. */ |
jjg@255 | 45 | ATYPE(2), |
jjg@255 | 46 | /** Opcode is followed by a 2-byte branch offset. */ |
jjg@255 | 47 | BRANCH(3), |
jjg@255 | 48 | /** Opcode is followed by a 4-byte branch offset. */ |
jjg@255 | 49 | BRANCH_W(5), |
jjg@255 | 50 | /** Opcode is followed by a signed byte value. */ |
jjg@255 | 51 | BYTE(2), |
jjg@255 | 52 | /** Opcode is followed by a 1-byte index into the constant pool. */ |
jjg@255 | 53 | CPREF(2), |
jjg@255 | 54 | /** Opcode is followed by a 2-byte index into the constant pool. */ |
jjg@255 | 55 | CPREF_W(3), |
jjg@255 | 56 | /** Opcode is followed by a 2-byte index into the constant pool, |
jjg@255 | 57 | * an unsigned byte value. */ |
jjg@255 | 58 | CPREF_W_UBYTE(4), |
jjg@255 | 59 | /** Opcode is followed by a 2-byte index into the constant pool., |
jjg@255 | 60 | * an unsigned byte value, and a zero byte. */ |
jjg@255 | 61 | CPREF_W_UBYTE_ZERO(5), |
jjg@255 | 62 | /** Opcode is followed by variable number of operands, depending |
jjg@255 | 63 | * on the instruction.*/ |
jjg@255 | 64 | DYNAMIC(-1), |
jjg@255 | 65 | /** Opcode is followed by a 1-byte reference to a local variable. */ |
jjg@255 | 66 | LOCAL(2), |
jjg@255 | 67 | /** Opcode is followed by a 1-byte reference to a local variable, |
jjg@255 | 68 | * and a signed byte value. */ |
jjg@255 | 69 | LOCAL_BYTE(3), |
jjg@255 | 70 | /** Opcode is followed by a signed short value. */ |
jjg@255 | 71 | SHORT(3), |
jjg@255 | 72 | /** Wide opcode is not followed by any operands. */ |
jjg@255 | 73 | WIDE_NO_OPERANDS(2), |
jjg@255 | 74 | /** Wide opcode is followed by a 2-byte index into the constant pool. */ |
jjg@255 | 75 | WIDE_CPREF_W(4), |
jjg@255 | 76 | /** Wide opcode is followed by a 2-byte index into the constant pool, |
jjg@255 | 77 | * and a signed short value. */ |
jjg@255 | 78 | WIDE_CPREF_W_SHORT(6), |
jjg@255 | 79 | /** Opcode was not recognized. */ |
jjg@255 | 80 | UNKNOWN(1); |
jjg@255 | 81 | |
jjg@255 | 82 | Kind(int length) { |
jjg@255 | 83 | this.length = length; |
jjg@255 | 84 | } |
jjg@255 | 85 | |
jjg@255 | 86 | /** The length, in bytes, of this kind of instruction, or -1 is the |
jjg@255 | 87 | * length depends on the specific instruction. */ |
jjg@255 | 88 | public final int length; |
jjg@255 | 89 | }; |
jjg@255 | 90 | |
jjg@255 | 91 | /** A utility visitor to help decode the operands of an instruction. |
jjg@255 | 92 | * @see Instruction#accept */ |
jjg@255 | 93 | public interface KindVisitor<R,P> { |
jjg@255 | 94 | /** See {@link Kind#NO_OPERANDS}, {@link Kind#WIDE_NO_OPERANDS}. */ |
jjg@255 | 95 | R visitNoOperands(Instruction instr, P p); |
jjg@255 | 96 | /** See {@link Kind#ATYPE}. */ |
jjg@255 | 97 | R visitArrayType(Instruction instr, TypeKind kind, P p); |
jjg@255 | 98 | /** See {@link Kind#BRANCH}, {@link Kind#BRANCH_W}. */ |
jjg@255 | 99 | R visitBranch(Instruction instr, int offset, P p); |
jjg@255 | 100 | /** See {@link Kind#CPREF}, {@link Kind#CPREF_W}, {@link Kind#WIDE_CPREF_W}. */ |
jjg@255 | 101 | R visitConstantPoolRef(Instruction instr, int index, P p); |
jjg@255 | 102 | /** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */ |
jjg@255 | 103 | R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p); |
jjg@255 | 104 | /** See {@link Kind#LOCAL}. */ |
jjg@255 | 105 | R visitLocal(Instruction instr, int index, P p); |
jjg@255 | 106 | /** See {@link Kind#LOCAL_UBYTE}. */ |
jjg@255 | 107 | R visitLocalAndValue(Instruction instr, int index, int value, P p); |
jjg@255 | 108 | /** See {@link Kind#DYNAMIC}. */ |
jjg@437 | 109 | R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, P p); |
jjg@255 | 110 | /** See {@link Kind#DYNAMIC}. */ |
jjg@437 | 111 | R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, P p); |
jjg@255 | 112 | /** See {@link Kind#BYTE}, {@link Kind#SHORT}. */ |
jjg@255 | 113 | R visitValue(Instruction instr, int value, P p); |
jjg@255 | 114 | /** Instruction is unrecognized. */ |
jjg@255 | 115 | R visitUnknown(Instruction instr, P p); |
jjg@255 | 116 | |
jjg@255 | 117 | } |
jjg@255 | 118 | |
jjg@255 | 119 | /** The kind of primitive array type to create. |
jjg@255 | 120 | * See JVMS chapter 6, newarray. */ |
jjg@255 | 121 | public static enum TypeKind { |
jjg@255 | 122 | T_BOOLEAN(4, "boolean"), |
jjg@255 | 123 | T_CHAR(5, "char"), |
jjg@255 | 124 | T_FLOAT(6, "float"), |
jjg@255 | 125 | T_DOUBLE(7, "double"), |
jjg@255 | 126 | T_BYTE(8, "byte"), |
jjg@255 | 127 | T_SHORT(9, "short"), |
jjg@255 | 128 | T_INT (10, "int"), |
jjg@255 | 129 | T_LONG (11, "long"); |
jjg@255 | 130 | TypeKind(int value, String name) { |
jjg@255 | 131 | this.value = value; |
jjg@255 | 132 | this.name = name; |
jjg@255 | 133 | } |
jjg@255 | 134 | |
jjg@255 | 135 | public static TypeKind get(int value) { |
jjg@255 | 136 | switch (value) { |
jjg@255 | 137 | case 4: return T_BOOLEAN; |
jjg@255 | 138 | case 5: return T_CHAR; |
jjg@255 | 139 | case 6: return T_FLOAT; |
jjg@255 | 140 | case 7: return T_DOUBLE; |
jjg@255 | 141 | case 8: return T_BYTE; |
jjg@255 | 142 | case 9: return T_SHORT; |
jjg@255 | 143 | case 10: return T_INT; |
jjg@255 | 144 | case 11: return T_LONG; |
jjg@255 | 145 | default: return null; |
jjg@255 | 146 | } |
jjg@255 | 147 | } |
jjg@255 | 148 | |
jjg@255 | 149 | public final int value; |
jjg@255 | 150 | public final String name; |
jjg@255 | 151 | } |
jjg@255 | 152 | |
jjg@255 | 153 | /** An instruction is defined by its position in a bytecode array. */ |
jjg@255 | 154 | public Instruction(byte[] bytes, int pc) { |
jjg@255 | 155 | this.bytes = bytes; |
jjg@255 | 156 | this.pc = pc; |
jjg@255 | 157 | } |
jjg@255 | 158 | |
jjg@255 | 159 | /** Get the position of the instruction within the bytecode array. */ |
jjg@255 | 160 | public int getPC() { |
jjg@255 | 161 | return pc; |
jjg@255 | 162 | } |
jjg@255 | 163 | |
jjg@255 | 164 | /** Get a byte value, relative to the start of this instruction. */ |
jjg@255 | 165 | public int getByte(int offset) { |
jjg@255 | 166 | return bytes[pc + offset]; |
jjg@255 | 167 | } |
jjg@255 | 168 | |
jjg@255 | 169 | /** Get an unsigned byte value, relative to the start of this instruction. */ |
jjg@255 | 170 | public int getUnsignedByte(int offset) { |
jjg@255 | 171 | return getByte(offset) & 0xff; |
jjg@255 | 172 | } |
jjg@255 | 173 | |
jjg@255 | 174 | /** Get a 2-byte value, relative to the start of this instruction. */ |
jjg@255 | 175 | public int getShort(int offset) { |
jjg@255 | 176 | return (getByte(offset) << 8) | getUnsignedByte(offset + 1); |
jjg@255 | 177 | } |
jjg@255 | 178 | |
jjg@255 | 179 | /** Get a unsigned 2-byte value, relative to the start of this instruction. */ |
jjg@255 | 180 | public int getUnsignedShort(int offset) { |
jjg@255 | 181 | return getShort(offset) & 0xFFFF; |
jjg@255 | 182 | } |
jjg@255 | 183 | |
jjg@255 | 184 | /** Get a 4-byte value, relative to the start of this instruction. */ |
jjg@255 | 185 | public int getInt(int offset) { |
jjg@255 | 186 | return (getShort(offset) << 16) | (getUnsignedShort(offset + 2)); |
jjg@255 | 187 | } |
jjg@255 | 188 | |
jjg@255 | 189 | /** Get the Opcode for this instruction, or null if the instruction is |
jjg@255 | 190 | * unrecognized. */ |
jjg@255 | 191 | public Opcode getOpcode() { |
jjg@255 | 192 | int b = getUnsignedByte(0); |
jjg@255 | 193 | switch (b) { |
jjg@255 | 194 | case Opcode.NONPRIV: |
jjg@255 | 195 | case Opcode.PRIV: |
jjg@255 | 196 | case Opcode.WIDE: |
jjg@255 | 197 | return Opcode.get(b, getUnsignedByte(1)); |
jjg@255 | 198 | } |
jjg@255 | 199 | return Opcode.get(b); |
jjg@255 | 200 | } |
jjg@255 | 201 | |
jjg@255 | 202 | /** Get the mnemonic for this instruction, or a default string if the |
jjg@255 | 203 | * instruction is unrecognized. */ |
jjg@255 | 204 | public String getMnemonic() { |
jjg@255 | 205 | Opcode opcode = getOpcode(); |
jjg@255 | 206 | if (opcode == null) |
jjg@255 | 207 | return "bytecode " + getUnsignedByte(0); |
jjg@255 | 208 | else |
jjg@255 | 209 | return opcode.toString().toLowerCase(); |
jjg@255 | 210 | } |
jjg@255 | 211 | |
jjg@255 | 212 | /** Get the length, in bytes, of this instruction, including the opcode |
jjg@255 | 213 | * and all its operands. */ |
jjg@255 | 214 | public int length() { |
jjg@255 | 215 | Opcode opcode = getOpcode(); |
jjg@255 | 216 | if (opcode == null) |
jjg@255 | 217 | return 1; |
jjg@255 | 218 | |
jjg@255 | 219 | switch (opcode) { |
jjg@255 | 220 | case TABLESWITCH: { |
jjg@255 | 221 | int pad = align(pc + 1) - pc; |
jjg@255 | 222 | int low = getInt(pad + 4); |
jjg@255 | 223 | int high = getInt(pad + 8); |
jjg@255 | 224 | return pad + 12 + 4 * (high - low + 1); |
jjg@255 | 225 | } |
jjg@255 | 226 | case LOOKUPSWITCH: { |
jjg@255 | 227 | int pad = align(pc + 1) - pc; |
jjg@255 | 228 | int npairs = getInt(pad + 4); |
jjg@255 | 229 | return pad + 8 + 8 * npairs; |
jjg@255 | 230 | |
jjg@255 | 231 | } |
jjg@255 | 232 | default: |
jjg@255 | 233 | return opcode.kind.length; |
jjg@255 | 234 | } |
jjg@255 | 235 | } |
jjg@255 | 236 | |
jjg@255 | 237 | /** Get the {@link Kind} of this instruction. */ |
jjg@255 | 238 | public Kind getKind() { |
jjg@255 | 239 | Opcode opcode = getOpcode(); |
jjg@255 | 240 | return (opcode != null ? opcode.kind : Kind.UNKNOWN); |
jjg@255 | 241 | } |
jjg@255 | 242 | |
jjg@255 | 243 | /** Invoke a method on the visitor according to the kind of this |
jjg@255 | 244 | * instruction, passing in the decoded operands for the instruction. */ |
jjg@255 | 245 | public <R,P> R accept(KindVisitor<R,P> visitor, P p) { |
jjg@255 | 246 | switch (getKind()) { |
jjg@255 | 247 | case NO_OPERANDS: |
jjg@255 | 248 | return visitor.visitNoOperands(this, p); |
jjg@255 | 249 | |
jjg@255 | 250 | case ATYPE: |
jjg@255 | 251 | return visitor.visitArrayType( |
jjg@255 | 252 | this, TypeKind.get(getUnsignedByte(1)), p); |
jjg@255 | 253 | |
jjg@255 | 254 | case BRANCH: |
jjg@255 | 255 | return visitor.visitBranch(this, getShort(1), p); |
jjg@255 | 256 | |
jjg@255 | 257 | case BRANCH_W: |
jjg@255 | 258 | return visitor.visitBranch(this, getInt(1), p); |
jjg@255 | 259 | |
jjg@255 | 260 | case BYTE: |
jjg@255 | 261 | return visitor.visitValue(this, getByte(1), p); |
jjg@255 | 262 | |
jjg@255 | 263 | case CPREF: |
jjg@255 | 264 | return visitor.visitConstantPoolRef(this, getUnsignedByte(1), p); |
jjg@255 | 265 | |
jjg@255 | 266 | case CPREF_W: |
jjg@255 | 267 | return visitor.visitConstantPoolRef(this, getUnsignedShort(1), p); |
jjg@255 | 268 | |
jjg@255 | 269 | case CPREF_W_UBYTE: |
jjg@255 | 270 | case CPREF_W_UBYTE_ZERO: |
jjg@255 | 271 | return visitor.visitConstantPoolRefAndValue( |
jjg@255 | 272 | this, getUnsignedShort(1), getUnsignedByte(3), p); |
jjg@255 | 273 | |
jjg@255 | 274 | case DYNAMIC: { |
jjg@255 | 275 | switch (getOpcode()) { |
jjg@255 | 276 | case TABLESWITCH: { |
jjg@255 | 277 | int pad = align(pc + 1) - pc; |
jjg@255 | 278 | int default_ = getInt(pad); |
jjg@255 | 279 | int low = getInt(pad + 4); |
jjg@255 | 280 | int high = getInt(pad + 8); |
jjg@255 | 281 | int[] values = new int[high - low + 1]; |
jjg@255 | 282 | for (int i = 0; i < values.length; i++) |
jjg@255 | 283 | values[i] = getInt(pad + 12 + 4 * i); |
jjg@255 | 284 | return visitor.visitTableSwitch( |
jjg@437 | 285 | this, default_, low, high, values, p); |
jjg@255 | 286 | } |
jjg@255 | 287 | case LOOKUPSWITCH: { |
jjg@255 | 288 | int pad = align(pc + 1) - pc; |
jjg@255 | 289 | int default_ = getInt(pad); |
jjg@255 | 290 | int npairs = getInt(pad + 4); |
jjg@255 | 291 | int[] matches = new int[npairs]; |
jjg@255 | 292 | int[] offsets = new int[npairs]; |
jjg@255 | 293 | for (int i = 0; i < npairs; i++) { |
jjg@255 | 294 | matches[i] = getInt(pad + 8 + i * 8); |
jjg@255 | 295 | offsets[i] = getInt(pad + 12 + i * 8); |
jjg@255 | 296 | } |
jjg@255 | 297 | return visitor.visitLookupSwitch( |
jjg@437 | 298 | this, default_, npairs, matches, offsets, p); |
jjg@255 | 299 | } |
jjg@255 | 300 | default: |
jjg@255 | 301 | throw new IllegalStateException(); |
jjg@255 | 302 | } |
jjg@255 | 303 | } |
jjg@255 | 304 | |
jjg@255 | 305 | case LOCAL: |
jjg@255 | 306 | return visitor.visitLocal(this, getUnsignedByte(1), p); |
jjg@255 | 307 | |
jjg@255 | 308 | case LOCAL_BYTE: |
jjg@255 | 309 | return visitor.visitLocalAndValue( |
jjg@255 | 310 | this, getUnsignedByte(1), getByte(2), p); |
jjg@255 | 311 | |
jjg@255 | 312 | case SHORT: |
jjg@255 | 313 | return visitor.visitValue(this, getShort(1), p); |
jjg@255 | 314 | |
jjg@255 | 315 | case WIDE_NO_OPERANDS: |
jjg@255 | 316 | return visitor.visitNoOperands(this, p); |
jjg@255 | 317 | |
jjg@255 | 318 | case WIDE_CPREF_W: |
jjg@255 | 319 | return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p); |
jjg@255 | 320 | |
jjg@255 | 321 | case WIDE_CPREF_W_SHORT: |
jjg@255 | 322 | return visitor.visitConstantPoolRefAndValue( |
jjg@255 | 323 | this, getUnsignedShort(2), getUnsignedByte(4), p); |
jjg@255 | 324 | |
jjg@255 | 325 | case UNKNOWN: |
jjg@255 | 326 | return visitor.visitUnknown(this, p); |
jjg@255 | 327 | |
jjg@255 | 328 | default: |
jjg@255 | 329 | throw new IllegalStateException(); |
jjg@255 | 330 | } |
jjg@255 | 331 | } |
jjg@255 | 332 | |
jjg@255 | 333 | private static int align(int n) { |
jjg@255 | 334 | return (n + 3) & ~3; |
jjg@255 | 335 | } |
jjg@255 | 336 | |
jjg@255 | 337 | private byte[] bytes; |
jjg@255 | 338 | private int pc; |
jjg@255 | 339 | } |