1 // Copyright (c) 1997, 1998, 1999, 2001, 2003, 2004, 2008 Per M.A. Bothner. 2 // This is free software; for terms and warranty disclaimer see ./COPYING. 3 4 package gnu.bytecode; 5 import java.io.*; 6 7 /** 8 * Represents the contents of a standard "Code" attribute. 9 * <p> 10 * Most of the actual methods that generate bytecode operation 11 * are in this class (typically with names starting with <code>emit</code>), 12 * though there are also some in <code>Method</code>. 13 * <p> 14 * Note that a <code>CodeAttr</code> is an <code>Attribute</code> 15 * of a <code>Method</code>, and can in turn contain other 16 * <code>Attribute</code>s, such as a <code>LineNumbersAttr</code>. 17 * 18 * @author Per Bothner 19 */ 20 21 public class CodeAttr extends Attribute implements AttrContainer 22 { 23 Attribute attributes; getAttributes()24 public final Attribute getAttributes () { return attributes; } setAttributes(Attribute attributes)25 public final void setAttributes (Attribute attributes) 26 { this.attributes = attributes; } 27 LineNumbersAttr lines; 28 public LocalVarsAttr locals; 29 public StackMapTableAttr stackMap; 30 31 SourceDebugExtAttr sourceDbgExt; 32 33 public static final int GENERATE_STACK_MAP_TABLE = 1; 34 public static final int DONT_USE_JSR = 2; 35 int flags; 36 37 public Type[] stack_types; 38 Type[] local_types = new Type[20]; 39 40 /** Previously-defined label. */ 41 Label previousLabel; 42 /** Set of vars set in current block (since previousLabel). 43 * This is so we can differentiate variable set locally, versus definitions 44 * that reach us (and that might be invalidated by future flows). */ 45 boolean[] varsSetInCurrentBlock; 46 47 int SP; // Current stack size (in "words") 48 private int max_stack; 49 private int max_locals; 50 /** Current active length of code array. 51 * Note that processFixups may expand/contract the code array. */ 52 int PC; 53 byte[] code; 54 useJsr()55 boolean useJsr() 56 { 57 return (flags & DONT_USE_JSR) == 0; 58 } 59 60 /* The exception handler table, as a vector of quadruples 61 (start_pc, end_pc, handler_pc, catch_type). 62 Only the first exception_table_length quadruples are defined. */ 63 short[] exception_table; 64 65 /* The number of (defined) exception handlers (i.e. quadruples) 66 in exception_table. */ 67 int exception_table_length; 68 69 /** The definition of a label. */ 70 static final int FIXUP_DEFINE = 0; 71 static final int FIXUP_DEFINE_UNREACHABLE = 1; 72 // From FIXUP_SWITCH up to FIXUP_TRANSFER2 must be contiguous 73 // - see the jump-to-jump optimization in processFixups. 74 /** The offset points to a tableswitch/lookupswitch - handle padding. */ 75 static final int FIXUP_SWITCH = 2; 76 /** The offset contains a label relative to the previous FIXUP_SWITCH. */ 77 static final int FIXUP_CASE = 3; 78 /** The offset points to a goto instruction. */ 79 static final int FIXUP_GOTO = 4; 80 /** The offset points to a jsr instruction. */ 81 static final int FIXUP_JSR = 5; 82 /** The offset points to a conditional transfer (if_xxx) instruction. */ 83 static final int FIXUP_TRANSFER = 6; 84 /** A FIXUP_GOTO_, FIXUP_JSR, or FIXUP_TRANSFER that uses a 2-byte offset. */ 85 static final int FIXUP_TRANSFER2 = 7; 86 /** The offsets points to 3 bytes that should be deleted. */ 87 static final int FIXUP_DELETE3 = 8; 88 /** The following instructions are moved to later in the code stream. 89 * Instead the instructions starting at the fixup label are patched here. 90 * (If the fixup label is null, we're done.) 91 * This allows re-arranging code to avoid unneeded gotos. 92 * The following instruction is the target of a later FIXUP_MOVE, 93 * and we'll insert then when we get to it. */ 94 static final int FIXUP_MOVE = 9; 95 /** The following instructions are moved to the end of the code stream. 96 * Same as FIXUP_MOVE, but there is no explicit later FIXUP_MOVE that 97 * refers to the following instructions. Created by beginFragment. 98 * The fixup_offset points to the end of the fragment. 99 * (The first processFixups patches these to FIXUP_MOVE.) */ 100 static final int FIXUP_MOVE_TO_END = 10; 101 /** FIXUP_TRY with the following FIXUP_TRY_END and FIXUP_TRY_HANDLER 102 * marks an exception handler. The label is the start of the try clause; 103 * the current offset marks the exception handler. */ 104 static final int FIXUP_TRY = 11; 105 /** Second part of a FIXUP_TRY/FIXUP_TRY_END/FIXUP_TRY_HANDLER set. 106 * The label is the end of the try clause; 107 * the current offset is the exception type as a constant pool index. */ 108 static final int FIXUP_TRY_END = 12; 109 static final int FIXUP_TRY_HANDLER = 13; 110 /** With following FIXUP_LINE_NUMBER associates an offset with a line number. 111 * The fixup_offset is the code location; the fixup_label is null. */ 112 static final int FIXUP_LINE_PC = 14; 113 /** With preceding FIXUP_LINE_PC associates an offset with a line number. 114 * The fixup_offset is the line number; the fixup_label is null. */ 115 static final int FIXUP_LINE_NUMBER = 15; 116 int[] fixup_offsets; 117 Label[] fixup_labels; 118 /** Active length of fixup_offsets and fixup_labels. 119 * If {@code fixup_count == -1} we're not doing fixups. */ 120 int fixup_count; 121 122 /** This causes a later processFixup to rearrange the code. 123 * The code at target comes here, instead of the following instructions. 124 * Fuctionally equivalent to: <code>goto target; here:</code>, 125 * but implemented by code re-arranging. Therefore there should be 126 * at some later point a <code>goto here; target:</code>. 127 */ fixupChain(Label here, Label target)128 public final void fixupChain (Label here, Label target) 129 { 130 fixupAdd(CodeAttr.FIXUP_MOVE, -1, target); 131 here.defineRaw(this); 132 setPreviousLabelHere(here); 133 } 134 135 /** Add a fixup at this location. 136 * @param kind one of the FIXUP_xxx codes. 137 * @param label varies - typically the target of jump. */ fixupAdd(int kind, Label label)138 public final void fixupAdd (int kind, Label label) 139 { 140 fixupAdd(kind, PC, label); 141 } 142 fixupAdd(int kind, int offset, Label label)143 final void fixupAdd (int kind, int offset, Label label) 144 { 145 if (label != null && kind != FIXUP_DEFINE && kind != FIXUP_DEFINE_UNREACHABLE 146 && kind != FIXUP_SWITCH && kind != FIXUP_TRY) 147 label.needsStackMapEntry = true; 148 int count = fixup_count; 149 if (count == 0) 150 { 151 fixup_offsets = new int[30]; 152 fixup_labels = new Label[30]; 153 } 154 else if (fixup_count == fixup_offsets.length) 155 { 156 int new_length = 2 * count; 157 Label[] new_labels = new Label[new_length]; 158 System.arraycopy (fixup_labels, 0, new_labels, 0, count); 159 fixup_labels = new_labels; 160 int[] new_offsets = new int[new_length]; 161 System.arraycopy (fixup_offsets, 0, new_offsets, 0, count); 162 fixup_offsets = new_offsets; 163 } 164 fixupSet(count, kind, offset); 165 fixup_labels[count] = label; 166 fixup_count = count + 1; 167 } 168 fixupOffset(int index)169 private final int fixupOffset(int index) 170 { 171 return fixup_offsets[index] >> 4; 172 } 173 fixupKind(int index)174 private final int fixupKind(int index) 175 { 176 return fixup_offsets[index] & 15; 177 } 178 fixupSet(int index, int kind, int offset)179 private void fixupSet(int index, int kind, int offset) { 180 fixup_offsets[index] = fixupEncode(kind, offset); 181 } fixupEncode(int kind, int offset)182 private int fixupEncode(int kind, int offset) { 183 return (offset << 4) | kind; 184 } 185 186 /** If true we get a line number entry for each instruction. 187 * Normally false, but can be a convenient hack to allow instruction-level 188 * stepping/debugging and stacktraces. In this case {@code LINE==PC}. */ 189 public static boolean instructionLineMode = false; 190 191 /** The stack of currently active conditionals. */ 192 IfState if_stack; 193 194 /** The stack of currently active try statements. */ 195 TryState try_stack; 196 getMethod()197 public final Method getMethod() { return (Method) getContainer(); } 198 getPC()199 public final int getPC() { return PC; } 200 getSP()201 public final int getSP() { return SP; } 202 getConstants()203 public final ConstantPool getConstants () 204 { 205 return getMethod().classfile.constants; 206 } 207 208 /* True if we cannot fall through to bytes[PC] - 209 the previous instruction was an uncondition control transfer. */ 210 private boolean unreachable_here; 211 /** True if control could reach here. */ reachableHere()212 public final boolean reachableHere () { return !unreachable_here; } setReachable(boolean val)213 public final void setReachable(boolean val) { unreachable_here = !val; } setUnreachable()214 public final void setUnreachable() { unreachable_here = true; } 215 216 /** Get the maximum number of words on the operand stack in this method. */ getMaxStack()217 public int getMaxStack() { return max_stack; } 218 /** Get the maximum number of local variable words in this method. */ getMaxLocals()219 public int getMaxLocals() { return max_locals; } 220 221 /** Set the maximum number of words on the operand stack in this method. */ setMaxStack(int n)222 public void setMaxStack(int n) { max_stack = n; } 223 /** Set the maximum number of local variable words in this method. */ setMaxLocals(int n)224 public void setMaxLocals(int n) { max_locals = n; } 225 226 /** Get the code (instruction bytes) of this method. 227 * Does not make a copy. */ getCode()228 public byte[] getCode() { return code; } 229 /** Set the code (instruction bytes) of this method. 230 * @param code the code bytes (which are not copied). 231 * Implicitly calls setCodeLength(code.length). */ setCode(byte[] code)232 public void setCode(byte[] code) { 233 this.code = code; this.PC = code.length; } 234 /** Set the length the the code (instruction bytes) of this method. 235 * That is the number of current used bytes in getCode(). 236 * (Any remaing bytes provide for future growth.) */ setCodeLength(int len)237 public void setCodeLength(int len) { PC = len;} 238 /** Set the current lengthof the code (instruction bytes) of this method. */ getCodeLength()239 public int getCodeLength() { return PC; } 240 CodeAttr(Method meth)241 public CodeAttr (Method meth) 242 { 243 super ("Code"); 244 addToFrontOf(meth); 245 meth.code = this; 246 if (meth.getDeclaringClass().getClassfileMajorVersion() >= 50) 247 flags |= GENERATE_STACK_MAP_TABLE|DONT_USE_JSR; 248 } 249 reserve(int bytes)250 public final void reserve (int bytes) 251 { 252 if (code == null) 253 code = new byte[100+bytes]; 254 else if (PC + bytes > code.length) 255 { 256 byte[] new_code = new byte[2 * code.length + bytes]; 257 System.arraycopy (code, 0, new_code, 0, PC); 258 code = new_code; 259 } 260 } 261 262 /** Get opcode that implements NOT (x OPCODE y). */ invert_opcode(byte opcode)263 byte invert_opcode (byte opcode) 264 { 265 int iopcode = opcode & 0xFF; 266 if ((iopcode >= 153 && iopcode <= 166) 267 || (iopcode >= 198 && iopcode <= 199)) 268 return (byte) (iopcode ^ 1); 269 throw new Error("unknown opcode to invert_opcode"); 270 } 271 272 /** 273 * Write an 8-bit byte to the current code-stream. 274 * @param i the byte to write 275 */ put1(int i)276 public final void put1(int i) 277 { 278 code[PC++] = (byte) i; 279 unreachable_here = false; 280 } 281 282 /** 283 * Write a 16-bit short to the current code-stream 284 * @param i the value to write 285 */ put2(int i)286 public final void put2(int i) 287 { 288 code[PC++] = (byte) (i >> 8); 289 code[PC++] = (byte) (i); 290 unreachable_here = false; 291 } 292 293 /** 294 * Write a 32-bit int to the current code-stream 295 * @param i the value to write 296 */ put4(int i)297 public final void put4(int i) 298 { 299 code[PC++] = (byte) (i >> 24); 300 code[PC++] = (byte) (i >> 16); 301 code[PC++] = (byte) (i >> 8); 302 303 code[PC++] = (byte) (i); 304 unreachable_here = false; 305 } 306 putIndex2(CpoolEntry cnst)307 public final void putIndex2 (CpoolEntry cnst) 308 { 309 put2(cnst.index); 310 } 311 putLineNumber(String filename, int linenumber)312 public final void putLineNumber (String filename, int linenumber) 313 { 314 if (filename != null) 315 getMethod().classfile.setSourceFile(filename); 316 putLineNumber(linenumber); 317 } 318 putLineNumber(int linenumber)319 public final void putLineNumber (int linenumber) 320 { 321 if (sourceDbgExt != null) 322 linenumber = sourceDbgExt.fixLine(linenumber); 323 fixupAdd(FIXUP_LINE_PC, null); 324 fixupAdd(FIXUP_LINE_NUMBER, linenumber, null); 325 } 326 327 /** Initialize local_types from parameters. */ noteParamTypes()328 void noteParamTypes () 329 { 330 Method method = getMethod(); 331 int offset = 0; 332 if ((method.access_flags & Access.STATIC) == 0) 333 { 334 Type type = method.classfile; 335 if ("<init>".equals(method.getName()) 336 && ! "java.lang.Object".equals(type.getName())) 337 type = UninitializedType.uninitializedThis((ClassType) type); 338 noteVarType(offset++, type); 339 } 340 int arg_count = method.arg_types.length; 341 for (int i = 0; i < arg_count; i++) 342 { 343 Type type = method.arg_types[i]; 344 noteVarType(offset++, type); 345 for (int size = type.getSizeInWords(); -- size > 0; ) 346 offset++; 347 } 348 if ((flags & GENERATE_STACK_MAP_TABLE) != 0) 349 { 350 stackMap = new StackMapTableAttr(); 351 352 int[] encodedLocals = new int[20+offset]; 353 int count = 0; 354 for (int i = 0; i < offset; i++) 355 { 356 int encoded = stackMap.encodeVerificationType(local_types[i], this); 357 encodedLocals[count++] = encoded; 358 int tag = encoded & 0xFF; 359 if (tag == 3 || tag == 4) 360 i++; 361 } 362 stackMap.encodedLocals = encodedLocals; 363 stackMap.countLocals = count; 364 stackMap.encodedStack = new int[10]; 365 stackMap.countStack = 0; 366 } 367 } 368 setPreviousLabelHere(Label here)369 void setPreviousLabelHere(Label here) { 370 previousLabel = here; 371 boolean[] varsSet = varsSetInCurrentBlock; 372 if (varsSet != null) 373 for (int i = varsSet.length; --i >= 0; ) varsSet[i] = false; 374 } 375 noteVarType(int offset, Type type)376 public void noteVarType (int offset, Type type) 377 { 378 int size = type.getSizeInWords(); 379 380 if (local_types == null) 381 local_types = new Type[offset + size + 20]; 382 else if (offset + size > local_types.length) { 383 Type[] new_array = new Type[2 * (offset + size)]; 384 System.arraycopy (local_types, 0, new_array, 0, local_types.length); 385 local_types = new_array; 386 } 387 local_types[offset] = type; 388 if (varsSetInCurrentBlock == null) 389 varsSetInCurrentBlock = new boolean[local_types.length]; 390 else if (varsSetInCurrentBlock.length <= offset) 391 { 392 boolean[] tmp = new boolean[local_types.length]; 393 System.arraycopy(varsSetInCurrentBlock, 0, tmp, 0, varsSetInCurrentBlock.length); 394 varsSetInCurrentBlock = tmp; 395 } 396 varsSetInCurrentBlock[offset] = true; 397 if (offset > 0) 398 { 399 Type prev = local_types[offset-1]; 400 if (prev != null && prev.getSizeInWords() == 2) 401 local_types[offset-1] = null; 402 } 403 while (--size > 0) 404 local_types[++offset] = null; 405 } 406 407 /** Set the current type state from a label. */ setTypes(Label label)408 public final void setTypes (Label label) 409 { 410 setTypes(label.localTypes, label.stackTypes); 411 } 412 413 /** Set the current type state from a label. */ setTypes(Type[] labelLocals, Type[] labelStack)414 public final void setTypes (Type[] labelLocals, Type[] labelStack) 415 { 416 int usedStack = labelStack.length; 417 int usedLocals = labelLocals.length; 418 if (local_types != null) 419 { 420 if (usedLocals > 0) 421 System.arraycopy(labelLocals, 0, local_types, 0, usedLocals); 422 for (int i = usedLocals; i < local_types.length; i++) 423 local_types[i] = null; 424 } 425 if (stack_types == null || usedStack > stack_types.length) 426 stack_types = new Type[usedStack]; 427 else 428 { 429 for (int i = usedStack; i < stack_types.length; i++) 430 stack_types[i] = null; 431 } 432 System.arraycopy(labelStack, 0, stack_types, 0, usedStack); 433 SP = usedStack; 434 } 435 pushType(Type type)436 public final void pushType(Type type) 437 { 438 if (type.size == 0) 439 throw new Error ("pushing void type onto stack"); 440 if (stack_types == null || stack_types.length == 0) // ?? 441 stack_types = new Type[20]; 442 else if (SP + 1 >= stack_types.length) { 443 Type[] new_array = new Type[2 * stack_types.length]; 444 System.arraycopy (stack_types, 0, new_array, 0, SP); 445 stack_types = new_array; 446 } 447 if (type.size == 8) 448 stack_types[SP++] = Type.voidType; 449 stack_types[SP++] = type; 450 if (SP > max_stack) 451 max_stack = SP; 452 } 453 popType()454 public final Type popType () 455 { 456 if (SP <= 0) 457 throw new Error("popType called with empty stack "+getMethod()); 458 Type type = stack_types[--SP]; 459 if (type.size == 8) 460 if (! popType().isVoid()) 461 throw new Error("missing void type on stack"); 462 return type; 463 } 464 topType()465 public final Type topType () 466 { 467 return stack_types[SP - 1]; 468 } 469 470 /** Compile code to pop values off the stack (and ignore them). 471 * @param nvalues the number of values (not words) to pop 472 */ emitPop(int nvalues)473 public void emitPop (int nvalues) 474 { 475 for ( ; nvalues > 0; --nvalues) 476 { 477 reserve(1); 478 Type type = popType(); 479 if (type.size > 4) 480 put1(88); // pop2 481 else if (nvalues > 1) 482 { // optimization: can we pop 2 4-byte words using a pop2 483 Type type2 = popType(); 484 if (type2.size > 4) 485 { 486 put1(87); // pop 487 reserve(1); 488 } 489 put1(88); // pop2 490 --nvalues; 491 } 492 else 493 put1(87); // pop 494 } 495 } 496 497 /** Get a new Label for the current location. 498 * Unlike Label.define, does not change reachableHere(). 499 */ getLabel()500 public Label getLabel () 501 { 502 Label label = new Label(); 503 label.defineRaw(this); 504 return label; 505 } 506 emitSwap()507 public void emitSwap () 508 { 509 reserve(1); 510 Type type1 = popType(); 511 Type type2 = popType(); 512 513 if (type1.size > 4 || type2.size > 4) 514 { 515 // There is no swap instruction in the JVM for this case. 516 // Fall back to a more convoluted way. 517 pushType(type2); 518 pushType(type1); 519 emitDupX(); 520 emitPop(1); 521 } 522 else 523 { 524 pushType(type1); 525 put1(95); // swap 526 pushType(type2); 527 } 528 } 529 530 /** Emit code to duplicate the top element of the stack. */ emitDup()531 public void emitDup () 532 { 533 reserve(1); 534 535 Type type = topType(); 536 put1 (type.size <= 4 ? 89 : 92); // dup or dup2 537 pushType (type); 538 } 539 540 /** Emit code to duplicate the top element of the stack 541 and place the copy before the previous element. */ emitDupX()542 public void emitDupX () 543 { 544 reserve(1); 545 546 Type type = popType(); 547 Type skipedType = popType(); 548 549 if (skipedType.size <= 4) 550 put1 (type.size <= 4 ? 90 : 93); // dup_x1 or dup2_x1 551 else 552 put1 (type.size <= 4 ? 91 : 94); // dup_x2 or dup2_x2 553 554 pushType (type); 555 pushType (skipedType); 556 pushType (type); 557 } 558 559 /** Compile code to duplicate with offset. 560 * @param size the size of the stack item to duplicate (1 or 2) 561 * @param offset where to insert the result (must be 0, 1, or 2) 562 * The new words get inserted at stack[SP-size-offset] 563 */ emitDup(int size, int offset)564 public void emitDup (int size, int offset) 565 { 566 if (size == 0) 567 return; 568 reserve(1); 569 // copied1 and (optionally copied2) are the types of the duplicated words 570 Type copied1 = popType (); 571 Type copied2 = null; 572 if (size == 1) 573 { 574 if (copied1.size > 4) 575 throw new Error ("using dup for 2-word type"); 576 } 577 else if (size != 2) 578 throw new Error ("invalid size to emitDup"); 579 else if (copied1.size <= 4) 580 { 581 copied2 = popType(); 582 if (copied2.size > 4) 583 throw new Error ("dup will cause invalid types on stack"); 584 } 585 586 int kind; 587 // These are the types of the words (in any) that are "skipped": 588 Type skipped1 = null; 589 Type skipped2 = null; 590 if (offset == 0) 591 { 592 kind = size == 1 ? 89 : 92; // dup or dup2 593 } 594 else if (offset == 1) 595 { 596 kind = size == 1 ? 90 : 93; // dup_x1 or dup2_x1 597 skipped1 = popType (); 598 if (skipped1.size > 4) 599 throw new Error ("dup will cause invalid types on stack"); 600 } 601 else if (offset == 2) 602 { 603 kind = size == 1 ? 91 : 94; // dup_x2 or dup2_x2 604 skipped1 = popType(); 605 if (skipped1.size <= 4) 606 { 607 skipped2 = popType(); 608 if (skipped2.size > 4) 609 throw new Error ("dup will cause invalid types on stack"); 610 } 611 } 612 else 613 throw new Error ("emitDup: invalid offset"); 614 615 put1(kind); 616 if (copied2 != null) 617 pushType(copied2); 618 pushType(copied1); 619 if (skipped2 != null) 620 pushType(skipped2); 621 if (skipped1 != null) 622 pushType(skipped1); 623 if (copied2 != null) 624 pushType(copied2); 625 pushType(copied1); 626 } 627 628 /** 629 * Compile code to duplicate the top 1 or 2 words. 630 * @param size number of words to duplicate 631 */ emitDup(int size)632 public void emitDup (int size) 633 { 634 emitDup(size, 0); 635 } 636 emitDup(Type type)637 public void emitDup (Type type) 638 { 639 emitDup(type.size > 4 ? 2 : 1, 0); 640 } 641 enterScope(Scope scope)642 public void enterScope (Scope scope) 643 { 644 scope.setStartPC(this); 645 locals.enterScope(scope); 646 } 647 pushScope()648 public Scope pushScope () 649 { 650 Scope scope = new Scope (); 651 if (locals == null) 652 locals = new LocalVarsAttr(getMethod()); 653 enterScope(scope); 654 if (locals.parameter_scope == null) 655 locals.parameter_scope = scope; 656 return scope; 657 } 658 659 /** Create a Scope that is automatically popped. 660 * I.e. the next popScope will keep popping autoPop scopes until 661 * it gets to a non-autoPop scope. An autoPop Scope is useful for 662 * variables that are assigned and set in the middle of a managed Scope. 663 */ pushAutoPoppableScope()664 public Scope pushAutoPoppableScope() { 665 Scope scope = pushScope(); 666 scope.autoPop = true; 667 return scope; 668 } 669 getCurrentScope()670 public Scope getCurrentScope() 671 { 672 return locals.current_scope; 673 } 674 popScope()675 public Scope popScope () { 676 Label end = getLabel(); 677 for (;;) { 678 Scope scope = locals.current_scope; 679 locals.current_scope = scope.parent; 680 scope.freeLocals(this); 681 scope.end = end; 682 if (! scope.autoPop) 683 return scope; 684 } 685 } 686 687 /** Get the index'th parameter. */ getArg(int index)688 public Variable getArg (int index) 689 { 690 return locals.parameter_scope.getVariable(index); 691 } 692 693 /** 694 * Search by name for a Variable 695 * @param name name to search for 696 * @return the Variable, or null if not found (in any scope of this Method). 697 */ lookup(String name)698 public Variable lookup (String name) 699 { 700 Scope scope = locals.current_scope; 701 for (; scope != null; scope = scope.parent) 702 { 703 Variable var = scope.lookup (name); 704 if (var != null) 705 return var; 706 } 707 return null; 708 } 709 710 /** Add a new local variable (in the current scope). 711 * @param type type of the new Variable. 712 * @return the new Variable. */ addLocal(Type type)713 public Variable addLocal (Type type) 714 { 715 return locals.current_scope.addVariable(this, type, null); 716 } 717 718 /** Add a new local variable (in the current scope). 719 * @param type type of the new Variable. 720 * @param name name of the new Variable. 721 * @return the new Variable. */ addLocal(Type type, String name)722 public Variable addLocal (Type type, String name) 723 { 724 return locals.current_scope.addVariable (this, type, name); 725 } 726 727 /** Call addLocal for parameters (as implied by method type). */ addParamLocals()728 public void addParamLocals() 729 { 730 Method method = getMethod(); 731 if ((method.access_flags & Access.STATIC) == 0) 732 addLocal(method.classfile).setParameter(true); 733 int arg_count = method.arg_types.length; 734 for (int i = 0; i < arg_count; i++) 735 addLocal(method.arg_types[i]).setParameter(true); 736 } 737 emitPushConstant(int val, Type type)738 public final void emitPushConstant(int val, Type type) 739 { 740 switch (type.getSignature().charAt(0)) 741 { 742 case 'B': case 'C': case 'I': case 'Z': case 'S': 743 emitPushInt(val); break; 744 case 'J': 745 emitPushLong((long)val); break; 746 case 'F': 747 emitPushFloat((float)val); break; 748 case 'D': 749 emitPushDouble((double)val); break; 750 default: 751 throw new Error("bad type to emitPushConstant"); 752 } 753 } 754 755 /* Low-level method to pust a ConstantPool entry. 756 * Does not do the appropriatre <code>pushType</code>. */ emitPushConstant(CpoolEntry cnst)757 public final void emitPushConstant (CpoolEntry cnst) 758 { 759 reserve(3); 760 int index = cnst.index; 761 if (cnst instanceof CpoolValue2) 762 { 763 put1 (20); // ldc2_w 764 put2 (index); 765 } 766 else if (index < 256) 767 { 768 put1(18); // ldc 769 put1(index); 770 } 771 else 772 { 773 put1(19); // ldc_w 774 put2(index); 775 } 776 } 777 emitPushInt(int i)778 public final void emitPushInt(int i) 779 { 780 reserve(3); 781 if (i >= -1 && i <= 5) 782 put1(i + 3); // iconst_m1 .. iconst_5 783 else if (i >= -128 && i < 128) 784 { 785 put1(16); // bipush 786 put1(i); 787 } 788 else if (i >= -32768 && i < 32768) 789 { 790 put1(17); // sipush 791 put2(i); 792 } 793 else 794 { 795 emitPushConstant(getConstants().addInt(i)); 796 } 797 pushType(Type.intType); 798 } 799 emitPushLong(long i)800 public void emitPushLong (long i) 801 { 802 if (i == 0 || i == 1) 803 { 804 reserve(1); 805 put1 (9 + (int) i); // lconst_0 .. lconst_1 806 } 807 else if ((long) (int) i == i) 808 { 809 emitPushInt ((int) i); 810 reserve(1); 811 popType(); 812 put1 (133); // i2l 813 } 814 else 815 { 816 emitPushConstant(getConstants().addLong(i)); 817 } 818 pushType(Type.longType); 819 } 820 emitPushFloat(float x)821 public void emitPushFloat (float x) 822 { 823 int xi = (int) x; 824 if ((float) xi == x && xi >= -128 && xi < 128) 825 { 826 if (xi >= 0 && xi <= 2) 827 { 828 reserve(1); 829 put1(11 + xi); // fconst_0 .. fconst_2 830 if (xi == 0 && Float.floatToIntBits(x) != 0) // x == -0.0 831 { 832 reserve(1); 833 put1(118); // fneg 834 } 835 } 836 else 837 { 838 // Saves space in the constant pool 839 // Probably faster, at least on modern CPUs. 840 emitPushInt (xi); 841 reserve(1); 842 popType(); 843 put1 (134); // i2f 844 } 845 } 846 else 847 { 848 emitPushConstant(getConstants().addFloat(x)); 849 } 850 pushType(Type.floatType); 851 } 852 emitPushDouble(double x)853 public void emitPushDouble (double x) 854 { 855 int xi = (int) x; 856 if ((double) xi == x && xi >= -128 && xi < 128) 857 { 858 if (xi == 0 || xi == 1) 859 { 860 reserve(1); 861 put1(14+xi); // dconst_0 or dconst_1 862 if (xi == 0 && Double.doubleToLongBits(x) != 0L) // x == -0.0 863 { 864 reserve(1); 865 put1(119); // dneg 866 } 867 } 868 else 869 { 870 // Saves space in the constant pool 871 // Probably faster, at least on modern CPUs. 872 emitPushInt (xi); 873 reserve(1); 874 popType(); 875 put1 (135); // i2d 876 } 877 } 878 else 879 { 880 emitPushConstant(getConstants().addDouble(x)); 881 } 882 pushType(Type.doubleType); 883 } 884 885 /** Calculate how many CONSTANT_String constants we need for a string. 886 * Each CONSTANT_String can be at most 0xFFFF bytes (as a UTF8 string). 887 * Returns a String, where each char, coerced to an int, is the length 888 * of a substring of the input that is at most 0xFFFF bytes. 889 */ calculateSplit(String str)890 public static final String calculateSplit (String str) 891 { 892 int strLength = str.length(); 893 StringBuffer sbuf = new StringBuffer(20); 894 // Where the current segments starts, as an index in 'str': 895 int segmentStart = 0; 896 int byteLength = 0; // Length in bytes of current segment so far. 897 for (int i = 0; i < strLength; i++) 898 { 899 char ch = str.charAt(i); 900 int bytes = ch >= 0x0800 ? 3 : ch >= 0x0080 || ch == 0 ? 2 : 1; 901 if (byteLength + bytes > 0xFFFF) 902 { 903 sbuf.append((char) (i - segmentStart)); 904 segmentStart = i; 905 byteLength = 0; 906 } 907 byteLength += bytes; 908 } 909 sbuf.append((char) (strLength - segmentStart)); 910 return sbuf.toString(); 911 } 912 913 /** Emit code to push the value of a constant String. 914 * Uses CONSTANT_String and CONSTANT_Utf8 constant pool entries as needed. 915 * Can handle Strings whose UTF8 length is greates than 0xFFFF bytes 916 * (the limit of a CONSTANT_Utf8) by generating String concatenation. 917 */ emitPushString(String str)918 public final void emitPushString (String str) 919 { 920 if (str == null) 921 emitPushNull(); 922 else 923 { 924 int length = str.length(); 925 String segments = calculateSplit(str); 926 int numSegments = segments.length(); 927 if (numSegments <= 1) 928 emitPushConstant(getConstants().addString(str)); 929 else 930 { 931 if (numSegments == 2) 932 { 933 int firstSegment = (int) segments.charAt(0); 934 emitPushString(str.substring(0, firstSegment)); 935 emitPushString(str.substring(firstSegment)); 936 Method concatMethod 937 = Type.javalangStringType.getDeclaredMethod("concat", 1); 938 emitInvokeVirtual(concatMethod); 939 } 940 else 941 { 942 ClassType sbufType = ClassType.make("java.lang.StringBuffer"); 943 emitNew(sbufType); 944 emitDup(sbufType); 945 emitPushInt(length); 946 Type[] args1 = { Type.intType }; 947 emitInvokeSpecial(sbufType.getDeclaredMethod("<init>", args1)); 948 Type[] args2 = { Type.javalangStringType }; 949 Method appendMethod 950 = sbufType.getDeclaredMethod("append", args2); 951 int segStart = 0; 952 for (int seg = 0; seg < numSegments; seg++) 953 { 954 emitDup(sbufType); 955 int segEnd = segStart + (int) segments.charAt(seg); 956 emitPushString(str.substring(segStart, segEnd)); 957 emitInvokeVirtual(appendMethod); 958 segStart = segEnd; 959 } 960 emitInvokeVirtual(Type.toString_method); 961 } 962 if (str == str.intern()) 963 emitInvokeVirtual(Type.javalangStringType.getDeclaredMethod("intern", 0)); 964 return; 965 } 966 pushType(Type.javalangStringType); 967 } 968 } 969 970 /** Push a class constant pool entry. 971 * This is only supported by JDK 1.5 and later. */ emitPushClass(ObjectType ctype)972 public final void emitPushClass (ObjectType ctype) 973 { 974 emitPushConstant(getConstants().addClass(ctype)); 975 pushType(Type.javalangClassType); 976 } 977 978 /** Push a MethodHandle, using an appropriate constant pool entry. 979 * This is only supported by JDK 1.6 and later. 980 */ emitPushMethodHandle(Method method)981 public final void emitPushMethodHandle(Method method) { 982 emitPushConstant(getConstants().addMethodHandle(method)); 983 pushType(Type.javalanginvokeMethodHandleType); 984 } 985 emitPushNull()986 public void emitPushNull() { emitPushNull(Type.nullType); } 987 emitPushNull(ObjectType type)988 public void emitPushNull(ObjectType type) { 989 reserve(1); 990 put1(1); // aconst_null 991 pushType(type); 992 } 993 994 /** Push zero or null as appropriate for the given type. */ emitPushDefaultValue(Type type)995 public void emitPushDefaultValue (Type type) 996 { 997 type = type.getImplementationType(); 998 if (type instanceof PrimType) 999 emitPushConstant(0, type); 1000 else 1001 emitPushNull(); 1002 } 1003 1004 /** Initialize a variable to zero or null, as appropriate. */ emitStoreDefaultValue(Variable var)1005 public void emitStoreDefaultValue (Variable var) 1006 { 1007 emitPushDefaultValue(var.getType()); 1008 emitStore(var); 1009 } 1010 emitPushThis()1011 public final void emitPushThis() 1012 { 1013 emitLoad(locals.used[0]); 1014 } 1015 emitPushPrimArray(Object value, ArrayType arrayType)1016 public final void emitPushPrimArray(Object value, ArrayType arrayType) 1017 { 1018 int len = java.lang.reflect.Array.getLength(value); 1019 emitPushPrimArray(value, len, len, arrayType); 1020 } 1021 1022 /** Emit code to push a constant primitive array. 1023 * @param value The array value that we want the emitted code to re-create. 1024 * @param arrayType The ArrayType that matches value. 1025 */ emitPushPrimArray(Object value, int len, int count, ArrayType arrayType)1026 public final void emitPushPrimArray(Object value, int len, int count, 1027 ArrayType arrayType) 1028 { 1029 Type elementType = arrayType.getComponentType(); 1030 emitPushInt(len); 1031 emitNewArray(elementType); 1032 char sig = elementType.getSignature().charAt(0); 1033 for (int i = 0; i < count; i++) 1034 { 1035 long ival = 0; float fval = 0; double dval = 0; 1036 switch (sig) 1037 { 1038 case 'J': 1039 ival = ((long[]) value)[i]; 1040 if (ival == 0) 1041 continue; 1042 break; 1043 case 'I': 1044 ival = ((int[]) value)[i]; 1045 if (ival == 0) 1046 continue; 1047 break; 1048 case 'S': 1049 ival = ((short[]) value)[i]; 1050 if (ival == 0) 1051 continue; 1052 break; 1053 case 'C': 1054 ival = ((char[]) value)[i]; 1055 if (ival == 0) 1056 continue; 1057 break; 1058 case 'B': 1059 ival = ((byte[]) value)[i]; 1060 if (ival == 0) 1061 continue; 1062 break; 1063 case 'Z': 1064 ival = ((boolean[]) value)[i] ? 1 : 0; 1065 if (ival == 0) 1066 continue; 1067 break; 1068 case 'F': 1069 fval = ((float[]) value)[i]; 1070 if (fval == 0.0) 1071 continue; 1072 break; 1073 case 'D': 1074 dval = ((double[]) value)[i]; 1075 if (dval == 0.0) 1076 continue; 1077 break; 1078 } 1079 emitDup(arrayType); 1080 emitPushInt(i); 1081 switch (sig) 1082 { 1083 case 'Z': 1084 case 'C': 1085 case 'B': 1086 case 'S': 1087 case 'I': 1088 emitPushInt((int) ival); 1089 break; 1090 case 'J': 1091 emitPushLong(ival); 1092 break; 1093 case 'F': 1094 emitPushFloat(fval); 1095 break; 1096 case 'D': 1097 emitPushDouble(dval); 1098 break; 1099 } 1100 emitArrayStore(elementType); 1101 } 1102 } 1103 1104 1105 emitNewArray(int type_code)1106 void emitNewArray (int type_code) 1107 { 1108 reserve(2); 1109 put1(188); // newarray 1110 put1(type_code); 1111 } 1112 emitArrayLength()1113 public final void emitArrayLength () 1114 { 1115 if (! (popType() instanceof ArrayType)) 1116 throw new Error( "non-array type in emitArrayLength" ); 1117 1118 reserve(1); 1119 put1(190); // arraylength 1120 pushType(Type.intType); 1121 } 1122 1123 /* Returns an integer in the range 0 (for 'int') through 4 (for object 1124 reference) to 7 (for 'short') which matches the pattern of how JVM 1125 opcodes typically depend on the operand type. */ 1126 adjustTypedOp(char sig)1127 private int adjustTypedOp (char sig) 1128 { 1129 switch (sig) 1130 { 1131 case 'I': return 0; // int 1132 case 'J': return 1; // long 1133 case 'F': return 2; // float 1134 case 'D': return 3; // double 1135 default: return 4; // object 1136 case 'B': 1137 case 'Z': return 5; // byte or boolean 1138 case 'C': return 6; // char 1139 case 'S': return 7; // short 1140 } 1141 } 1142 adjustTypedOp(Type type)1143 private int adjustTypedOp (Type type) 1144 { 1145 return adjustTypedOp(type.getSignature().charAt(0)); 1146 } 1147 emitTypedOp(int op, Type type)1148 private void emitTypedOp (int op, Type type) 1149 { 1150 reserve(1); 1151 put1(op + adjustTypedOp(type)); 1152 } 1153 emitTypedOp(int op, char sig)1154 private void emitTypedOp (int op, char sig) 1155 { 1156 reserve(1); 1157 put1(op + adjustTypedOp(sig)); 1158 } 1159 1160 /** Store into an element of an array. 1161 * Must already have pushed the array reference, the index, 1162 * and the new value (in that order). 1163 * Stack: {@literal ..., array, index, value => ...} 1164 */ emitArrayStore(Type element_type)1165 public void emitArrayStore (Type element_type) 1166 { 1167 popType(); // Pop new value 1168 popType(); // Pop index 1169 popType(); // Pop array reference 1170 emitTypedOp(79, element_type); 1171 } 1172 1173 /** Store into an element of an array. 1174 * Must already have pushed the array reference, the index, 1175 * and the new value (in that order). 1176 * Stack: {@literal ..., array, index, value => ...} 1177 */ emitArrayStore()1178 public void emitArrayStore () 1179 { 1180 popType(); // Pop new value 1181 popType(); // Pop index 1182 Type arrayType = popType().getImplementationType(); // Pop array reference 1183 Type elementType = ((ArrayType) arrayType).getComponentType(); 1184 emitTypedOp(79, elementType); 1185 } 1186 1187 /** Load an element from an array. 1188 * Must already have pushed the array and the index (in that order): 1189 * Stack: {@literal ..., array, index => ..., value} 1190 */ emitArrayLoad(Type element_type)1191 public void emitArrayLoad (Type element_type) 1192 { 1193 popType(); // Pop index 1194 popType(); // Pop array reference 1195 emitTypedOp(46, element_type); 1196 pushType(element_type); 1197 } 1198 1199 /** Load an element from an array. 1200 * Equivalent to {@code emitArrayLoad(Type)}, but element_type is implied. 1201 * Must already have pushed the array and the index (in that order): 1202 * Stack: {@literal ..., array, index => ..., value} 1203 */ emitArrayLoad()1204 public void emitArrayLoad () 1205 { 1206 popType(); // Pop index 1207 Type arrayType = popType().getImplementationType(); 1208 Type elementType = ((ArrayType) arrayType).getComponentType(); 1209 emitTypedOp(46, elementType); 1210 pushType(elementType); 1211 } 1212 1213 /** 1214 * Invoke new on a class type. 1215 * Does not call the constructor! 1216 * @param type the desired new object type 1217 */ emitNew(ClassType type)1218 public void emitNew (ClassType type) 1219 { 1220 reserve(3); 1221 Label label = new Label(this); 1222 label.defineRaw(this); 1223 put1(187); // new 1224 putIndex2(getConstants().addClass(type)); 1225 pushType(new UninitializedType(type, label)); 1226 } 1227 1228 /** Compile code to allocate a new array. 1229 * The size should have been already pushed on the stack. 1230 * @param element_type type of the array elements 1231 * @param dims number of dimensions - more than 1 is untested 1232 */ emitNewArray(Type element_type, int dims)1233 public void emitNewArray (Type element_type, int dims) 1234 { 1235 if (popType ().promote () != Type.intType) 1236 throw new Error ("non-int dim. spec. in emitNewArray"); 1237 1238 if (element_type instanceof PrimType) 1239 { 1240 int code; 1241 switch (element_type.getSignature().charAt(0)) 1242 { 1243 case 'B': code = 8; break; 1244 case 'S': code = 9; break; 1245 case 'I': code = 10; break; 1246 case 'J': code = 11; break; 1247 case 'F': code = 6; break; 1248 case 'D': code = 7; break; 1249 case 'Z': code = 4; break; 1250 case 'C': code = 5; break; 1251 default: throw new Error("bad PrimType in emitNewArray"); 1252 } 1253 emitNewArray(code); 1254 } 1255 else if (element_type instanceof ArrayType && dims > 1) // untested 1256 { 1257 reserve(4); 1258 put1(197); // multianewarray 1259 putIndex2 (getConstants ().addClass (new ArrayType (element_type))); 1260 if (dims < 1 || dims > 255) 1261 throw new Error ("dims out of range in emitNewArray"); 1262 put1(dims); 1263 while (-- dims > 0) // first dim already popped 1264 if (popType ().promote () != Type.intType) 1265 throw new Error ("non-int dim. spec. in emitNewArray"); 1266 } 1267 else if (element_type instanceof ObjectType) 1268 { 1269 reserve(3); 1270 put1(189); // anewarray 1271 putIndex2(getConstants().addClass((ObjectType) element_type)); 1272 } 1273 else 1274 throw new Error ("unimplemented type in emitNewArray"); 1275 1276 pushType (new ArrayType (element_type)); 1277 } 1278 emitNewArray(Type element_type)1279 public void emitNewArray (Type element_type) 1280 { 1281 emitNewArray (element_type, 1); 1282 } 1283 1284 // We may want to deprecate this, because it depends on popType. emitBinop(int base_code)1285 private void emitBinop (int base_code) 1286 { 1287 Type type2 = popType().promote(); 1288 Type type1_raw = popType(); 1289 Type type1 = type1_raw.promote(); 1290 if (type1 != type2 || ! (type1 instanceof PrimType)) 1291 throw new Error ("non-matching or bad types in binary operation"); 1292 emitTypedOp(base_code, type1); 1293 pushType(type1_raw); 1294 } 1295 emitBinop(int base_code, char sig)1296 private void emitBinop (int base_code, char sig) 1297 { 1298 popType(); 1299 popType(); 1300 emitTypedOp(base_code, sig); 1301 pushType(Type.signatureToPrimitive(sig)); 1302 } 1303 emitBinop(int base_code, Type type)1304 public void emitBinop (int base_code, Type type) 1305 { 1306 popType(); 1307 popType(); 1308 emitTypedOp(base_code, type); 1309 pushType(type); 1310 } 1311 1312 // public final void emitIntAdd () { put1(96); popType();} 1313 // public final void emitLongAdd () { put1(97); popType();} 1314 // public final void emitFloatAdd () { put1(98); popType();} 1315 // public final void emitDoubleAdd () { put1(99); popType();} 1316 emitAdd(char sig)1317 public final void emitAdd(char sig) { emitBinop (96, sig); } emitAdd(PrimType type)1318 public final void emitAdd(PrimType type) { emitBinop (96, type); } emitAdd()1319 @Deprecated public final void emitAdd () { emitBinop (96); } 1320 emitSub(char sig)1321 public final void emitSub(char sig) { emitBinop (100, sig); } emitSub(PrimType type)1322 public final void emitSub(PrimType type) { emitBinop (100, type); } emitSub()1323 @Deprecated public final void emitSub () { emitBinop (100); } 1324 emitMul()1325 public final void emitMul () { emitBinop (104); } emitDiv()1326 public final void emitDiv () { emitBinop (108); } emitRem()1327 public final void emitRem () { emitBinop (112); } emitAnd()1328 public final void emitAnd () { emitBinop (126); } emitIOr()1329 public final void emitIOr () { emitBinop (128); } emitXOr()1330 public final void emitXOr () { emitBinop (130); } 1331 emitShl()1332 public final void emitShl () { emitShift (120); } emitShr()1333 public final void emitShr () { emitShift (122); } emitUshr()1334 public final void emitUshr() { emitShift (124); } 1335 emitShift(int base_code)1336 private void emitShift (int base_code) 1337 { 1338 Type type2 = popType().promote(); 1339 Type type1_raw = popType(); 1340 Type type1 = type1_raw.promote(); 1341 1342 if (type1 != Type.intType && type1 != Type.longType) 1343 throw new Error ("the value shifted must be an int or a long"); 1344 1345 if (type2 != Type.intType) 1346 throw new Error ("the amount of shift must be an int"); 1347 1348 emitTypedOp(base_code, type1); 1349 pushType(type1_raw); 1350 } 1351 1352 /** Compile 'not', assuming 0 or 1 is on the JVM stack. */ emitNot(Type type)1353 public final void emitNot(Type type) 1354 { 1355 emitPushConstant(1, type); 1356 emitAdd(); 1357 emitPushConstant(1, type); 1358 emitAnd(); 1359 } 1360 emitPrimop(int opcode, int arg_count, Type retType)1361 public void emitPrimop (int opcode, int arg_count, Type retType) 1362 { 1363 reserve(1); 1364 while (-- arg_count >= 0) 1365 popType(); 1366 put1(opcode); 1367 pushType(retType); 1368 } 1369 emitMaybeWide(int opcode, int index)1370 void emitMaybeWide (int opcode, int index) 1371 { 1372 if (index >= 256) 1373 { 1374 put1(196); // wide 1375 put1(opcode); 1376 put2(index); 1377 } 1378 else 1379 { 1380 put1(opcode); 1381 put1(index); 1382 } 1383 } 1384 1385 /** 1386 * Compile code to push the contents of a local variable onto the statck. 1387 * @param var The variable whose contents we want to push. 1388 */ emitLoad(Variable var)1389 public final void emitLoad (Variable var) 1390 { 1391 if (var.dead()) 1392 throw new Error("attempting to push dead variable"); 1393 int offset = var.offset; 1394 if (offset < 0 || !var.isSimple()) 1395 throw new Error ("attempting to load from unassigned variable "+var 1396 +" simple:"+var.isSimple()+", offset: "+offset); 1397 Type type = var.getType().promote(); 1398 reserve(4); 1399 int kind = adjustTypedOp(type); 1400 if (offset <= 3) 1401 put1(26 + 4 * kind + offset); // [ilfda]load_[0123] 1402 else 1403 emitMaybeWide(21 + kind, offset); // [ilfda]load 1404 pushType(var.getType()); 1405 } 1406 emitStore(Variable var)1407 public void emitStore (Variable var) 1408 { 1409 if (! reachableHere()) 1410 return; 1411 int offset = var.offset; 1412 if (offset < 0 || !var.isSimple ()) 1413 throw new Error ("attempting to store in unassigned "+var 1414 +" simple:"+var.isSimple()+", offset: "+offset); 1415 Type type = var.getType().promote (); 1416 noteVarType(offset, type); 1417 reserve(4); 1418 popType(); 1419 int kind = adjustTypedOp(type); 1420 if (offset <= 3) 1421 put1(59 + 4 * kind + offset); // [ilfda]store_[0123] 1422 else 1423 emitMaybeWide(54 + kind, offset); // [ilfda]store 1424 } 1425 1426 1427 /** Emit an instruction to increment a variable by some amount. 1428 * If the increment is zero, do nothing. 1429 * The variable must contain an integral value - except if increment is zero. 1430 */ emitInc(Variable var, short inc)1431 public void emitInc (Variable var, short inc) 1432 { 1433 if (var.dead ()) 1434 throw new Error ("attempting to increment dead variable"); 1435 int offset = var.offset; 1436 if (offset < 0 || !var.isSimple ()) 1437 throw new Error ("attempting to increment unassigned variable"+var.getName() 1438 +" simple:"+var.isSimple()+", offset: "+offset); 1439 1440 if (inc == 0) 1441 return; 1442 1443 reserve(6); 1444 if (var.getType().getImplementationType().promote() != Type.intType) 1445 throw new Error("attempting to increment non-int variable"); 1446 1447 boolean wide = offset > 255 || inc > 255 || inc < -256; 1448 if (wide) 1449 { 1450 put1(196); // wide 1451 put1(132); // iinc 1452 put2(offset); 1453 put2(inc); 1454 } 1455 else 1456 { 1457 put1(132); // iinc 1458 put1(offset); 1459 put1(inc); 1460 } 1461 } 1462 1463 1464 private final void emitFieldop (Field field, int opcode) 1465 { 1466 reserve(3); 1467 put1(opcode); 1468 putIndex2(getConstants().addFieldRef(field)); 1469 } 1470 1471 /** Compile code to get a static field value. 1472 * Stack: {@code ... => ..., value} */ 1473 1474 public final void emitGetStatic(Field field) 1475 { 1476 pushType(field.getType()); 1477 emitFieldop (field, 178); // getstatic 1478 } 1479 1480 /** Compile code to get a non-static field value. 1481 * Stack: {@code ..., objectref => ..., value} */ 1482 1483 public final void emitGetField(Field field) 1484 { 1485 popType(); 1486 pushType(field.getType()); 1487 emitFieldop(field, 180); // getfield 1488 } 1489 1490 /** Compile code to put a static field value. 1491 * Stack: {@code ..., value => ...} */ 1492 1493 public final void emitPutStatic (Field field) 1494 { 1495 popType(); 1496 emitFieldop(field, 179); // putstatic 1497 } 1498 1499 /** Compile code to put a non-static field value. 1500 * Stack: {@code ..., objectref, value => ...} */ 1501 1502 public final void emitPutField (Field field) 1503 { 1504 popType(); 1505 popType(); 1506 emitFieldop(field, 181); // putfield 1507 } 1508 1509 /** Comptes the number of stack words taken by a list of types. */ 1510 private int words(Type[] types) 1511 { 1512 int res = 0; 1513 for (int i=types.length; --i >= 0; ) 1514 if (types[i].size > 4) 1515 res+=2; 1516 else 1517 res++; 1518 return res; 1519 } 1520 emitInvokeMethod(Method method, int opcode)1521 public void emitInvokeMethod (Method method, int opcode) 1522 { 1523 if (! reachableHere()) 1524 return; 1525 reserve(opcode == 185 ? 5 : 3); 1526 int arg_count = method.arg_types.length; 1527 boolean is_invokestatic = opcode == 184; 1528 boolean is_init = opcode == 183 && "<init>".equals(method.getName()); 1529 1530 if (is_invokestatic != ((method.access_flags & Access.STATIC) != 0)) 1531 throw new Error 1532 ("emitInvokeXxx static flag mis-match method.flags="+method.access_flags); 1533 if (!is_invokestatic && !is_init) 1534 arg_count++; 1535 put1(opcode); // invokevirtual, invokespecial, or invokestatic 1536 putIndex2(getConstants().addMethodRef(method)); 1537 if (opcode == 185) // invokeinterface 1538 { 1539 put1(words(method.arg_types)+1); // 1 word for 'this' 1540 put1(0); 1541 } 1542 while (--arg_count >= 0) 1543 { 1544 Type t = popType(); 1545 if (t instanceof UninitializedType) 1546 throw new Error("passing "+t+" as parameter"); 1547 } 1548 if (is_init) 1549 { 1550 Type t = popType(); 1551 ClassType ctype; 1552 if (! (t instanceof UninitializedType)) 1553 throw new Error("calling <init> on already-initialized object"); 1554 ctype = ((UninitializedType) t).ctype; 1555 for (int i = 0; i < SP; i++) 1556 if (stack_types[i] == t) 1557 stack_types[i] = ctype; 1558 Variable[] used = locals.used; 1559 for (int i = used == null ? 0 : used.length; --i >= 0; ) 1560 { 1561 Variable var = used[i]; 1562 if (var != null && var.getType() == t) 1563 var.setType(ctype); 1564 } 1565 for (int i = local_types == null ? 0 : local_types.length; --i >= 0; ) 1566 { 1567 if (local_types[i] == t) 1568 local_types[i] = ctype; 1569 } 1570 } 1571 if (method.return_type.size != 0) 1572 pushType(method.return_type); 1573 } 1574 emitInvoke(Method method)1575 public void emitInvoke (Method method) 1576 { 1577 int opcode; 1578 if ((method.access_flags & Access.STATIC) != 0) 1579 opcode = 184; // invokestatic 1580 else if (method.classfile.isInterface()) 1581 opcode = 185; // invokeinterface 1582 else if ("<init>".equals(method.getName()) 1583 || (method.access_flags & Access.PRIVATE) != 0) 1584 opcode = 183; // invokespecial 1585 else 1586 opcode = 182; // invokevirtual 1587 emitInvokeMethod(method, opcode); 1588 } 1589 1590 /** Compile a virtual method call. 1591 * The stack contains the 'this' object, followed by the arguments in order. 1592 * @param method the method to invoke virtually 1593 */ emitInvokeVirtual(Method method)1594 public void emitInvokeVirtual (Method method) 1595 { 1596 emitInvokeMethod(method, 182); // invokevirtual 1597 } 1598 emitInvokeSpecial(Method method)1599 public void emitInvokeSpecial (Method method) 1600 { 1601 emitInvokeMethod(method, 183); // invokespecial 1602 } 1603 1604 /** Compile a static method call. 1605 * The stack contains the the arguments in order. 1606 * @param method the static method to invoke 1607 */ emitInvokeStatic(Method method)1608 public void emitInvokeStatic (Method method) 1609 { 1610 emitInvokeMethod(method, 184); // invokestatic 1611 } 1612 emitInvokeInterface(Method method)1613 public void emitInvokeInterface (Method method) 1614 { 1615 emitInvokeMethod(method, 185); // invokeinterface 1616 } 1617 emitTransfer(Label label, int opcode)1618 final void emitTransfer (Label label, int opcode) 1619 { 1620 label.setTypes(this); 1621 fixupAdd(FIXUP_TRANSFER, label); 1622 put1(opcode); 1623 PC += 2; 1624 } 1625 1626 /** Compile an unconditional branch (goto). 1627 * @param label target of the branch (must be in this method). 1628 */ emitGoto(Label label)1629 public final void emitGoto (Label label) 1630 { 1631 label.setTypes(this); 1632 fixupAdd(FIXUP_GOTO, label); 1633 reserve(3); 1634 put1(167); 1635 PC += 2; 1636 setUnreachable(); 1637 } 1638 emitJsr(Label label)1639 public final void emitJsr (Label label) 1640 { 1641 fixupAdd(FIXUP_JSR, label); 1642 reserve(3); 1643 put1(168); 1644 PC += 2; 1645 } 1646 1647 ExitableBlock currentExitableBlock; 1648 int exitableBlockLevel; 1649 1650 /** Enter a block which can be exited. 1651 * Used to make sure finally-blocks are executed when exiting a block, 1652 * loop, or method. 1653 */ startExitableBlock(Type resultType, boolean runFinallyBlocks)1654 public ExitableBlock startExitableBlock (Type resultType, boolean runFinallyBlocks) 1655 { 1656 ExitableBlock bl = new ExitableBlock(resultType, this, runFinallyBlocks); 1657 bl.outer = currentExitableBlock; 1658 currentExitableBlock = bl; 1659 return bl; 1660 } 1661 1662 /** End a block entered by a previous startExitableBlock. 1663 */ endExitableBlock()1664 public void endExitableBlock () 1665 { 1666 ExitableBlock bl = currentExitableBlock; 1667 bl.finish(); 1668 currentExitableBlock = bl.outer; 1669 } 1670 emitGotoIfCompare1(Label label, int opcode)1671 public final void emitGotoIfCompare1 (Label label, int opcode) 1672 { 1673 popType(); 1674 reserve(3); 1675 emitTransfer (label, opcode); 1676 } 1677 emitGotoIfIntEqZero(Label label)1678 public final void emitGotoIfIntEqZero(Label label) 1679 { emitGotoIfCompare1(label, 153); } emitGotoIfIntNeZero(Label label)1680 public final void emitGotoIfIntNeZero(Label label) 1681 { emitGotoIfCompare1(label, 154); } emitGotoIfIntLtZero(Label label)1682 public final void emitGotoIfIntLtZero(Label label) 1683 { emitGotoIfCompare1(label, 155); } emitGotoIfIntGeZero(Label label)1684 public final void emitGotoIfIntGeZero(Label label) 1685 { emitGotoIfCompare1(label, 156); } emitGotoIfIntGtZero(Label label)1686 public final void emitGotoIfIntGtZero(Label label) 1687 { emitGotoIfCompare1(label, 157); } emitGotoIfIntLeZero(Label label)1688 public final void emitGotoIfIntLeZero(Label label) 1689 { emitGotoIfCompare1(label, 158); } emitGotoIfNull(Label label)1690 public final void emitGotoIfNull(Label label) 1691 { emitGotoIfCompare1(label, 198); } emitGotoIfNonNull(Label label)1692 public final void emitGotoIfNonNull(Label label) 1693 { emitGotoIfCompare1(label, 199); } 1694 emitGotoIfCompare2(Label label, int logop)1695 public final void emitGotoIfCompare2 (Label label, int logop) 1696 { 1697 Type type2 = popType().promote(); 1698 Type type1 = popType().promote(); 1699 reserve(4); 1700 char sig1 = type1.getSignature().charAt(0); 1701 char sig2 = type2.getSignature().charAt(0); 1702 1703 boolean cmpg = (logop == 155 || logop == 158); // iflt,ifle 1704 1705 if (sig1 == 'I' && sig2 == 'I') 1706 logop += 6; // iflt -> if_icmplt etc. 1707 else if (sig1 == 'J' && sig2 == 'J') 1708 put1(148); // lcmp 1709 else if (sig1 == 'F' && sig2 == 'F') 1710 put1(cmpg ? 149 : 150); // fcmpl/fcmpg 1711 else if (sig1 == 'D' && sig2 == 'D') 1712 put1(cmpg ? 151 : 152); // dcmpl/dcmpg 1713 else if ((sig1 == 'L' || sig1 == '[') 1714 && (sig2 == 'L' || sig2 == '[') 1715 && logop <= 154) 1716 logop += 12; // ifeq->if_acmpeq, ifne->if_acmpne 1717 else 1718 throw new Error ("invalid types to emitGotoIfCompare2"); 1719 1720 emitTransfer (label, logop); 1721 } 1722 1723 // binary comparisons 1724 @Deprecated emitGotoIfEq(Label label, boolean invert)1725 public final void emitGotoIfEq (Label label, boolean invert) 1726 { 1727 emitGotoIfCompare2(label, invert ? 154 : 153); 1728 } 1729 1730 /** Compile a conditional transfer if 2 top stack elements are equal. */ emitGotoIfEq(Label label)1731 public final void emitGotoIfEq (Label label) 1732 { 1733 emitGotoIfCompare2(label, 153); 1734 } 1735 1736 /** Compile conditional transfer if 2 top stack elements are not equal. */ emitGotoIfNE(Label label)1737 public final void emitGotoIfNE (Label label) 1738 { 1739 emitGotoIfCompare2(label, 154); 1740 } 1741 emitGotoIfLt(Label label)1742 public final void emitGotoIfLt(Label label) 1743 { emitGotoIfCompare2(label, 155); } emitGotoIfGe(Label label)1744 public final void emitGotoIfGe(Label label) 1745 { emitGotoIfCompare2(label, 156); } emitGotoIfGt(Label label)1746 public final void emitGotoIfGt(Label label) 1747 { emitGotoIfCompare2(label, 157); } emitGotoIfLe(Label label)1748 public final void emitGotoIfLe(Label label) 1749 { emitGotoIfCompare2(label, 158); } 1750 1751 1752 /** Compile start of a conditional: 1753 * <tt>if (!(<var>x</var> opcode 0)) ...</tt>. 1754 * The value of <var>x</var> must already have been pushed. */ emitIfCompare1(int opcode)1755 public final void emitIfCompare1 (int opcode) 1756 { 1757 if (popType().promote() != Type.intType) 1758 throw new Error ("non-int type to emitIfCompare1"); 1759 reserve(3); 1760 emitTransfer(emitIfRaw(), opcode); 1761 } 1762 1763 /** Compile start of conditional: <tt>if (x != 0) ...</tt>. 1764 * Also use this if you have pushed a boolean value: if (b) ... */ emitIfIntNotZero()1765 public final void emitIfIntNotZero() 1766 { 1767 emitIfCompare1(153); // ifeq 1768 } 1769 1770 /** Compile start of conditional: <tt>if (x == 0) ...</tt>. 1771 * Also use this if you have pushed a boolean value: if (!b) ... */ emitIfIntEqZero()1772 public final void emitIfIntEqZero() 1773 { 1774 emitIfCompare1(154); // ifne 1775 } 1776 1777 /** Compile start of conditional: {@code if (x <= 0)}. */ emitIfIntLEqZero()1778 public final void emitIfIntLEqZero() 1779 { 1780 emitIfCompare1(157); // ifgt 1781 } 1782 1783 /** Compile start of conditional: {@code if (x >= 0)}. */ emitIfIntGEqZero()1784 public final void emitIfIntGEqZero() 1785 { 1786 emitIfCompare1(155); // iflt 1787 } 1788 1789 /** Compile start of a conditional: {@code if (!(x opcode null)) ...}. 1790 * The value of <tt>x</tt> must already have been pushed and must be of 1791 * reference type. */ emitIfRefCompare1(int opcode)1792 public final void emitIfRefCompare1 (int opcode) 1793 { 1794 if (! (popType() instanceof ObjectType)) 1795 throw new Error ("non-ref type to emitIfRefCompare1"); 1796 reserve(3); 1797 emitTransfer(emitIfRaw(), opcode); 1798 } 1799 1800 /** Compile start of conditional: {@code if (x != null) ...}. */ emitIfNotNull()1801 public final void emitIfNotNull() 1802 { 1803 emitIfRefCompare1(198); // ifnull 1804 } 1805 1806 /** Compile start of conditional: {@code if (x == null) ...} */ emitIfNull()1807 public final void emitIfNull() 1808 { 1809 emitIfRefCompare1(199); // ifnonnull 1810 } 1811 1812 /** Compile start of a conditional: {@code if (!(x OPCODE y)) ...} 1813 * The value of x and y must already have been pushed. */ emitIfIntCompare(int opcode)1814 public final void emitIfIntCompare(int opcode) 1815 { 1816 popType(); 1817 popType(); 1818 reserve(3); 1819 emitTransfer(emitIfRaw(), opcode); 1820 } 1821 1822 /* Compile start of a conditional: {@code if (x < y) ...} */ emitIfIntLt()1823 public final void emitIfIntLt() 1824 { 1825 emitIfIntCompare(162); // if_icmpge 1826 } 1827 1828 /* Compile start of a conditional: {@code if (x >= y) ...} */ emitIfIntGEq()1829 public final void emitIfIntGEq() 1830 { 1831 emitIfIntCompare(161); // if_icmplt 1832 } 1833 1834 /** Compile start of a conditional: if (x != y) ... 1835 * The values of x and y must already have been pushed. */ emitIfNEq()1836 public final void emitIfNEq () 1837 { 1838 emitGotoIfEq(emitIfRaw()); 1839 } 1840 1841 /** Compile start of a conditional: {@code if (x == y) ...} 1842 * The values of x and y must already have been pushed. */ emitIfEq()1843 public final void emitIfEq () 1844 { 1845 emitGotoIfNE(emitIfRaw()); 1846 } 1847 1848 /** Compile start of a conditional: {@code if (x < y) ...} 1849 * The values of x and y must already have been pushed. */ emitIfLt()1850 public final void emitIfLt () 1851 { 1852 emitGotoIfGe(emitIfRaw()); 1853 } 1854 1855 /** Compile start of a conditional: {@code if (x >= y) ...} 1856 * The values of x and y must already have been pushed. */ emitIfGe()1857 public final void emitIfGe () 1858 { 1859 emitGotoIfLt(emitIfRaw()); 1860 } 1861 1862 /** Compile start of a conditional: {@code if (x > y) ...} 1863 * The values of x and y must already have been pushed. */ emitIfGt()1864 public final void emitIfGt () 1865 { 1866 emitGotoIfLe(emitIfRaw()); 1867 } 1868 1869 /** Compile start of a conditional: {@code if (x <= y) ...} 1870 * The values of x and y must already have been pushed. */ emitIfLe()1871 public final void emitIfLe () 1872 { 1873 emitGotoIfGt(emitIfRaw()); 1874 } 1875 1876 /** Emit a 'ret' instruction. 1877 * @param var the variable containing the return address */ emitRet(Variable var)1878 public void emitRet (Variable var) 1879 { 1880 int offset = var.offset; 1881 if (offset < 256) 1882 { 1883 reserve(2); 1884 put1(169); // ret 1885 put1(offset); 1886 } 1887 else 1888 { 1889 reserve(4); 1890 put1(196); // wide 1891 put1(169); // ret 1892 put2(offset); 1893 } 1894 } 1895 emitThen()1896 public final void emitThen() 1897 { 1898 } 1899 emitIfThen()1900 public final void emitIfThen () 1901 { 1902 new IfState(this, null); 1903 } 1904 1905 /** Compile start of else clause. */ emitElse()1906 public final void emitElse () 1907 { 1908 Label else_label = if_stack.end_label; 1909 if (reachableHere ()) 1910 { 1911 Label end_label = new Label (this); 1912 if_stack.end_label = end_label; 1913 emitGoto (end_label); 1914 } 1915 else 1916 if_stack.end_label = null; 1917 if (else_label != null) 1918 else_label.define (this); 1919 if_stack.doing_else = true; 1920 } 1921 1922 /** Compile end of conditional. */ emitFi()1923 public final void emitFi () 1924 { 1925 if (if_stack.end_label != null) 1926 if_stack.end_label.define (this); 1927 // Pop the if_stack. 1928 if_stack = if_stack.previous; 1929 } 1930 1931 /** Convenience for compiling {@code if P1 && P2 then S1 else S2}. 1932 * Compile that as: 1933 * <pre> 1934 * compile P1, including an appropriate emitIfXxx 1935 * emitAndThen() 1936 * compile P2, including an appropriate emitIfXxx 1937 * compile S1 1938 * emitElse 1939 * compile S2 1940 * emitFi 1941 * </pre> 1942 */ emitAndThen()1943 public void emitAndThen() { 1944 if (if_stack==null||if_stack.andThenSet) throw new InternalError(); 1945 if_stack.andThenSet = true; 1946 } 1947 1948 /** Start a new if/then/else block. 1949 * The caller is responsible for evaluating the condition, 1950 * and in the "false" case got the returned label. 1951 * In the "true" case just continue inline. 1952 * @return the else/end label to goto if the condition is false. 1953 * A subsequent emitElse or emitFi defines the label. 1954 */ emitIfRaw()1955 public Label emitIfRaw() { 1956 if (if_stack!=null && if_stack.andThenSet) { 1957 if_stack.andThenSet = false; 1958 } else 1959 new IfState(this); 1960 return if_stack.end_label; 1961 } 1962 fixUnsigned(Type stackType)1963 public final void fixUnsigned(Type stackType) { 1964 if (stackType instanceof PrimType 1965 && ((PrimType) stackType).isUnsigned()) { 1966 char sig1 = stackType.getSignature().charAt(0); 1967 if (sig1 == 'S') { 1968 reserve(1); 1969 put1(146); // i2c 1970 } else if (sig1 == 'B') { 1971 emitPushInt(255); 1972 emitAnd(); 1973 } 1974 } 1975 } 1976 emitConvert(PrimType from, PrimType to)1977 public final void emitConvert(PrimType from, PrimType to) { 1978 String to_sig = to.getSignature(); 1979 String from_sig = from.getSignature(); 1980 int op = -1; 1981 char to_sig0 = to_sig.charAt(0); 1982 char from_sig0 = from_sig.charAt(0); 1983 if (from_sig0 == to_sig0) 1984 return; 1985 if (from.size < 4) 1986 from_sig0 = 'I'; 1987 if (to.size < 4) { 1988 emitConvert(from, Type.intType); 1989 from_sig0 = 'I'; 1990 if (to.isUnsigned()) { 1991 if (to_sig0 == 'S') 1992 to_sig0 = 'C'; 1993 else if (to_sig0 == 'B') { 1994 emitPushInt(0xff); 1995 emitAnd(); 1996 return; 1997 } 1998 } 1999 } 2000 if (from_sig0 == 'J' && from.isUnsigned() 2001 && (to_sig0 == 'F' || to_sig0 == 'D')) { 2002 emitPushInt(1); 2003 emitUshr(); 2004 emitConvert(Type.longType, to); 2005 emitPushConstant(2, to); 2006 emitMul(); 2007 return; 2008 } 2009 if (from_sig0 == 'I' && from.isUnsigned() 2010 && (to_sig0 == 'J' || to_sig0 == 'F' || to_sig0 == 'D')) { 2011 emitConvert(Type.intType, Type.longType); 2012 reserve(4); 2013 emitPushLong(0xffffffffL); 2014 emitAnd(); 2015 from_sig0 = 'J'; 2016 } 2017 if (from_sig0 == to_sig0) 2018 return; 2019 switch (from_sig0) 2020 { 2021 case 'I': 2022 switch (to_sig0) 2023 { 2024 case 'B': op = 145; break; // i2b 2025 case 'C': op = 146; break; // i2c 2026 case 'S': op = 147; break; // i2s 2027 case 'J': op = 133; break; // i2l 2028 case 'F': op = 134; break; // i2f 2029 case 'D': op = 135; break; // i2d 2030 } 2031 break; 2032 case 'J': 2033 switch (to_sig0) 2034 { 2035 case 'I': op = 136; break; // l2i 2036 case 'F': op = 137; break; // l2f 2037 case 'D': op = 138; break; // l2d 2038 } 2039 break; 2040 case 'F': 2041 switch (to_sig0) 2042 { 2043 case 'I': op = 139; break; // f2i 2044 case 'J': op = 140; break; // f2l 2045 case 'D': op = 141; break; // f2d 2046 } 2047 break; 2048 case 'D': 2049 switch (to_sig0) 2050 { 2051 case 'I': op = 142; break; // d2i 2052 case 'J': op = 143; break; // d2l 2053 case 'F': op = 144; break; // d2f 2054 } 2055 break; 2056 } 2057 if (op < 0) 2058 throw new Error ("unsupported CodeAttr.emitConvert"); 2059 reserve(1); 2060 popType(); 2061 put1(op); 2062 pushType(to); 2063 } 2064 emitCheckcast(Type type, int opcode)2065 private void emitCheckcast (Type type, int opcode) 2066 { 2067 reserve(3); 2068 popType(); 2069 put1(opcode); 2070 if (type instanceof ObjectType) 2071 { 2072 putIndex2(getConstants().addClass((ObjectType) type)); 2073 } 2074 else 2075 throw new Error ("unimplemented type " + type 2076 + " in emitCheckcast/emitInstanceof"); 2077 } 2078 castNeeded(Type top, Type required)2079 public static boolean castNeeded (Type top, Type required) 2080 { 2081 top = top.getRawType(); 2082 for (;;) 2083 { 2084 if (top == required) 2085 return false; 2086 if (required instanceof ClassType 2087 && top instanceof ClassType 2088 && ((ClassType) top).isSubclass((ClassType) required)) 2089 return false; 2090 else if (required instanceof ArrayType 2091 && top instanceof ArrayType) 2092 { 2093 required = ((ArrayType) required).getComponentType(); 2094 top = ((ArrayType) top).getComponentType(); 2095 continue; 2096 } 2097 return true; 2098 } 2099 } 2100 emitCheckcast(Type type)2101 public void emitCheckcast (Type type) 2102 { 2103 if (castNeeded(topType(), type)) 2104 { 2105 emitCheckcast(type, 192); 2106 pushType(type); 2107 } 2108 } 2109 emitInstanceof(Type type)2110 public void emitInstanceof (Type type) 2111 { 2112 emitCheckcast(type, 193); 2113 pushType(Type.booleanType); 2114 } 2115 emitThrow()2116 public final void emitThrow () 2117 { 2118 popType(); 2119 reserve(1); 2120 put1 (191); // athrow 2121 setUnreachable(); 2122 } 2123 emitMonitorEnter()2124 public final void emitMonitorEnter () 2125 { 2126 popType(); 2127 reserve(1); 2128 put1 (194); // monitorenter 2129 } 2130 emitMonitorExit()2131 public final void emitMonitorExit () 2132 { 2133 popType(); 2134 reserve(1); 2135 put1 (195); // monitorexit 2136 } 2137 2138 /** 2139 * Compile a method return. 2140 * If inside a 'catch' clause, first call 'finally' clauses. 2141 * The return value (unless the return type is void) must be on the stack, 2142 * and have the correct type. 2143 */ emitReturn()2144 public final void emitReturn () 2145 { 2146 if (try_stack != null) 2147 new Error(); 2148 emitRawReturn(); 2149 } 2150 emitRawReturn()2151 final void emitRawReturn () 2152 { 2153 if (! reachableHere()) 2154 return; 2155 if (getMethod().getReturnType().size == 0) 2156 { 2157 reserve(1); 2158 put1(177); // return 2159 } 2160 else 2161 emitTypedOp (172, popType().promote()); 2162 setUnreachable(); 2163 } 2164 2165 2166 /** Add an exception handler. 2167 * Low-level routine; {@code #emitCatchStart} is preferred. */ addHandler(int start_pc, int end_pc, int handler_pc, int catch_type)2168 public void addHandler (int start_pc, int end_pc, 2169 int handler_pc, int catch_type) 2170 { 2171 int index = 4 * exception_table_length; 2172 if (exception_table == null) 2173 { 2174 exception_table = new short[20]; 2175 } 2176 else if (exception_table.length <= index) 2177 { 2178 short[] new_table = new short[2 * exception_table.length]; 2179 System.arraycopy(exception_table, 0, new_table, 0, index); 2180 exception_table = new_table; 2181 } 2182 exception_table[index++] = (short) start_pc; 2183 exception_table[index++] = (short) end_pc; 2184 exception_table[index++] = (short) handler_pc; 2185 exception_table[index++] = (short) catch_type; 2186 exception_table_length++; 2187 } 2188 2189 /** Add an exception handler. 2190 * Low-level routine; {@link #emitCatchStart} is preferred. */ addHandler(Label start_try, Label end_try, ClassType catch_type)2191 public void addHandler (Label start_try, Label end_try, 2192 ClassType catch_type) 2193 { 2194 ConstantPool constants = getConstants(); 2195 int catch_type_index; 2196 if (catch_type == null) 2197 catch_type_index = 0; 2198 else 2199 catch_type_index = constants.addClass(catch_type).index; 2200 fixupAdd(FIXUP_TRY, start_try); 2201 fixupAdd(FIXUP_TRY_END, catch_type_index, end_try); 2202 Label handler = new Label(); 2203 handler.localTypes = start_try.localTypes; 2204 handler.stackTypes = new Type[1]; 2205 Type handler_class = catch_type == null ? Type.javalangThrowableType : catch_type; 2206 handler.stackTypes[0] = handler_class; 2207 setTypes(handler); 2208 fixupAdd(FIXUP_TRY_HANDLER, 0, handler); 2209 setReachable(true); 2210 } 2211 2212 /** Beginning of code that has a cleanup handler. 2213 * This is similar to a try-finally, but the cleanup is only 2214 * done in the case of an exception. Alternatively, the try clause 2215 * has to manually do the cleanup with code duplication. 2216 * Equivalent to: <code>try <var>body</var> catch (Throwable ex) { <var>cleanup</var>; throw ex; }</code> 2217 * Call <code>emitWithCleanupStart</code> before the <code><var>body</var></code>. 2218 */ emitWithCleanupStart()2219 public void emitWithCleanupStart () 2220 { 2221 int savedSP = SP; 2222 SP = 0; // Hack to disable emitTryStart needlessly saving the stack. 2223 emitTryStart(false, null); 2224 SP = savedSP; 2225 } 2226 2227 /** Called after a <code><var>body</var></code> that has a <code><var>cleanup</var></code> clause. 2228 * Followed by the <code><var>cleanup</var></code> code. 2229 */ emitWithCleanupCatch(Variable catchVar)2230 public void emitWithCleanupCatch (Variable catchVar) 2231 { 2232 emitTryEnd(false); 2233 try_stack.saved_result = catchVar; 2234 emitCatchStart(catchVar); 2235 } 2236 2237 /** Called after generating a <code><var>cleanup</var></code> handler. */ 2238 emitWithCleanupDone()2239 public void emitWithCleanupDone () 2240 { 2241 Variable catchVar = try_stack.saved_result; 2242 try_stack.saved_result = null; 2243 if (catchVar != null) 2244 emitLoad(catchVar); 2245 emitThrow(); 2246 emitCatchEnd(); 2247 emitTryCatchEnd(); 2248 } 2249 2250 emitTryStart(boolean has_finally, Type result_type)2251 public void emitTryStart(boolean has_finally, Type result_type) 2252 { 2253 if (result_type != null && result_type.isVoid()) 2254 result_type = null; 2255 Variable[] savedStack = null; 2256 if (result_type != null || SP > 0) 2257 pushScope(); 2258 if (SP > 0) 2259 { 2260 savedStack = new Variable[SP]; 2261 int i = 0; 2262 while (SP > 0) 2263 { 2264 Variable var = addLocal(topType()); 2265 emitStore(var); 2266 savedStack[i++] = var; 2267 } 2268 } 2269 TryState try_state = new TryState(this); 2270 try_state.savedStack = savedStack; 2271 2272 int usedLocals = local_types == null ? 0 : local_types.length; 2273 for (; usedLocals > 0; usedLocals--) 2274 { 2275 Type last = local_types[usedLocals-1]; 2276 if (last != null) 2277 break; 2278 } 2279 2280 Type[] startLocals; 2281 if (usedLocals == 0) 2282 startLocals = Type.typeArray0; 2283 else 2284 { 2285 startLocals = new Type[usedLocals]; 2286 System.arraycopy(local_types, 0, startLocals, 0, usedLocals); 2287 } 2288 try_state.start_try.localTypes = startLocals; 2289 2290 if (result_type != null) 2291 try_state.saved_result = addLocal(result_type); 2292 if (has_finally) 2293 try_state.finally_subr = new Label(); 2294 } 2295 2296 @Deprecated emitTryEnd()2297 public void emitTryEnd() { 2298 } 2299 emitTryEnd(boolean fromFinally)2300 private void emitTryEnd (boolean fromFinally) 2301 { 2302 if (try_stack.tryClauseDone) 2303 return; 2304 try_stack.tryClauseDone = true; 2305 if (try_stack.finally_subr != null) 2306 try_stack.exception = addLocal(Type.javalangThrowableType); 2307 gotoFinallyOrEnd(fromFinally); 2308 try_stack.end_try = getLabel(); 2309 } 2310 emitCatchStart(Variable var)2311 public void emitCatchStart(Variable var) { 2312 if (var == null) 2313 emitCatchStart((ClassType) null); 2314 else { 2315 emitCatchStart((ClassType) var.getType()); 2316 emitStore(var); 2317 } 2318 } 2319 emitCatchStart(ClassType type)2320 public void emitCatchStart(ClassType type) 2321 { 2322 emitTryEnd(false); 2323 setTypes(try_stack.start_try.localTypes, Type.typeArray0); 2324 if (try_stack.try_type != null) 2325 emitCatchEnd(); 2326 try_stack.try_type = type; 2327 addHandler(try_stack.start_try, try_stack.end_try, type); 2328 setReachable(true); 2329 } 2330 emitCatchEnd()2331 public void emitCatchEnd() 2332 { 2333 gotoFinallyOrEnd(false); 2334 try_stack.try_type = null; 2335 } 2336 gotoFinallyOrEnd(boolean fromFinally)2337 private void gotoFinallyOrEnd (boolean fromFinally) 2338 { 2339 if (reachableHere()) 2340 { 2341 if (try_stack.saved_result != null) 2342 emitStore(try_stack.saved_result); 2343 if (try_stack.end_label == null) 2344 try_stack.end_label = new Label(); 2345 if (try_stack.finally_subr == null || useJsr()) 2346 { 2347 if (try_stack.finally_subr != null) 2348 emitJsr(try_stack.finally_subr); 2349 emitGoto(try_stack.end_label); 2350 } 2351 else 2352 { 2353 if (try_stack.exitCases != null) 2354 emitPushInt(0); 2355 emitPushNull(); // No caught Throwable. 2356 if (! fromFinally) 2357 emitGoto(try_stack.finally_subr); 2358 } 2359 } 2360 } 2361 emitFinallyStart()2362 public void emitFinallyStart() 2363 { 2364 emitTryEnd(true); 2365 if (try_stack.try_type != null) 2366 emitCatchEnd(); 2367 try_stack.end_try = getLabel(); 2368 2369 pushScope(); 2370 if (useJsr()) 2371 { 2372 SP = 0; 2373 emitCatchStart((ClassType) null); 2374 emitStore(try_stack.exception); 2375 emitJsr(try_stack.finally_subr); 2376 emitLoad(try_stack.exception); 2377 emitThrow(); 2378 } 2379 else 2380 { 2381 if (reachableHere()) 2382 emitGoto(try_stack.finally_subr); 2383 addHandler(try_stack.start_try, try_stack.end_try, Type.javalangThrowableType); 2384 if (try_stack.saved_result != null) 2385 emitStoreDefaultValue(try_stack.saved_result); 2386 if (try_stack.exitCases != null) 2387 { 2388 emitPushInt(-1); // Return switch case code. 2389 emitSwap(); 2390 } 2391 } 2392 try_stack.finally_subr.define(this); 2393 2394 if (useJsr()) 2395 { 2396 Type ret_addr_type = Type.objectType; 2397 try_stack.finally_ret_addr = addLocal(ret_addr_type); 2398 pushType(ret_addr_type); 2399 emitStore(try_stack.finally_ret_addr); 2400 } 2401 else 2402 { 2403 // Stack contents at the start of the finally block: 2404 // an integer exit code, but only if (exitCases != null). 2405 // a Throwable or null 2406 } 2407 } 2408 emitFinallyEnd()2409 public void emitFinallyEnd() 2410 { 2411 if (! reachableHere()) 2412 try_stack.end_label = null; 2413 else if (useJsr()) 2414 emitRet(try_stack.finally_ret_addr); 2415 else if (try_stack.end_label == null && try_stack.exitCases == null) 2416 { 2417 emitThrow(); 2418 } 2419 else 2420 { 2421 emitStore(try_stack.exception); 2422 emitLoad(try_stack.exception); 2423 emitIfNotNull(); 2424 emitLoad(try_stack.exception); 2425 emitThrow(); 2426 emitElse(); 2427 2428 ExitableBlock exit = try_stack.exitCases; 2429 2430 if (exit != null) 2431 { 2432 SwitchState sw = startSwitch(); 2433 2434 while (exit != null) 2435 { 2436 ExitableBlock next = exit.nextCase; 2437 exit.nextCase = null; 2438 exit.currentTryState = null; 2439 TryState nextTry = TryState.outerHandler(try_stack.previous, 2440 exit.initialTryState); 2441 if (nextTry == exit.initialTryState) // Optimization 2442 { 2443 sw.addCaseGoto(exit.switchCase, this, exit.endLabel); 2444 } 2445 else 2446 { 2447 sw.addCase(exit.switchCase, this); 2448 exit.exit(nextTry); 2449 } 2450 exit = next; 2451 } 2452 try_stack.exitCases = null; 2453 2454 sw.addDefault(this); 2455 sw.finish(this); 2456 } 2457 emitFi(); 2458 2459 setUnreachable(); 2460 } 2461 popScope(); 2462 try_stack.finally_subr = null; 2463 } 2464 emitTryCatchEnd()2465 public void emitTryCatchEnd() 2466 { 2467 if (try_stack.finally_subr != null) 2468 emitFinallyEnd(); 2469 Variable[] vars = try_stack.savedStack; 2470 if (try_stack.end_label == null) 2471 setUnreachable(); 2472 else 2473 { 2474 setTypes(try_stack.start_try.localTypes, Type.typeArray0); 2475 try_stack.end_label.define(this); 2476 if (vars != null) 2477 { 2478 for (int i = vars.length; --i >= 0; ) 2479 { 2480 Variable v = vars[i]; 2481 if (v != null) { 2482 emitLoad(v); 2483 } 2484 } 2485 } 2486 if (try_stack.saved_result != null) 2487 emitLoad(try_stack.saved_result); 2488 } 2489 if (try_stack.saved_result != null || vars != null) 2490 popScope(); 2491 try_stack = try_stack.previous; 2492 } 2493 getCurrentTry()2494 public final TryState getCurrentTry () 2495 { 2496 return try_stack; 2497 } 2498 isInTry()2499 public final boolean isInTry() 2500 { 2501 // This also return true if we're in a catch clause, but that is 2502 // good enough for now. 2503 return try_stack != null; 2504 } 2505 2506 /** Start a new switch statment or expression. 2507 * The switch value must have been calculated and left on the stack. 2508 */ startSwitch()2509 public SwitchState startSwitch () 2510 { 2511 SwitchState sw = new SwitchState(this); 2512 sw.switchValuePushed(this); 2513 return sw; 2514 } 2515 2516 /** Compile a tail-call to position 0 of the current procedure. 2517 * @param pop_args if true, copy argument registers (except this) from stack. 2518 * @param start the Label to jump back to. */ emitTailCall(boolean pop_args, Label start)2519 public void emitTailCall (boolean pop_args, Label start) 2520 { 2521 if (pop_args) 2522 { 2523 Method meth = getMethod(); 2524 int arg_slots = ((meth.access_flags & Access.STATIC) != 0) ? 0 : 1; 2525 for (int i = meth.arg_types.length; --i >= 0; ) 2526 arg_slots += meth.arg_types[i].size > 4 ? 2 : 1; 2527 for (int i = meth.arg_types.length; --i >= 0; ) 2528 { 2529 arg_slots -= meth.arg_types[i].size > 4 ? 2 : 1; 2530 emitStore(locals.used [arg_slots]); 2531 } 2532 } 2533 emitGoto(start); 2534 } 2535 2536 /** Compile a tail-call to position 0 of the current procedure. 2537 * @param pop_args if true, copy argument registers (except this) from stack. 2538 * @param scope Scope whose start we jump back to. */ emitTailCall(boolean pop_args, Scope scope)2539 public void emitTailCall (boolean pop_args, Scope scope) 2540 { 2541 emitTailCall(pop_args, scope.start); 2542 } 2543 processFixups()2544 public void processFixups() { 2545 if (fixup_count <= 0) 2546 return; 2547 2548 // For each label, set it to its maximum limit, assuming all 2549 // fixups causes the code to be expanded. We need a prepass 2550 // for this, since FIXUP_MOVEs can cause code to be reordered. 2551 // Also, convert each FIXUP_MOVE_TO_END to FIXUP_MOVE. 2552 2553 int delta = 0; 2554 int instruction_tail = fixup_count; 2555 fixupAdd(CodeAttr.FIXUP_MOVE, -1, null); 2556 2557 /* DEBUGGING 2558 if (false) { 2559 ClassTypeWriter writer = 2560 new ClassTypeWriter(getMethod().getDeclaringClass(), 2561 System.err, 0); 2562 writer.println("processFixups1 for "+getMethod()); 2563 disAssembleWithFixups(writer); 2564 writer.flush(); 2565 } 2566 */ 2567 2568 loop1: 2569 for (int i = 0; ; ) 2570 { 2571 int offset = fixup_offsets[i]; 2572 int kind = offset & 15; 2573 offset >>= 4; 2574 Label label = fixup_labels[i]; 2575 // Optimize: TRANSFER L1; ...; L1: GOTO L2 2576 // to: TRANSFER L2; ...; L1: GOTO L2 2577 // If L1 is a FIXUP_DEFINE_UNREACHABLE then we can delete the GOTO L2 2578 // (replace it with a DELETE3), since L1 is never reached. 2579 if (kind >= FIXUP_CASE && kind <= FIXUP_TRANSFER2) { 2580 int max = fixup_count; 2581 goto_to_goto: 2582 while (label != null && --max >= 0) { 2583 int labpc = fixupOffset(label.first_fixup); 2584 for (int def = label.first_fixup+1; ; def++) { 2585 if (def >= fixup_count || labpc != fixupOffset(def)) { 2586 break goto_to_goto; 2587 } else if (fixupKind(def) == FIXUP_GOTO 2588 || fixupKind(def) == FIXUP_DELETE3) { 2589 label = fixup_labels[def]; 2590 fixup_labels[i] = label; 2591 break; 2592 } 2593 } 2594 } 2595 } 2596 switch (kind) 2597 { 2598 case FIXUP_TRY: 2599 i+=2; 2600 break; 2601 case FIXUP_LINE_PC: 2602 i++; 2603 case FIXUP_CASE: 2604 case FIXUP_DELETE3: 2605 break; 2606 case FIXUP_DEFINE_UNREACHABLE: 2607 // If we're currently "unreachable" and we see 2608 // L0: L1: ... Ln: GOTO Lg 2609 // then we can delete the "GOTO Lg" because we also (separately) 2610 // patch each use of Li to Lg. 2611 while (i + 1 < fixup_count && fixupKind(i+1) == FIXUP_DEFINE 2612 && fixupOffset(i+1) == offset) { 2613 i++; 2614 label.position += delta; 2615 label = fixup_labels[i]; 2616 } 2617 if (i + 1 < fixup_count && fixupKind(i+1) == FIXUP_GOTO 2618 && fixupOffset(i+1) == offset) { 2619 for (int j = i; ; j--) { 2620 fixup_labels[j].needsStackMapEntry = false; 2621 if (fixupKind(j) == FIXUP_DEFINE_UNREACHABLE) 2622 break; 2623 } 2624 i++; 2625 fixupSet(i, FIXUP_DELETE3, offset); 2626 delta -= 3; 2627 continue; 2628 } 2629 // fall through 2630 case FIXUP_DEFINE: 2631 label.position += delta; 2632 break; 2633 case FIXUP_SWITCH: 2634 delta += 3; // May need to add up to 3 padding bytes. 2635 break; 2636 case FIXUP_GOTO: 2637 if (fixupOffset(label.first_fixup) == offset + 3) 2638 { 2639 // Optimize: GOTO L; L: 2640 fixupSet(i, FIXUP_DELETE3, offset); 2641 delta -= 3; 2642 break; 2643 } 2644 // ... else fall through ... 2645 case FIXUP_JSR: 2646 if (PC >= 0x8000) 2647 delta += 2; // May need to convert goto->goto_w, jsr->jsr_w. 2648 break; 2649 case FIXUP_TRANSFER: 2650 if (PC >= 0x8000) 2651 delta += 5; // May need to add a goto_w. 2652 break; 2653 case FIXUP_MOVE_TO_END: 2654 fixup_labels[instruction_tail] = fixup_labels[i+1]; 2655 instruction_tail = offset; 2656 // ... fall through ... 2657 case FIXUP_MOVE: 2658 int cur_pc = ((i+1) >= fixup_count ? PC 2659 : fixupOffset(fixup_labels[i+1].first_fixup)); 2660 fixupSet(i, FIXUP_MOVE, cur_pc); 2661 if (label == null) 2662 break loop1; 2663 else 2664 { 2665 i = label.first_fixup; 2666 int next_pc = fixupOffset(i); 2667 delta = (cur_pc + delta) - next_pc; 2668 continue; 2669 } 2670 default: 2671 throw new Error("unexpected fixup"); 2672 } 2673 i++; 2674 } 2675 // Next a loop to fix the position of each label, and calculate 2676 // the exact number of code bytes. 2677 2678 // Number of bytes to be inserted or (if negative) removed, so far. 2679 int new_size = PC; 2680 // Current delta between final PC and offset in generated code array. 2681 delta = 0; 2682 loop2: 2683 for (int i = 0; i < fixup_count; ) 2684 { 2685 int offset = fixup_offsets[i]; 2686 int kind = offset & 15; 2687 Label label = fixup_labels[i]; 2688 if (label != null && label.position < 0) 2689 throw new Error ("undefined label "+label); 2690 offset = offset >> 4; 2691 switch (kind) 2692 { 2693 case FIXUP_TRY: 2694 i+=2; 2695 fixup_labels[i].position = offset + delta; 2696 break; 2697 case FIXUP_LINE_PC: 2698 i++; 2699 case FIXUP_CASE: 2700 break; 2701 case FIXUP_DELETE3: 2702 delta -= 3; 2703 new_size -= 3; 2704 break; 2705 case FIXUP_DEFINE_UNREACHABLE: 2706 case FIXUP_DEFINE: 2707 label.position = offset + delta; 2708 break; 2709 case FIXUP_SWITCH: 2710 int padding = 3 - (offset+delta) & 3; 2711 delta += padding; 2712 new_size += padding; 2713 break; 2714 case FIXUP_GOTO: 2715 case FIXUP_JSR: 2716 case FIXUP_TRANSFER: 2717 int rel = label.position - (offset+delta); 2718 if ((short) rel == rel) 2719 { 2720 fixupSet(i, FIXUP_TRANSFER2, offset); 2721 } 2722 else 2723 { 2724 delta += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w 2725 new_size += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w 2726 } 2727 break; 2728 case FIXUP_MOVE: 2729 if (label == null) 2730 break loop2; 2731 else 2732 { 2733 i = label.first_fixup; 2734 int next_pc = fixupOffset(i); 2735 delta = (offset + delta) - next_pc; 2736 continue; 2737 } 2738 default: 2739 throw new Error("unexpected fixup"); 2740 } 2741 i++; 2742 } 2743 2744 /* DEBUGGING 2745 if (false) { 2746 ClassTypeWriter writer = 2747 new ClassTypeWriter(getMethod().getDeclaringClass(), System.err, 0); 2748 writer.println("processFixups3 for "+getMethod()); 2749 disAssembleWithFixups(writer); 2750 writer.flush(); 2751 } 2752 */ 2753 2754 byte[] new_code = new byte[new_size]; 2755 int prev_linenumber = -1; 2756 int new_pc = 0; 2757 int next_fixup_index = 0; 2758 int next_fixup_offset = fixupOffset(0); 2759 int oldPC = -1; 2760 Label pendingStackMapLabel = null; 2761 loop3: 2762 for (int old_pc = 0; ; ) 2763 { 2764 if (old_pc < next_fixup_offset) 2765 new_code[new_pc++] = code[old_pc++]; 2766 else 2767 { 2768 int kind = fixup_offsets[next_fixup_index] & 15; 2769 Label label = fixup_labels[next_fixup_index]; 2770 if (pendingStackMapLabel != null 2771 && pendingStackMapLabel.position < new_pc) 2772 { 2773 stackMap.emitStackMapEntry(pendingStackMapLabel, this); 2774 pendingStackMapLabel = null; 2775 } 2776 if (pendingStackMapLabel != null 2777 && pendingStackMapLabel.position > new_pc) 2778 throw new Error("labels out of order"); 2779 switch (kind) 2780 { 2781 case FIXUP_DEFINE: 2782 case FIXUP_DEFINE_UNREACHABLE: 2783 if (stackMap != null && label != null && label.isUsed() && label.needsStackMapEntry) 2784 { 2785 pendingStackMapLabel 2786 = mergeLabels(pendingStackMapLabel, label); 2787 } 2788 break; 2789 case FIXUP_DELETE3: 2790 old_pc += 3; 2791 break; 2792 case FIXUP_TRANSFER2: 2793 delta = label.position - new_pc; 2794 new_code[new_pc++] = code[old_pc]; 2795 new_code[new_pc++] = (byte) (delta >> 8); 2796 new_code[new_pc++] = (byte) (delta & 0xFF); 2797 old_pc += 3; 2798 break; 2799 case FIXUP_GOTO: 2800 case FIXUP_JSR: 2801 case FIXUP_TRANSFER: 2802 delta = label.position - new_pc; 2803 byte opcode = code[old_pc]; 2804 if (kind == FIXUP_TRANSFER) 2805 { 2806 // convert: IF_xxx L to IF_NOT_xxx Lt; GOTO L; Lt: 2807 opcode = invert_opcode(opcode); 2808 new_code[new_pc++] = opcode; 2809 new_code[new_pc++] = 0; 2810 new_code[new_pc++] = 8; // 8 byte offset to Lt. 2811 opcode = (byte) 200; // goto_w 2812 } 2813 else 2814 { 2815 // Change goto to goto_w; jsr to jsr_w: 2816 opcode = (byte) (opcode + (200-167)); 2817 } 2818 new_code[new_pc++] = opcode; 2819 new_code[new_pc++] = (byte) (delta >> 24); 2820 new_code[new_pc++] = (byte) (delta >> 16); 2821 new_code[new_pc++] = (byte) (delta >> 8); 2822 new_code[new_pc++] = (byte) (delta & 0xFF); 2823 old_pc += 3; 2824 break; 2825 case FIXUP_SWITCH: 2826 int padding = 3 - new_pc & 3; 2827 int switch_start = new_pc; 2828 new_code[new_pc++] = code[old_pc++]; 2829 while (--padding >= 0) 2830 new_code[new_pc++] = 0; 2831 while (next_fixup_index < fixup_count 2832 && fixupKind(next_fixup_index + 1) == FIXUP_CASE) 2833 { 2834 next_fixup_index++; 2835 int offset = fixupOffset(next_fixup_index); 2836 while (old_pc < offset) 2837 new_code[new_pc++] = code[old_pc++]; 2838 delta = (fixup_labels[next_fixup_index].position 2839 - switch_start); 2840 new_code[new_pc++] = (byte) (delta >> 24); 2841 new_code[new_pc++] = (byte) (delta >> 16); 2842 new_code[new_pc++] = (byte) (delta >> 8); 2843 new_code[new_pc++] = (byte) (delta & 0xFF); 2844 old_pc += 4; 2845 } 2846 break; 2847 case FIXUP_TRY: 2848 label = fixup_labels[next_fixup_index+2]; 2849 int handler_type_index = fixupOffset(next_fixup_index+1); 2850 if (stackMap != null) 2851 pendingStackMapLabel 2852 = mergeLabels(pendingStackMapLabel, label); 2853 addHandler(fixup_labels[next_fixup_index].position, 2854 fixup_labels[next_fixup_index+1].position, 2855 new_pc, 2856 handler_type_index); 2857 next_fixup_index+=2; 2858 break; 2859 case FIXUP_LINE_PC: 2860 if (lines == null) 2861 lines = new LineNumbersAttr(this); 2862 next_fixup_index++; 2863 int linenumber = fixupOffset(next_fixup_index); 2864 if (linenumber != prev_linenumber) 2865 lines.put(linenumber, new_pc); 2866 prev_linenumber = linenumber; 2867 break; 2868 case FIXUP_MOVE: 2869 if (label == null) 2870 break loop3; 2871 else 2872 { 2873 next_fixup_index = label.first_fixup; 2874 old_pc = fixupOffset(next_fixup_index); 2875 next_fixup_offset = old_pc; 2876 if (label.position != new_pc) 2877 throw new Error("bad pc"); 2878 continue; 2879 } 2880 default: 2881 throw new Error("unexpected fixup"); 2882 } 2883 next_fixup_index++; 2884 next_fixup_offset = fixupOffset(next_fixup_index); 2885 } 2886 } 2887 if (new_size != new_pc) 2888 throw new Error("PC confusion new_pc:"+new_pc+" new_size:"+new_size); 2889 PC = new_size; 2890 code = new_code; 2891 fixup_count = 0; 2892 fixup_labels = null; 2893 fixup_offsets = null; 2894 } 2895 mergeLabels(Label oldLabel, Label newLabel)2896 private Label mergeLabels (Label oldLabel, Label newLabel) 2897 { 2898 if (oldLabel != null) 2899 newLabel.setTypes(oldLabel); 2900 return newLabel; 2901 } 2902 assignConstants(ClassType cl)2903 public void assignConstants (ClassType cl) 2904 { 2905 if (locals != null && locals.container == null && ! locals.isEmpty()) 2906 locals.addToFrontOf(this); 2907 processFixups(); 2908 if (stackMap != null && stackMap.numEntries > 0) 2909 stackMap.addToFrontOf(this); 2910 if (instructionLineMode) 2911 { 2912 // A kludge to low-level debugging: 2913 // Define a "line number" for each instrction. 2914 if (lines == null) 2915 lines = new LineNumbersAttr(this); 2916 lines.linenumber_count = 0; 2917 int codeLen = getCodeLength(); 2918 for (int i = 0; i < codeLen; i++) 2919 lines.put(i, i); 2920 } 2921 super.assignConstants(cl); 2922 Attribute.assignConstants(this, cl); 2923 } 2924 getLength()2925 public final int getLength() 2926 { 2927 return 12 + getCodeLength() + 8 * exception_table_length 2928 + Attribute.getLengthAll(this); 2929 } 2930 write(DataOutputStream dstr)2931 public void write (DataOutputStream dstr) throws java.io.IOException 2932 { 2933 dstr.writeShort (max_stack); 2934 dstr.writeShort (max_locals); 2935 dstr.writeInt (PC); 2936 dstr.write (code, 0, PC); 2937 2938 dstr.writeShort (exception_table_length); 2939 int count = exception_table_length; 2940 for (int i = 0; --count >= 0; i += 4) 2941 { 2942 dstr.writeShort(exception_table[i]); 2943 dstr.writeShort(exception_table[i+1]); 2944 dstr.writeShort(exception_table[i+2]); 2945 dstr.writeShort(exception_table[i+3]); 2946 } 2947 2948 Attribute.writeAll(this, dstr); 2949 } 2950 print(ClassTypeWriter dst)2951 public void print (ClassTypeWriter dst) 2952 { 2953 dst.print("Attribute \""); 2954 dst.print(getName()); 2955 dst.print("\", length:"); 2956 dst.print(getLength()); 2957 dst.print(", max_stack:"); 2958 dst.print(max_stack); 2959 dst.print(", max_locals:"); 2960 dst.print(max_locals); 2961 dst.print(", code_length:"); 2962 int length = getCodeLength(); 2963 dst.println(length); 2964 disAssemble(dst, 0, length); 2965 if (exception_table_length > 0) 2966 { 2967 dst.print("Exceptions (count: "); 2968 dst.print(exception_table_length); 2969 dst.println("):"); 2970 int count = exception_table_length; 2971 for (int i = 0; --count >= 0; i += 4) 2972 { 2973 dst.print(" start: "); 2974 dst.print(exception_table[i] & 0xffff); 2975 dst.print(", end: "); 2976 dst.print(exception_table[i+1] & 0xffff); 2977 dst.print(", handler: "); 2978 dst.print(exception_table[i+2] & 0xffff); 2979 dst.print(", type: "); 2980 int catch_type_index = exception_table[i+3] & 0xffff; 2981 if (catch_type_index == 0) 2982 dst.print("0 /* finally */"); 2983 else 2984 { 2985 dst.printOptionalIndex(catch_type_index); 2986 dst.printConstantTersely(catch_type_index, ConstantPool.CLASS); 2987 } 2988 dst.println(); 2989 } 2990 } 2991 dst.printAttributes(this); 2992 } 2993 2994 /* DEBUGGING: 2995 public void disAssembleWithFixups(ClassTypeWriter dst) { 2996 if (fixup_count <= 0) { 2997 disAssemble(dst, 0, PC); 2998 return; 2999 } 3000 int prev_pc = 0; 3001 for (int i = 0; i < fixup_count; ) { 3002 int offset = fixup_offsets[i]; 3003 int kind = offset & 15; 3004 Label label = fixup_labels[i]; 3005 offset = offset >> 4; 3006 int pc = offset; 3007 if (kind == FIXUP_MOVE || kind == FIXUP_MOVE_TO_END) 3008 pc = (i+1 >= fixup_count) ? PC : fixup_offsets[i+1] >> 4; 3009 else if (kind == FIXUP_CASE) 3010 pc = prev_pc; 3011 disAssemble(dst, prev_pc, pc); 3012 3013 dst.print("fixup#"); dst.print(i); 3014 dst.print(" @"); dst.print(offset); 3015 prev_pc = pc; 3016 switch (kind) { 3017 case FIXUP_DEFINE: 3018 case FIXUP_DEFINE_UNREACHABLE: 3019 dst.print(" DEFINE "); 3020 if (kind == FIXUP_DEFINE_UNREACHABLE) 3021 dst.print("(unreachable) "); 3022 dst.println(label); 3023 break; 3024 case FIXUP_SWITCH: 3025 dst.println(" SWITCH"); 3026 break; 3027 case FIXUP_CASE: 3028 dst.print(" CASE "); 3029 dst.println(label); 3030 break; 3031 case FIXUP_GOTO: 3032 dst.print(" GOTO "); 3033 dst.println(label); 3034 break; 3035 case FIXUP_TRANSFER: 3036 dst.print(" TRANSFER "); 3037 dst.println(label); 3038 break; 3039 case FIXUP_TRANSFER2: 3040 dst.print(" TRANSFER2 "); 3041 dst.println(label); 3042 break; 3043 case FIXUP_DELETE3: 3044 dst.println(" DELETE3"); 3045 break; 3046 case FIXUP_MOVE: 3047 dst.print(" MOVE "); 3048 dst.println(label); 3049 break; 3050 case FIXUP_MOVE_TO_END: 3051 dst.print(" MOVE_TO_END "); 3052 dst.println(label); 3053 break; 3054 case FIXUP_TRY: 3055 dst.print(" TRY start: "); 3056 dst.println(label); 3057 i++; 3058 dst.print(" - end: "); 3059 dst.print(fixup_labels[i]); 3060 dst.print(" type: "); 3061 dst.println(fixup_offsets[i] >> 4); 3062 i++; 3063 dst.print(" - handler: "); 3064 dst.println(fixup_labels[i]); 3065 break; 3066 case FIXUP_LINE_PC: 3067 dst.print(" LINE "); 3068 i++; 3069 dst.println(fixup_offsets[i] >> 4); 3070 break; 3071 default: 3072 dst.println(" kind:"+fixupKind(i)+" offset:"+fixupOffset(i) 3073 +" "+fixup_labels[i]); 3074 } 3075 i++; 3076 } 3077 disAssemble(dst, prev_pc, PC); 3078 } 3079 */ 3080 disAssemble(ClassTypeWriter dst, int start, int limit)3081 public void disAssemble (ClassTypeWriter dst, int start, int limit) 3082 { 3083 boolean wide = false; 3084 for (int i = start; i < limit; ) 3085 { 3086 int oldpc = i++; 3087 int op = code[oldpc] & 0xff; 3088 String str = Integer.toString(oldpc); 3089 int printConstant = 0; 3090 int j = str.length(); 3091 while (++j <= 3) dst.print(' '); 3092 dst.print(str); 3093 dst.print(": "); 3094 // We do a rough binary partition of the opcodes. 3095 if (op < 120) 3096 { 3097 if (op < 87) 3098 { 3099 if (op < 3) print("nop;aconst_null;iconst_m1;", op, dst); 3100 else if (op < 9) { dst.print("iconst_"); dst.print(op-3); } 3101 else if (op < 16) // op >= 9 [lconst_0] && op <= 15 [dconst_1] 3102 { 3103 char typ; 3104 if (op < 11) { typ = 'l'; op -= 9; } 3105 else if (op < 14) { typ = 'f'; op -= 11; } 3106 else { typ = 'd'; op -= 14; } 3107 dst.print(typ); dst.print("const_"); dst.print(op); 3108 } 3109 else if (op < 21) 3110 { 3111 if (op < 18) // op >= 16 [bipush] && op <= 17 [sipush] 3112 { 3113 print("bipush ;sipush ;", op-16, dst); 3114 int constant; 3115 if (op == 16) constant = code[i++]; 3116 else { constant = (short) readUnsignedShort(i); i+=2;} 3117 dst.print(constant); 3118 } 3119 else // op >= 18 [ldc] && op <= 20 [ldc2_w] 3120 { 3121 printConstant = op == 18 ? 1 : 2; 3122 print("ldc;ldc_w;ldc2_w;", op-18, dst); 3123 } 3124 } 3125 else // op >= 21 && op < 87 3126 { 3127 String load_or_store; 3128 if (op < 54) { load_or_store = "load"; } 3129 else { load_or_store = "store"; op -=(54-21); } 3130 int index; // -2 if array op; -1 if index follows 3131 if (op < 26) { index = -1; op -= 21; } 3132 else if (op < 46) { op -= 26; index = op % 4; op >>= 2; } 3133 else { index = -2; op -= 46; } 3134 dst.print("ilfdabcs".charAt(op)); 3135 if (index == -2) dst.write('a'); 3136 dst.print(load_or_store); 3137 if (index >= 0) { dst.write('_'); dst.print(index); } 3138 else if (index == -1) 3139 { 3140 if (wide) { index = readUnsignedShort(i); i += 2; } 3141 else { index = code[i] & 0xff; i++; } 3142 wide = false; 3143 dst.print(' '); 3144 dst.print(index); 3145 } 3146 } 3147 } 3148 else // op >= 87 && op < 120 3149 { 3150 if (op < 96) 3151 print("pop;pop2;dup;dup_x1;dup_x2;dup2;dup2_x1;dup2_x2;swap;" 3152 , op-87, dst); 3153 else // op >= 96 [iadd] && op <= 119 [dneg] 3154 { 3155 dst.print("ilfda".charAt((op-96) % 4)); 3156 print("add;sub;mul;div;rem;neg;", (op-96)>>2, dst); 3157 } 3158 } 3159 } 3160 else // op >= 120 3161 { 3162 if (op < 170) 3163 { 3164 if (op < 132) // op >= 120 [ishl] && op <= 131 [lxor] 3165 { 3166 dst.print((op & 1) == 0 ? 'i' : 'l'); 3167 print("shl;shr;ushr;and;or;xor;", (op-120)>>1, dst); 3168 } 3169 else if (op == 132) // iinc 3170 { 3171 int var_index; 3172 int constant; 3173 dst.print("iinc"); 3174 if (! wide) 3175 { 3176 var_index = 0xff & code[i++]; 3177 constant = code[i++]; 3178 } 3179 else 3180 { 3181 var_index = readUnsignedShort(i); 3182 i += 2; 3183 constant = (short) readUnsignedShort(i); 3184 i += 2; 3185 wide = false; 3186 } 3187 dst.print(' '); dst.print(var_index); 3188 dst.print(' '); dst.print(constant); 3189 } 3190 else if (op < 148) // op >= 133 [i2l] && op <= 147 [i2s] 3191 { 3192 dst.print("ilfdi".charAt((op-133) / 3)); 3193 dst.print('2'); 3194 dst.print("lfdifdildilfbcs".charAt(op-133)); 3195 } 3196 else if (op < 153) // op >= 148 [lcmp] && op <= 152 [dcmpg] 3197 print("lcmp;fcmpl;fcmpg;dcmpl;dcmpg;", op-148, dst); 3198 else if (op < 169) 3199 { 3200 if (op < 159) 3201 { 3202 dst.print("if"); 3203 print("eq;ne;lt;ge;gt;le;", op-153, dst); 3204 } 3205 else if (op < 167) 3206 { 3207 if (op < 165) { dst.print("if_icmp"); } 3208 else { dst.print("if_acmp"); op -= 165-159; } 3209 print("eq;ne;lt;ge;gt;le;", op-159, dst); 3210 } 3211 else 3212 print("goto;jsr;", op-167, dst); 3213 int delta = (short) readUnsignedShort(i); 3214 i += 2; 3215 dst.print(' '); dst.print(oldpc+delta); 3216 } 3217 else 3218 { 3219 int index; 3220 dst.print("ret "); 3221 if (wide) { index = readUnsignedShort(i); i += 2; } 3222 else { index = code[i] & 0xff; i++; } 3223 wide = false; 3224 dst.print(index); 3225 } 3226 } 3227 else 3228 { 3229 if (op < 172) // [tableswitch] or [lookupswitch] 3230 { 3231 if (fixup_count <= 0) 3232 i = (i + 3) & ~3; // skip 0-3 byte padding. 3233 int code_offset = readInt(i); i += 4; 3234 if (op == 170) 3235 { 3236 dst.print("tableswitch"); 3237 int low = readInt(i); i += 4; 3238 int high = readInt(i); i += 4; 3239 dst.print(" low: "); dst.print(low); 3240 dst.print(" high: "); dst.print(high); 3241 dst.print(" default: "); dst.print(oldpc+code_offset); 3242 for (; low <= high; low++) 3243 { 3244 code_offset = readInt(i); i += 4; 3245 dst.println(); 3246 dst.print(" "); dst.print(low); 3247 dst.print(": "); dst.print(oldpc + code_offset); 3248 } 3249 } 3250 else 3251 { 3252 dst.print("lookupswitch"); 3253 int npairs = readInt(i); i += 4; 3254 dst.print(" npairs: "); dst.print(npairs); 3255 dst.print(" default: "); dst.print(oldpc+code_offset); 3256 while (--npairs >= 0) 3257 { 3258 int match = readInt(i); i += 4; 3259 code_offset = readInt(i); i += 4; 3260 dst.println(); 3261 dst.print(" "); dst.print(match); 3262 dst.print(": "); dst.print(oldpc + code_offset); 3263 } 3264 } 3265 } 3266 else if (op < 178) // op >= 172 [ireturn] && op <= 177 [return] 3267 { 3268 if (op < 177) dst.print("ilfda".charAt(op-172)); 3269 dst.print("return"); 3270 } 3271 else if (op < 182) // op >= 178 [getstatic] && op <= 181 [putfield] 3272 { 3273 print("getstatic;putstatic;getfield;putfield;", op-178, dst); 3274 printConstant = 2; 3275 } 3276 else if (op < 185) // op >= 182 && op <= 185 [invoke*] 3277 { 3278 dst.print("invoke"); 3279 print("virtual;special;static;", op-182, dst); 3280 printConstant = 2; 3281 } 3282 else if (op == 185) // invokeinterface 3283 { 3284 dst.print("invokeinterface ("); 3285 int index = readUnsignedShort(i); 3286 i += 2; 3287 int args = 0xff & code[i]; 3288 i += 2; 3289 dst.print(args + " args)"); 3290 dst.printConstantOperand(index); 3291 } 3292 else if (op == 186) // invokedynamic 3293 { 3294 dst.print("invokedynamic"); 3295 int index = readUnsignedShort(i); 3296 i += 4; 3297 dst.printConstantOperand(index); 3298 } 3299 else if (op < 196) 3300 { 3301 print("186;new;newarray;anewarray;arraylength;athrow;checkcast;instanceof;monitorenter;monitorexit;", op-186, dst); 3302 if (op == 187 || op == 189 || op == 192 || op == 193) 3303 printConstant = 2; 3304 else if (op == 188) // newarray 3305 { 3306 int type = code[i++]; 3307 dst.print(' '); 3308 if (type >= 4 && type <= 11) 3309 print("boolean;char;float;double;byte;short;int;long;", 3310 type-4, dst); 3311 else 3312 dst.print(type); 3313 } 3314 3315 } 3316 else if (op == 196) // wide 3317 { 3318 dst.print("wide"); 3319 wide = true; 3320 } 3321 else if (op == 197) 3322 { 3323 dst.print("multianewarray"); 3324 int index = readUnsignedShort(i); 3325 i += 2; 3326 dst.printConstantOperand(index); 3327 int dims = 0xff & code[i++]; 3328 dst.print(' '); 3329 dst.print(dims); 3330 } 3331 else if (op < 200) 3332 { 3333 print("ifnull;ifnonnull;", op-198, dst); 3334 int delta = (short) readUnsignedShort(i); 3335 i += 2; 3336 dst.print(' '); dst.print(oldpc+delta); 3337 } 3338 else if (op < 202) 3339 { 3340 print("goto_w;jsr_w;", op-200, dst); 3341 int delta = readInt(i); 3342 i += 4; 3343 dst.print(' '); dst.print(oldpc+delta); 3344 } 3345 else 3346 dst.print(op); 3347 } 3348 } 3349 if (printConstant > 0) 3350 { 3351 int index; 3352 if (printConstant == 1) index = 0xff & code[i++]; 3353 else { index = readUnsignedShort(i); i += 2; } 3354 dst.printConstantOperand(index); 3355 } 3356 dst.println(); 3357 } 3358 } 3359 readUnsignedShort(int offset)3360 private int readUnsignedShort(int offset) 3361 { 3362 return ((0xff & code[offset]) << 8) | (0xff & code[offset+1]); 3363 } 3364 readInt(int offset)3365 private int readInt(int offset) 3366 { 3367 return (readUnsignedShort(offset) << 16) | readUnsignedShort(offset+2); 3368 } 3369 3370 /* 3371 public saveStack (ClassType into) 3372 { 3373 Field[] flds = new Field[SP]; 3374 while (SP > 0) 3375 { 3376 Field fld = ?; 3377 emitStore(fld); 3378 flds[SP...] 3379 } 3380 } 3381 */ 3382 3383 /* Print the i'th ';'-delimited substring of str on dst. */ print(String str, int i, PrintWriter dst)3384 private void print (String str, int i, PrintWriter dst) 3385 { 3386 int last = 0; 3387 int pos = -1; 3388 for (; i >= 0; i--) 3389 { 3390 last = ++pos; 3391 pos = str.indexOf(';', last); 3392 } 3393 dst.write(str, last, pos-last); 3394 } 3395 beginFragment(Label after)3396 public int beginFragment (Label after) 3397 { 3398 return beginFragment(new Label(), after); 3399 } 3400 beginFragment(Label start, Label after)3401 public int beginFragment (Label start, Label after) 3402 { 3403 int i = fixup_count; 3404 fixupAdd(FIXUP_MOVE_TO_END, after); 3405 start.define(this); 3406 return i; 3407 } 3408 3409 /** End a fragment. 3410 * @param cookie the return value from the previous beginFragment. 3411 */ endFragment(int cookie)3412 public void endFragment (int cookie) 3413 { 3414 fixupSet(cookie, FIXUP_MOVE_TO_END, fixup_count); 3415 Label after = fixup_labels[cookie]; 3416 fixupAdd(FIXUP_MOVE, -1, null); 3417 after.define(this); 3418 int fx = fixup_count - 1; 3419 fixupSet(fx, FIXUP_DEFINE, fixupOffset(fx)); 3420 } 3421 } 3422