Showing the changes to java/pkg/sun/tools/asm/Instruction.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,831 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1994, 2003, 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 sun.tools.asm; | ||
| 27 | |||
| 28 | import sun.tools.java.*; | ||
| 29 | import java.util.Enumeration; | ||
| 30 | import java.io.IOException; | ||
| 31 | import java.io.DataOutputStream; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * An Java instruction | ||
| 35 | * | ||
| 36 | * WARNING: The contents of this source file are not part of any | ||
| 37 | * supported API. Code that depends on them does so at its own risk: | ||
| 38 | * they are subject to change or removal without notice. | ||
| 39 | */ | ||
| 40 | public | ||
| 41 | class Instruction implements Constants { | ||
| 42 | long where; | ||
| 43 | int pc; | ||
| 44 | int opc; | ||
| 45 | Object value; | ||
| 46 | Instruction next; | ||
| 47 | //JCOV | ||
| 48 | boolean flagCondInverted; /* if true, the condition is reversed | ||
| 49 | relatively of source code */ | ||
| 50 | boolean flagNoCovered = false; /* if true, the command will | ||
| 51 | ignored for coverage */ | ||
| 52 | |||
| 53 | |||
| 54 | /** | ||
| 55 | * Constructor | ||
| 56 | */ | ||
| 57 | public Instruction(long where, int opc, Object value, boolean flagCondInverted) { | ||
| 58 | this.where = where; | ||
| 59 | this.opc = opc; | ||
| 60 | this.value = value; | ||
| 61 | this.flagCondInverted = flagCondInverted; | ||
| 62 | } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Constructor | ||
| 66 | */ | ||
| 67 | public Instruction(boolean flagNoCovered, long where, int opc, Object value) { | ||
| 68 | this.where = where; | ||
| 69 | this.opc = opc; | ||
| 70 | this.value = value; | ||
| 71 | this.flagNoCovered = flagNoCovered; | ||
| 72 | } | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Constructor | ||
| 76 | */ | ||
| 77 | public Instruction(long where, int opc, boolean flagNoCovered) { | ||
| 78 | this.where = where; | ||
| 79 | this.opc = opc; | ||
| 80 | this.flagNoCovered = flagNoCovered; | ||
| 81 | } | ||
| 82 | //end JCOV | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Constructor | ||
| 86 | */ | ||
| 87 | public Instruction(long where, int opc, Object value) { | ||
| 88 | this.where = where; | ||
| 89 | this.opc = opc; | ||
| 90 | this.value = value; | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | * When deciding between a lookupswitch and a tableswitch, this | ||
| 95 | * value is used in determining how much size increase is | ||
| 96 | * acceptable. | ||
| 97 | */ | ||
| 98 | public static final double SWITCHRATIO; | ||
| 99 | |||
| 100 | static { | ||
| 101 | // Set SWITCHRATIO from the property javac.switchratio | ||
| 102 | // if it exists and is reasonable. Otherwise, set | ||
| 103 | // SWITCHRATIO to 1.5, meaning that we will accept a 1.5x | ||
| 104 | // blowup (for the instruction) to use a tableswitch instead | ||
| 105 | // of a lookupswitch. | ||
| 106 | double ratio = 1.5; | ||
| 107 | String valStr = System.getProperty("javac.switchratio"); | ||
| 108 | if (valStr != null) { | ||
| 109 | try { | ||
| 110 | double temp = Double.valueOf(valStr).doubleValue(); | ||
| 111 | if (!(Double.isNaN(temp) || temp < 0.0)) { | ||
| 112 | ratio = temp; | ||
| 113 | } | ||
| 114 | } catch (NumberFormatException ee) {} | ||
| 115 | } | ||
| 116 | SWITCHRATIO = ratio; | ||
| 117 | } | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Accessor | ||
| 121 | */ | ||
| 122 | public int getOpcode() { | ||
| 123 | return pc; | ||
| 124 | } | ||
| 125 | |||
| 126 | public Object getValue() { | ||
| 127 | return value; | ||
| 128 | } | ||
| 129 | |||
| 130 | public void setValue(Object value) { | ||
| 131 | this.value = value; | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | /** | ||
| 136 | * Optimize | ||
| 137 | */ | ||
| 138 | void optimize(Environment env) { | ||
| 139 | switch (opc) { | ||
| 140 | case opc_istore: case opc_lstore: case opc_fstore: | ||
| 141 | case opc_dstore: case opc_astore: | ||
| 142 | // Don't keep the LocalVariable info around, unless we | ||
| 143 | // are actually going to generate a local variable table. | ||
| 144 | if ((value instanceof LocalVariable) && !env.debug_vars()) { | ||
| 145 | value = new Integer(((LocalVariable)value).slot); | ||
| 146 | } | ||
| 147 | break; | ||
| 148 | |||
| 149 | case opc_goto: { | ||
| 150 | Label lbl = (Label)value; | ||
| 151 | value = lbl = lbl.getDestination(); | ||
| 152 | if (lbl == next) { | ||
| 153 | // goto to the next instruction, obsolete | ||
| 154 | opc = opc_dead; | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | |||
| 158 | // We optimize | ||
| 159 | // | ||
| 160 | // goto Tag | ||
| 161 | // ... | ||
| 162 | // Tag: | ||
| 163 | // return | ||
| 164 | // | ||
| 165 | // except when we're generating debuggable code. When | ||
| 166 | // we're generating debuggable code, we leave it alone, | ||
| 167 | // in order to provide better stepping behavior. Consider | ||
| 168 | // a method the end of which looks like this: | ||
| 169 | // | ||
| 170 | // ... | ||
| 171 | // break; | ||
| 172 | // } // end of loop | ||
| 173 | // } // end of method | ||
| 174 | // | ||
| 175 | // If we optimize the goto away, we'll be left with a | ||
| 176 | // single instruction (return) and the need to ascribe that | ||
| 177 | // instruction to two source lines (the break statement and | ||
| 178 | // the method's right curly). Can't get there from here. | ||
| 179 | // Depending on which line-number ascription we choose, the | ||
| 180 | // stepping user will step directly from the break statement | ||
| 181 | // back into the caller of the method (case 1) or from the | ||
| 182 | // statement that precedes the break statement to the method's | ||
| 183 | // right curly (case 2). Similarly, he'll be able to set a | ||
| 184 | // breakpoint on the break statement (case 1) or the method's | ||
| 185 | // right curly (case 2), but not on both. Neither case 1 nor | ||
| 186 | // case 2 is desirable. .We want him to see both the break | ||
| 187 | // statement and the method's right curly when stepping, | ||
| 188 | // and we want him to be able to set a breakpoint on either or | ||
| 189 | // both. So we suppress the optimization when generating | ||
| 190 | // debuggable code. | ||
| 191 | // (Above notes from brucek@eng in JDK1.0.2, copied here | ||
| 192 | // by kelly.ohair@eng for JDK1.1) | ||
| 193 | // | ||
| 194 | // With the changes to allow -O and -g at the same time, | ||
| 195 | // I've changed the condition to be whether optimization is | ||
| 196 | // on instead of the debugging flag being off. | ||
| 197 | // - david.stoutamire@eng for 1.2 | ||
| 198 | |||
| 199 | if (lbl.next != null && env.opt()) { | ||
| 200 | switch (lbl.next.opc) { | ||
| 201 | case opc_return: case opc_ireturn: case opc_lreturn: | ||
| 202 | case opc_freturn: case opc_dreturn: case opc_areturn: | ||
| 203 | // goto to return | ||
| 204 | opc = lbl.next.opc; | ||
| 205 | value = lbl.next.value; | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | |||
| 212 | case opc_ifeq: case opc_ifne: case opc_ifgt: | ||
| 213 | case opc_ifge: case opc_iflt: case opc_ifle: | ||
| 214 | case opc_ifnull: case opc_ifnonnull: | ||
| 215 | value = ((Label)value).getDestination(); | ||
| 216 | if (value == next) { | ||
| 217 | // branch to next instruction, obsolete | ||
| 218 | opc = opc_pop; | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | if ((next.opc == opc_goto) && (value == next.next)) { | ||
| 222 | // Conditional branch over goto, invert | ||
| 223 | // Note that you can't invert all conditions, condition | ||
| 224 | // results for float/double compares are not invertable. | ||
| 225 | switch (opc) { | ||
| 226 | case opc_ifeq: opc = opc_ifne; break; | ||
| 227 | case opc_ifne: opc = opc_ifeq; break; | ||
| 228 | case opc_iflt: opc = opc_ifge; break; | ||
| 229 | case opc_ifle: opc = opc_ifgt; break; | ||
| 230 | case opc_ifgt: opc = opc_ifle; break; | ||
| 231 | case opc_ifge: opc = opc_iflt; break; | ||
| 232 | case opc_ifnull: opc = opc_ifnonnull; break; | ||
| 233 | case opc_ifnonnull: opc = opc_ifnull; break; | ||
| 234 | } | ||
| 235 | //JCOV | ||
| 236 | flagCondInverted = !flagCondInverted; | ||
| 237 | //end JCOV | ||
| 238 | value = next.value; | ||
| 239 | next.opc = opc_dead; | ||
| 240 | } | ||
| 241 | break; | ||
| 242 | |||
| 243 | case opc_if_acmpeq: case opc_if_acmpne: | ||
| 244 | case opc_if_icmpeq: case opc_if_icmpne: | ||
| 245 | case opc_if_icmpgt: case opc_if_icmpge: | ||
| 246 | case opc_if_icmplt: case opc_if_icmple: | ||
| 247 | value = ((Label)value).getDestination(); | ||
| 248 | if (value == next) { | ||
| 249 | // branch to next instruction, obsolete | ||
| 250 | opc = opc_pop2; | ||
| 251 | break; | ||
| 252 | } | ||
| 253 | if ((next.opc == opc_goto) && (value == next.next)) { | ||
| 254 | // Conditional branch over goto, invert | ||
| 255 | switch (opc) { | ||
| 256 | case opc_if_acmpeq: opc = opc_if_acmpne; break; | ||
| 257 | case opc_if_acmpne: opc = opc_if_acmpeq; break; | ||
| 258 | case opc_if_icmpeq: opc = opc_if_icmpne; break; | ||
| 259 | case opc_if_icmpne: opc = opc_if_icmpeq; break; | ||
| 260 | case opc_if_icmpgt: opc = opc_if_icmple; break; | ||
| 261 | case opc_if_icmpge: opc = opc_if_icmplt; break; | ||
| 262 | case opc_if_icmplt: opc = opc_if_icmpge; break; | ||
| 263 | case opc_if_icmple: opc = opc_if_icmpgt; break; | ||
| 264 | } | ||
| 265 | //JCOV | ||
| 266 | flagCondInverted = !flagCondInverted; | ||
| 267 | //end JCOV | ||
| 268 | value = next.value; | ||
| 269 | next.opc = opc_dead; | ||
| 270 | } | ||
| 271 | break; | ||
| 272 | |||
| 273 | case opc_tableswitch: | ||
| 274 | case opc_lookupswitch: { | ||
| 275 | SwitchData sw = (SwitchData)value; | ||
| 276 | sw.defaultLabel = sw.defaultLabel.getDestination(); | ||
| 277 | for (Enumeration e = sw.tab.keys() ; e.hasMoreElements() ; ) { | ||
| 278 | Integer k = (Integer)e.nextElement(); | ||
| 279 | Label lbl = (Label)sw.tab.get(k); | ||
| 280 | sw.tab.put(k, lbl.getDestination()); | ||
| 281 | } | ||
| 282 | |||
| 283 | // Compute the approximate sizes of a tableswitch and a | ||
| 284 | // lookupswitch. Decide which one we want to generate. | ||
| 285 | |||
| 286 | long range = (long)sw.maxValue - (long)sw.minValue + 1; | ||
| 287 | long entries = sw.tab.size(); | ||
| 288 | |||
| 289 | long tableSize = 4 + range; | ||
| 290 | long lookupSize = 3 + 2 * entries; | ||
| 291 | |||
| 292 | if (tableSize <= lookupSize * SWITCHRATIO) { | ||
| 293 | opc = opc_tableswitch; | ||
| 294 | } else { | ||
| 295 | opc = opc_lookupswitch; | ||
| 296 | } | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | |||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | ||
| 304 | * Collect constants into the constant table | ||
| 305 | */ | ||
| 306 | void collect(ConstantPool tab) { | ||
| 307 | switch (opc) { | ||
| 308 | case opc_istore: case opc_lstore: case opc_fstore: | ||
| 309 | case opc_dstore: case opc_astore: | ||
| 310 | if (value instanceof LocalVariable) { | ||
| 311 | MemberDefinition field = ((LocalVariable)value).field; | ||
| 312 | tab.put(field.getName().toString()); | ||
| 313 | tab.put(field.getType().getTypeSignature()); | ||
| 314 | } | ||
| 315 | return; | ||
| 316 | |||
| 317 | case opc_new: case opc_putfield: | ||
| 318 | case opc_putstatic: case opc_getfield: | ||
| 319 | case opc_getstatic: case opc_invokevirtual: | ||
| 320 | case opc_invokespecial: case opc_invokestatic: | ||
| 321 | case opc_invokeinterface: case opc_instanceof: | ||
| 322 | case opc_checkcast: | ||
| 323 | tab.put(value); | ||
| 324 | return; | ||
| 325 | |||
| 326 | case opc_anewarray: | ||
| 327 | tab.put(value); | ||
| 328 | return; | ||
| 329 | |||
| 330 | case opc_multianewarray: | ||
| 331 | tab.put(((ArrayData)value).type); | ||
| 332 | return; | ||
| 333 | |||
| 334 | case opc_ldc: | ||
| 335 | case opc_ldc_w: | ||
| 336 | if (value instanceof Integer) { | ||
| 337 | int v = ((Integer)value).intValue(); | ||
| 338 | if ((v >= -1) && (v <= 5)) { | ||
| 339 | opc = opc_iconst_0 + v; | ||
| 340 | return; | ||
| 341 | } else if ((v >= -(1 << 7)) && (v < (1 << 7))) { | ||
| 342 | opc = opc_bipush; | ||
| 343 | return; | ||
| 344 | } else if ((v >= -(1 << 15)) && (v < (1 << 15))) { | ||
| 345 | opc = opc_sipush; | ||
| 346 | return; | ||
| 347 | } | ||
| 348 | } else if (value instanceof Float) { | ||
| 349 | float v = ((Float)value).floatValue(); | ||
| 350 | if (v == 0) { | ||
| 351 | if (Float.floatToIntBits(v) == 0) { | ||
| 352 | opc = opc_fconst_0; | ||
| 353 | return; | ||
| 354 | } | ||
| 355 | } else if (v == 1) { | ||
| 356 | opc = opc_fconst_1; | ||
| 357 | return; | ||
| 358 | } else if (v == 2) { | ||
| 359 | opc = opc_fconst_2; | ||
| 360 | return; | ||
| 361 | } | ||
| 362 | } | ||
| 363 | tab.put(value); | ||
| 364 | return; | ||
| 365 | |||
| 366 | case opc_ldc2_w: | ||
| 367 | if (value instanceof Long) { | ||
| 368 | long v = ((Long)value).longValue(); | ||
| 369 | if (v == 0) { | ||
| 370 | opc = opc_lconst_0; | ||
| 371 | return; | ||
| 372 | } else if (v == 1) { | ||
| 373 | opc = opc_lconst_1; | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | } else if (value instanceof Double) { | ||
| 377 | double v = ((Double)value).doubleValue(); | ||
| 378 | if (v == 0) { | ||
| 379 | if (Double.doubleToLongBits(v) == 0) { | ||
| 380 | opc = opc_dconst_0; | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | } else if (v == 1) { | ||
| 384 | opc = opc_dconst_1; | ||
| 385 | return; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | tab.put(value); | ||
| 389 | return; | ||
| 390 | |||
| 391 | case opc_try: | ||
| 392 | for (Enumeration e = ((TryData)value).catches.elements() ; e.hasMoreElements() ;) { | ||
| 393 | CatchData cd = (CatchData)e.nextElement(); | ||
| 394 | if (cd.getType() != null) { | ||
| 395 | tab.put(cd.getType()); | ||
| 396 | } | ||
| 397 | } | ||
| 398 | return; | ||
| 399 | |||
| 400 | case opc_nop: | ||
| 401 | if ((value != null) && (value instanceof ClassDeclaration)) | ||
| 402 | tab.put(value); | ||
| 403 | return; | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | /** | ||
| 408 | * Balance the stack | ||
| 409 | */ | ||
| 410 | int balance() { | ||
| 411 | switch (opc) { | ||
| 412 | case opc_dead: case opc_label: case opc_iinc: | ||
| 413 | case opc_arraylength: case opc_laload: case opc_daload: | ||
| 414 | case opc_nop: case opc_ineg: case opc_fneg: | ||
| 415 | case opc_lneg: case opc_dneg: case opc_i2f: | ||
| 416 | case opc_f2i: case opc_l2d: case opc_d2l: | ||
| 417 | case opc_i2b: case opc_i2c: case opc_i2s: | ||
| 418 | case opc_jsr: case opc_goto: case opc_jsr_w: | ||
| 419 | case opc_goto_w: case opc_return: case opc_ret: | ||
| 420 | case opc_instanceof: case opc_checkcast: case opc_newarray: | ||
| 421 | case opc_anewarray: case opc_try: case opc_swap: | ||
| 422 | return 0; | ||
| 423 | |||
| 424 | case opc_ldc: case opc_ldc_w: case opc_bipush: | ||
| 425 | case opc_sipush: case opc_aconst_null: case opc_iconst_m1: | ||
| 426 | case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: | ||
| 427 | case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: | ||
| 428 | case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: | ||
| 429 | case opc_iload: case opc_fload: case opc_aload: | ||
| 430 | case opc_dup: case opc_dup_x1: case opc_dup_x2: | ||
| 431 | case opc_i2l: case opc_i2d: case opc_f2l: | ||
| 432 | case opc_f2d: case opc_new: | ||
| 433 | return 1; | ||
| 434 | |||
| 435 | case opc_lload: case opc_dload: case opc_dup2: | ||
| 436 | case opc_dup2_x1: case opc_dup2_x2: case opc_ldc2_w: | ||
| 437 | case opc_lconst_0: case opc_lconst_1: case opc_dconst_0: | ||
| 438 | case opc_dconst_1: | ||
| 439 | return 2; | ||
| 440 | |||
| 441 | case opc_istore: case opc_fstore: case opc_astore: | ||
| 442 | case opc_iaload: case opc_faload: case opc_aaload: | ||
| 443 | case opc_baload: case opc_caload: case opc_saload: | ||
| 444 | case opc_pop: case opc_iadd: case opc_fadd: | ||
| 445 | case opc_isub: case opc_fsub: case opc_imul: | ||
| 446 | case opc_fmul: case opc_idiv: case opc_fdiv: | ||
| 447 | case opc_irem: case opc_frem: case opc_ishl: | ||
| 448 | case opc_ishr: case opc_iushr: case opc_lshl: | ||
| 449 | case opc_lshr: case opc_lushr: case opc_iand: | ||
| 450 | case opc_ior: case opc_ixor: case opc_l2i: | ||
| 451 | case opc_l2f: case opc_d2i: case opc_d2f: | ||
| 452 | case opc_ifeq: case opc_ifne: case opc_iflt: | ||
| 453 | case opc_ifle: case opc_ifgt: case opc_ifge: | ||
| 454 | case opc_ifnull: case opc_ifnonnull: case opc_fcmpl: | ||
| 455 | case opc_fcmpg: case opc_ireturn: case opc_freturn: | ||
| 456 | case opc_areturn: case opc_tableswitch: case opc_lookupswitch: | ||
| 457 | case opc_athrow: case opc_monitorenter: case opc_monitorexit: | ||
| 458 | return -1; | ||
| 459 | |||
| 460 | case opc_lstore: case opc_dstore: case opc_pop2: | ||
| 461 | case opc_ladd: case opc_dadd: case opc_lsub: | ||
| 462 | case opc_dsub: case opc_lmul: case opc_dmul: | ||
| 463 | case opc_ldiv: case opc_ddiv: case opc_lrem: | ||
| 464 | case opc_drem: case opc_land: case opc_lor: | ||
| 465 | case opc_lxor: case opc_if_acmpeq: case opc_if_acmpne: | ||
| 466 | case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: | ||
| 467 | case opc_if_icmple: case opc_if_icmpgt: case opc_if_icmpge: | ||
| 468 | case opc_lreturn: case opc_dreturn: | ||
| 469 | return -2; | ||
| 470 | |||
| 471 | case opc_iastore: case opc_fastore: case opc_aastore: | ||
| 472 | case opc_bastore: case opc_castore: case opc_sastore: | ||
| 473 | case opc_lcmp: case opc_dcmpl: case opc_dcmpg: | ||
| 474 | return -3; | ||
| 475 | |||
| 476 | case opc_lastore: case opc_dastore: | ||
| 477 | return -4; | ||
| 478 | |||
| 479 | case opc_multianewarray: | ||
| 480 | return 1 - ((ArrayData)value).nargs; | ||
| 481 | |||
| 482 | case opc_getfield: | ||
| 483 | return ((MemberDefinition)value).getType().stackSize() - 1; | ||
| 484 | |||
| 485 | case opc_putfield: | ||
| 486 | return -1 - ((MemberDefinition)value).getType().stackSize(); | ||
| 487 | |||
| 488 | case opc_getstatic: | ||
| 489 | return ((MemberDefinition)value).getType().stackSize(); | ||
| 490 | |||
| 491 | case opc_putstatic: | ||
| 492 | return -((MemberDefinition)value).getType().stackSize(); | ||
| 493 | |||
| 494 | case opc_invokevirtual: | ||
| 495 | case opc_invokespecial: | ||
| 496 | case opc_invokeinterface: | ||
| 497 | return ((MemberDefinition)value).getType().getReturnType().stackSize() - | ||
| 498 | (((MemberDefinition)value).getType().stackSize() + 1); | ||
| 499 | |||
| 500 | case opc_invokestatic: | ||
| 501 | return ((MemberDefinition)value).getType().getReturnType().stackSize() - | ||
| 502 | (((MemberDefinition)value).getType().stackSize()); | ||
| 503 | } | ||
| 504 | throw new CompilerError("invalid opcode: " + toString()); | ||
| 505 | } | ||
| 506 | |||
| 507 | /** | ||
| 508 | * Return the size of the instruction | ||
| 509 | */ | ||
| 510 | int size(ConstantPool tab) { | ||
| 511 | switch (opc) { | ||
| 512 | case opc_try: case opc_label: case opc_dead: | ||
| 513 | return 0; | ||
| 514 | |||
| 515 | case opc_bipush: case opc_newarray: | ||
| 516 | return 2; | ||
| 517 | |||
| 518 | case opc_sipush: case opc_goto: case opc_jsr: | ||
| 519 | case opc_ifeq: case opc_ifne: case opc_ifgt: | ||
| 520 | case opc_ifge: case opc_iflt: case opc_ifle: | ||
| 521 | case opc_ifnull: case opc_ifnonnull: case opc_if_acmpeq: | ||
| 522 | case opc_if_acmpne: case opc_if_icmpeq: case opc_if_icmpne: | ||
| 523 | case opc_if_icmpgt: case opc_if_icmpge: case opc_if_icmplt: | ||
| 524 | case opc_if_icmple: | ||
| 525 | return 3; | ||
| 526 | |||
| 527 | case opc_ldc: | ||
| 528 | case opc_ldc_w: | ||
| 529 | if (tab.index(value) < 256) { | ||
| 530 | opc = opc_ldc; | ||
| 531 | return 2; | ||
| 532 | } else { | ||
| 533 | opc = opc_ldc_w; | ||
| 534 | return 3; | ||
| 535 | } | ||
| 536 | |||
| 537 | case opc_iload: case opc_lload: case opc_fload: | ||
| 538 | case opc_dload: case opc_aload: { | ||
| 539 | int v = ((Number)value).intValue(); | ||
| 540 | if (v < 4) { | ||
| 541 | if (v < 0) { | ||
| 542 | throw new CompilerError("invalid slot: " + toString() | ||
| 543 | + "\nThis error possibly resulted from poorly constructed class paths."); | ||
| 544 | } | ||
| 545 | opc = opc_iload_0 + (opc - opc_iload) * 4 + v; | ||
| 546 | return 1; | ||
| 547 | } else if (v <= 255) { | ||
| 548 | return 2; | ||
| 549 | } else { | ||
| 550 | opc += 256; // indicate wide variant | ||
| 551 | return 4; | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | case opc_iinc: { | ||
| 556 | int register = ((int[])value)[0]; | ||
| 557 | int increment = ((int[])value)[1]; | ||
| 558 | if (register < 0) { | ||
| 559 | throw new CompilerError("invalid slot: " + toString()); | ||
| 560 | } | ||
| 561 | if (register <= 255 && (((byte)increment) == increment)) { | ||
| 562 | return 3; | ||
| 563 | } else { | ||
| 564 | opc += 256; // indicate wide variant | ||
| 565 | return 6; | ||
| 566 | } | ||
| 567 | } | ||
| 568 | |||
| 569 | case opc_istore: case opc_lstore: case opc_fstore: | ||
| 570 | case opc_dstore: case opc_astore: { | ||
| 571 | int v = (value instanceof Number) ? | ||
| 572 | ((Number)value).intValue() : ((LocalVariable)value).slot; | ||
| 573 | if (v < 4) { | ||
| 574 | if (v < 0) { | ||
| 575 | throw new CompilerError("invalid slot: " + toString()); | ||
| 576 | } | ||
| 577 | opc = opc_istore_0 + (opc - opc_istore) * 4 + v; | ||
| 578 | return 1; | ||
| 579 | } else if (v <= 255) { | ||
| 580 | return 2; | ||
| 581 | } else { | ||
| 582 | opc += 256; // indicate wide variant | ||
| 583 | return 4; | ||
| 584 | } | ||
| 585 | } | ||
| 586 | |||
| 587 | case opc_ret: { | ||
| 588 | int v = ((Number)value).intValue(); | ||
| 589 | if (v <= 255) { | ||
| 590 | if (v < 0) { | ||
| 591 | throw new CompilerError("invalid slot: " + toString()); | ||
| 592 | } | ||
| 593 | return 2; | ||
| 594 | } else { | ||
| 595 | opc += 256; // indicate wide variant | ||
| 596 | return 4; | ||
| 597 | } | ||
| 598 | } | ||
| 599 | |||
| 600 | case opc_ldc2_w: case opc_new: | ||
| 601 | case opc_putstatic: case opc_getstatic: | ||
| 602 | case opc_putfield: case opc_getfield: | ||
| 603 | case opc_invokevirtual: case opc_invokespecial: | ||
| 604 | case opc_invokestatic: case opc_instanceof: | ||
| 605 | case opc_checkcast: case opc_anewarray: | ||
| 606 | return 3; | ||
| 607 | |||
| 608 | case opc_multianewarray: | ||
| 609 | return 4; | ||
| 610 | |||
| 611 | case opc_invokeinterface: | ||
| 612 | case opc_goto_w: | ||
| 613 | case opc_jsr_w: | ||
| 614 | return 5; | ||
| 615 | |||
| 616 | case opc_tableswitch: { | ||
| 617 | SwitchData sw = (SwitchData)value; | ||
| 618 | int n = 1; | ||
| 619 | for(; ((pc + n) % 4) != 0 ; n++); | ||
| 620 | return n + 16 + (sw.maxValue - sw.minValue) * 4; | ||
| 621 | } | ||
| 622 | |||
| 623 | case opc_lookupswitch: { | ||
| 624 | SwitchData sw = (SwitchData)value; | ||
| 625 | int n = 1; | ||
| 626 | for(; ((pc + n) % 4) != 0 ; n++); | ||
| 627 | return n + 8 + sw.tab.size() * 8; | ||
| 628 | } | ||
| 629 | |||
| 630 | case opc_nop: | ||
| 631 | if ((value != null) && !(value instanceof Integer)) | ||
| 632 | return 2; | ||
| 633 | else | ||
| 634 | return 1; | ||
| 635 | } | ||
| 636 | |||
| 637 | // most opcodes are only 1 byte long | ||
| 638 | return 1; | ||
| 639 | } | ||
| 640 | |||
| 641 | /** | ||
| 642 | * Generate code | ||
| 643 | */ | ||
| 644 | void write(DataOutputStream out, ConstantPool tab) throws IOException { | ||
| 645 | switch (opc) { | ||
| 646 | case opc_try: case opc_label: case opc_dead: | ||
| 647 | break; | ||
| 648 | |||
| 649 | case opc_bipush: case opc_newarray: | ||
| 650 | case opc_iload: case opc_lload: case opc_fload: | ||
| 651 | case opc_dload: case opc_aload: case opc_ret: | ||
| 652 | out.writeByte(opc); | ||
| 653 | out.writeByte(((Number)value).intValue()); | ||
| 654 | break; | ||
| 655 | |||
| 656 | case opc_iload + 256: case opc_lload + 256: | ||
| 657 | case opc_fload + 256: case opc_dload + 256: | ||
| 658 | case opc_aload + 256: case opc_ret + 256: | ||
| 659 | out.writeByte(opc_wide); | ||
| 660 | out.writeByte(opc - 256); | ||
| 661 | out.writeShort(((Number)value).intValue()); | ||
| 662 | break; | ||
| 663 | |||
| 664 | case opc_istore: case opc_lstore: case opc_fstore: | ||
| 665 | case opc_dstore: case opc_astore: | ||
| 666 | out.writeByte(opc); | ||
| 667 | out.writeByte((value instanceof Number) ? | ||
| 668 | ((Number)value).intValue() : ((LocalVariable)value).slot); | ||
| 669 | break; | ||
| 670 | |||
| 671 | case opc_istore + 256: case opc_lstore + 256: | ||
| 672 | case opc_fstore + 256: case opc_dstore + 256: | ||
| 673 | case opc_astore + 256: | ||
| 674 | out.writeByte(opc_wide); | ||
| 675 | out.writeByte(opc - 256); | ||
| 676 | out.writeShort((value instanceof Number) ? | ||
| 677 | ((Number)value).intValue() : ((LocalVariable)value).slot); | ||
| 678 | break; | ||
| 679 | |||
| 680 | case opc_sipush: | ||
| 681 | out.writeByte(opc); | ||
| 682 | out.writeShort(((Number)value).intValue()); | ||
| 683 | break; | ||
| 684 | |||
| 685 | case opc_ldc: | ||
| 686 | out.writeByte(opc); | ||
| 687 | out.writeByte(tab.index(value)); | ||
| 688 | break; | ||
| 689 | |||
| 690 | case opc_ldc_w: case opc_ldc2_w: | ||
| 691 | case opc_new: case opc_putstatic: | ||
| 692 | case opc_getstatic: case opc_putfield: | ||
| 693 | case opc_getfield: case opc_invokevirtual: | ||
| 694 | case opc_invokespecial: case opc_invokestatic: | ||
| 695 | case opc_instanceof: case opc_checkcast: | ||
| 696 | out.writeByte(opc); | ||
| 697 | out.writeShort(tab.index(value)); | ||
| 698 | break; | ||
| 699 | |||
| 700 | case opc_iinc: | ||
| 701 | out.writeByte(opc); | ||
| 702 | out.writeByte(((int[])value)[0]); // register | ||
| 703 | out.writeByte(((int[])value)[1]); // increment | ||
| 704 | break; | ||
| 705 | |||
| 706 | case opc_iinc + 256: | ||
| 707 | out.writeByte(opc_wide); | ||
| 708 | out.writeByte(opc - 256); | ||
| 709 | out.writeShort(((int[])value)[0]); // register | ||
| 710 | out.writeShort(((int[])value)[1]); // increment | ||
| 711 | break; | ||
| 712 | |||
| 713 | case opc_anewarray: | ||
| 714 | out.writeByte(opc); | ||
| 715 | out.writeShort(tab.index(value)); | ||
| 716 | break; | ||
| 717 | |||
| 718 | case opc_multianewarray: | ||
| 719 | out.writeByte(opc); | ||
| 720 | out.writeShort(tab.index(((ArrayData)value).type)); | ||
| 721 | out.writeByte(((ArrayData)value).nargs); | ||
| 722 | break; | ||
| 723 | |||
| 724 | case opc_invokeinterface: | ||
| 725 | out.writeByte(opc); | ||
| 726 | out.writeShort(tab.index(value)); | ||
| 727 | out.writeByte(((MemberDefinition)value).getType().stackSize() + 1); | ||
| 728 | out.writeByte(0); | ||
| 729 | break; | ||
| 730 | |||
| 731 | case opc_goto: case opc_jsr: case opc_ifeq: | ||
| 732 | case opc_ifne: case opc_ifgt: case opc_ifge: | ||
| 733 | case opc_iflt: case opc_ifle: case opc_ifnull: | ||
| 734 | case opc_ifnonnull: case opc_if_acmpeq: case opc_if_acmpne: | ||
| 735 | case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: | ||
| 736 | case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: | ||
| 737 | out.writeByte(opc); | ||
| 738 | out.writeShort(((Instruction)value).pc - pc); | ||
| 739 | break; | ||
| 740 | |||
| 741 | case opc_goto_w: | ||
| 742 | case opc_jsr_w: | ||
| 743 | out.writeByte(opc); | ||
| 744 | out.writeLong(((Instruction)value).pc - pc); | ||
| 745 | break; | ||
| 746 | |||
| 747 | case opc_tableswitch: { | ||
| 748 | SwitchData sw = (SwitchData)value; | ||
| 749 | out.writeByte(opc); | ||
| 750 | for(int n = 1 ; ((pc + n) % 4) != 0 ; n++) { | ||
| 751 | out.writeByte(0); | ||
| 752 | } | ||
| 753 | out.writeInt(sw.defaultLabel.pc - pc); | ||
| 754 | out.writeInt(sw.minValue); | ||
| 755 | out.writeInt(sw.maxValue); | ||
| 756 | for (int n = sw.minValue ; n <= sw.maxValue ; n++) { | ||
| 757 | Label lbl = sw.get(n); | ||
| 758 | int target_pc = (lbl != null) ? lbl.pc : sw.defaultLabel.pc; | ||
| 759 | out.writeInt(target_pc - pc); | ||
| 760 | } | ||
| 761 | break; | ||
| 762 | } | ||
| 763 | |||
| 764 | case opc_lookupswitch: { | ||
| 765 | SwitchData sw = (SwitchData)value; | ||
| 766 | out.writeByte(opc); | ||
| 767 | int n = pc + 1; | ||
| 768 | for(; (n % 4) != 0 ; n++) { | ||
| 769 | out.writeByte(0); | ||
| 770 | } | ||
| 771 | out.writeInt(sw.defaultLabel.pc - pc); | ||
| 772 | out.writeInt(sw.tab.size()); | ||
| 773 | for (Enumeration e = sw.sortedKeys(); e.hasMoreElements() ; ) { | ||
| 774 | Integer v = (Integer)e.nextElement(); | ||
| 775 | out.writeInt(v.intValue()); | ||
| 776 | out.writeInt(sw.get(v).pc - pc); | ||
| 777 | } | ||
| 778 | break; | ||
| 779 | } | ||
| 780 | |||
| 781 | case opc_nop: | ||
| 782 | if (value != null) { | ||
| 783 | if (value instanceof Integer) | ||
| 784 | out.writeByte(((Integer)value).intValue()); | ||
| 785 | else | ||
| 786 | out.writeShort(tab.index(value)); | ||
| 787 | return; | ||
| 788 | } | ||
| 789 | // fall through | ||
| 790 | |||
| 791 | default: | ||
| 792 | out.writeByte(opc); | ||
| 793 | break; | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 797 | /** | ||
| 798 | * toString | ||
| 799 | */ | ||
| 800 | public String toString() { | ||
| 801 | String prefix = (where >> WHEREOFFSETBITS) + ":\t"; | ||
| 802 | switch (opc) { | ||
| 803 | case opc_try: | ||
| 804 | return prefix + "try " + ((TryData)value).getEndLabel().hashCode(); | ||
| 805 | |||
| 806 | case opc_dead: | ||
| 807 | return prefix + "dead"; | ||
| 808 | |||
| 809 | case opc_iinc: { | ||
| 810 | int register = ((int[])value)[0]; | ||
| 811 | int increment = ((int[])value)[1]; | ||
| 812 | return prefix + opcNames[opc] + " " + register + ", " + increment; | ||
| 813 | } | ||
| 814 | |||
| 815 | default: | ||
| 816 | if (value != null) { | ||
| 817 | if (value instanceof Label) { | ||
| 818 | return prefix + opcNames[opc] + " " + value.toString(); | ||
| 819 | } else if (value instanceof Instruction) { | ||
| 820 | return prefix + opcNames[opc] + " " + value.hashCode(); | ||
| 821 | } else if (value instanceof String) { | ||
| 822 | return prefix + opcNames[opc] + " \"" + value + "\""; | ||
| 823 | } else { | ||
| 824 | return prefix + opcNames[opc] + " " + value; | ||
| 825 | } | ||
| 826 | } else { | ||
| 827 | return prefix + opcNames[opc]; | ||
| 828 | } | ||
| 829 | } | ||
| 830 | } | ||
| 831 | } | ||