001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.classloader; 014 015 import org.jikesrvm.VM; 016 import org.jikesrvm.compilers.common.BootImageCompiler; 017 import org.jikesrvm.compilers.common.CompiledMethod; 018 import org.jikesrvm.compilers.common.RuntimeCompiler; 019 import org.jikesrvm.runtime.DynamicLink; 020 import org.jikesrvm.util.HashMapRVM; 021 import org.vmmagic.pragma.Uninterruptible; 022 023 /** 024 * A method of a java class that has bytecodes. 025 */ 026 public final class NormalMethod extends RVMMethod implements BytecodeConstants { 027 028 /* As we read the bytecodes for the method, we compute 029 * a simple summary of some interesting properties of the method. 030 * Because we do this for every method, we require the summarization to 031 * be fast and the computed summary to be very space efficient. 032 * 033 * The following constants encode the estimated relative cost in 034 * machine instructions when a particular class of bytecode is compiled 035 * by the optimizing compiler. The estimates approximate the typical 036 * optimization the compiler is able to perform. 037 * This information is used to estimate how big a method will be when 038 * it is inlined. 039 */ 040 public static final int SIMPLE_OPERATION_COST = 1; 041 public static final int LONG_OPERATION_COST = 2; 042 public static final int ARRAY_LOAD_COST = 2; 043 public static final int ARRAY_STORE_COST = 2; 044 public static final int JSR_COST = 5; 045 public static final int CALL_COST = 6; 046 // Bias to inlining methods with magic 047 // most magics are quite cheap (0-1 instructions) 048 public static final int MAGIC_COST = 0; 049 // News are actually more expensive than calls 050 // but bias to inline methods that allocate 051 // objects because we expect better downstream optimization of 052 // the caller due to class analysis 053 // and propagation of nonNullness 054 public static final int ALLOCATION_COST = 4; 055 // Approximations, assuming some CSE/PRE of object model computations 056 public static final int CLASS_CHECK_COST = 2 * SIMPLE_OPERATION_COST; 057 public static final int STORE_CHECK_COST = 4 * SIMPLE_OPERATION_COST; 058 // Just a call. 059 public static final int THROW_COST = CALL_COST; 060 // Really a bunch of operations plus a call, but undercharge because 061 // we don't have worry about this causing an exponential growth of call chain 062 // and we probably want to inline synchronization 063 // (to get a chance to optimize it). 064 public static final int SYNCH_COST = 4 * SIMPLE_OPERATION_COST; 065 // The additional cost of a switch isn't that large, since if the 066 // switch has more than a few cases the method will be too big to inline 067 // anyways. 068 public static final int SWITCH_COST = CALL_COST; 069 070 // Definition of flag bits 071 private static final char HAS_MAGIC = 0x8000; 072 private static final char HAS_SYNCH = 0x4000; 073 private static final char HAS_ALLOCATION = 0x2000; 074 private static final char HAS_THROW = 0x1000; 075 private static final char HAS_INVOKE = 0x0800; 076 private static final char HAS_FIELD_READ = 0x0400; 077 private static final char HAS_FIELD_WRITE = 0x0200; 078 private static final char HAS_ARRAY_READ = 0x0100; 079 private static final char HAS_ARRAY_WRITE = 0x0080; 080 private static final char HAS_JSR = 0x0040; 081 private static final char HAS_COND_BRANCH = 0x0020; 082 private static final char HAS_SWITCH = 0x0010; 083 private static final char HAS_BACK_BRANCH = 0x0008; 084 private static final char IS_RS_METHOD = 0x0004; 085 086 /** 087 * storage for bytecode summary flags 088 */ 089 private char summaryFlags; 090 /** 091 * storage for bytecode summary size 092 */ 093 private char summarySize; 094 095 /** 096 * words needed for local variables (including parameters) 097 */ 098 private final short localWords; 099 100 /** 101 * words needed for operand stack (high water mark) 102 * TODO: OSR redesign; add subclass of NormalMethod for OSR method 103 * and then make this field final in NormalMethod. 104 */ 105 private short operandWords; 106 107 /** 108 * bytecodes for this method ({@code null} --> none) 109 */ 110 private final byte[] bytecodes; 111 112 /** 113 * try/catch/finally blocks for this method ({@code null} --> none) 114 */ 115 private final ExceptionHandlerMap exceptionHandlerMap; 116 117 /** 118 * pc to source-line info ({@code null} --> none) 119 * Each entry contains both the line number (upper 16 bits) 120 * and corresponding start PC (lower 16 bits). 121 */ 122 private final int[] lineNumberMap; 123 124 /** 125 * the local variable table 126 */ 127 private static final HashMapRVM<NormalMethod, LocalVariableTable> localVariableTables = new HashMapRVM<NormalMethod, LocalVariableTable>(); 128 129 // Extra fields for on-stack replacement 130 /** Possible OSR bytecode array consisting of prologue and original bytecodes */ 131 private static final HashMapRVM<NormalMethod, byte[]> synthesizedBytecodes = 132 new HashMapRVM<NormalMethod, byte[]>(); 133 /** Possible OSR record of osr prologue */ 134 private static final HashMapRVM<NormalMethod, byte[]> osrPrologues = 135 new HashMapRVM<NormalMethod, byte[]>(); 136 /** 137 * Possibly OSR prologue may change the maximum stack height, remember the 138 * original stack height 139 */ 140 private static final HashMapRVM<NormalMethod, Integer> savedOperandWords = 141 new HashMapRVM<NormalMethod, Integer>(); 142 143 /** 144 * Construct a normal Java bytecode method's information 145 * 146 * @param dc the TypeReference object of the class that declared this field 147 * @param mr the canonical memberReference for this member. 148 * @param mo modifiers associated with this member. 149 * @param et exceptions thrown by this method. 150 * @param lw the number of local words used by the bytecode of this method 151 * @param ow the number of operand words used by the bytecode of this method 152 * @param bc the bytecodes of this method 153 * @param eMap the exception handler map for this method 154 * @param lm the line number map for this method 155 * @param lvt the local variable table for this method 156 * @param constantPool the constantPool for this method 157 * @param sig generic type of this method. 158 * @param annotations array of runtime visible annotations 159 * @param parameterAnnotations array of runtime visible paramter annotations 160 * @param ad annotation default value for that appears in annotation classes 161 */ 162 NormalMethod(TypeReference dc, MemberReference mr, short mo, TypeReference[] et, short lw, short ow, 163 byte[] bc, ExceptionHandlerMap eMap, int[] lm, LocalVariableTable lvt, int[] constantPool, Atom sig, 164 RVMAnnotation[] annotations, RVMAnnotation[][] parameterAnnotations, Object ad) { 165 super(dc, mr, mo, et, sig, annotations, parameterAnnotations, ad); 166 localWords = lw; 167 operandWords = ow; 168 bytecodes = bc; 169 exceptionHandlerMap = eMap; 170 lineNumberMap = lm; 171 localVariableTables.put(this, lvt); 172 computeSummary(constantPool); 173 } 174 175 @Override 176 protected CompiledMethod genCode() throws VerifyError { 177 if (VM.writingBootImage) { 178 return BootImageCompiler.compile(this); 179 } else { 180 return RuntimeCompiler.compile(this); 181 } 182 } 183 184 /** 185 * Space required by this method for its local variables, in words. 186 * Note: local variables include parameters 187 */ 188 @Uninterruptible 189 public int getLocalWords() { 190 return localWords; 191 } 192 193 /** 194 * Space required by this method for its operand stack, in words. 195 */ 196 @Uninterruptible 197 public int getOperandWords() { 198 return operandWords; 199 } 200 201 /** 202 * Get a representation of the bytecodes in the code attribute of this method. 203 * @return object representing the bytecodes 204 */ 205 public BytecodeStream getBytecodes() { 206 return new BytecodeStream(this, bytecodes); 207 } 208 209 /** 210 * Fill in DynamicLink object for the invoke at the given bytecode index 211 * @param dynamicLink the dynamicLink object to initialize 212 * @param bcIndex the bcIndex of the invoke instruction 213 */ 214 @Uninterruptible 215 public void getDynamicLink(DynamicLink dynamicLink, int bcIndex) { 216 if (VM.VerifyAssertions) VM._assert(bytecodes != null); 217 if (VM.VerifyAssertions) VM._assert(bcIndex + 2 < bytecodes.length); 218 int bytecode = bytecodes[bcIndex] & 0xFF; 219 if (VM.VerifyAssertions) { 220 VM._assert((BytecodeConstants.JBC_invokevirtual <= bytecode) && 221 (bytecode <= BytecodeConstants.JBC_invokeinterface)); 222 } 223 int constantPoolIndex = ((bytecodes[bcIndex + 1] & 0xFF) << BITS_IN_BYTE) | (bytecodes[bcIndex + 2] & 0xFF); 224 dynamicLink.set(getDeclaringClass().getMethodRef(constantPoolIndex), bytecode); 225 } 226 227 /** 228 * Size of bytecodes for this method 229 */ 230 public int getBytecodeLength() { 231 return bytecodes.length; 232 } 233 234 /** 235 * Exceptions caught by this method. 236 * @return info (null --> method doesn't catch any exceptions) 237 */ 238 @Uninterruptible 239 public ExceptionHandlerMap getExceptionHandlerMap() { 240 return exceptionHandlerMap; 241 } 242 243 /** 244 * Return the line number information for the argument bytecode index. 245 * @return The line number, a positive integer. Zero means unable to find. 246 */ 247 @Uninterruptible 248 public int getLineNumberForBCIndex(int bci) { 249 if (lineNumberMap == null) return 0; 250 int idx; 251 for (idx = 0; idx < lineNumberMap.length; idx++) { 252 int pc = lineNumberMap[idx] & 0xffff; // lower 16 bits are bcIndex 253 if (bci < pc) { 254 if (idx == 0) idx++; // add 1, so we can subtract 1 below. 255 break; 256 } 257 } 258 return lineNumberMap[--idx] >>> 16; // upper 16 bits are line number 259 } 260 261 // Extra methods for on-stack replacement 262 // BaselineCompiler and BC2IR should check if a method is 263 // for specialization by calling isForOsrSpecialization, the compiler 264 // uses synthesized bytecodes (prologue + original bytecodes) for 265 // OSRing method. Other interfaces of method are not changed, therefore, 266 // dynamic linking and gc referring to bytecodes are safe. 267 268 /** 269 * Checks if the method is in state for OSR specialization now 270 * @return {@code true}, if it is (with prologue) 271 */ 272 public boolean isForOsrSpecialization() { 273 synchronized(synthesizedBytecodes) { 274 return synthesizedBytecodes.get(this) != null; 275 } 276 } 277 278 /** 279 * Sets method in state for OSR specialization, i.e, the subsequent calls 280 * of {@link #getBytecodes} return the stream of specialized bytecodes.<p> 281 * 282 * NB: between flag and action, it should not allow GC or threadSwitch happen. 283 * @param prologue The bytecode of prologue 284 * @param newStackHeight The prologue may change the default height of 285 * stack 286 */ 287 public void setForOsrSpecialization(byte[] prologue, short newStackHeight) { 288 if (VM.VerifyAssertions) { 289 synchronized (synthesizedBytecodes) { 290 VM._assert(synthesizedBytecodes.get(this) == null); 291 } 292 } 293 294 byte[] newBytecodes = new byte[prologue.length + bytecodes.length]; 295 System.arraycopy(prologue, 0, newBytecodes, 0, prologue.length); 296 System.arraycopy(bytecodes, 0, newBytecodes, prologue.length, bytecodes.length); 297 298 synchronized(osrPrologues) { 299 osrPrologues.put(this, prologue); 300 } 301 synchronized(synthesizedBytecodes) { 302 synthesizedBytecodes.put(this, newBytecodes); 303 } 304 synchronized(savedOperandWords) { 305 savedOperandWords.put(this, Integer.valueOf(operandWords)); 306 } 307 if (newStackHeight > operandWords) { 308 this.operandWords = newStackHeight; 309 } 310 } 311 312 /** 313 * Restores the original state of the method. 314 */ 315 public void finalizeOsrSpecialization() { 316 if (VM.VerifyAssertions) { 317 synchronized (synthesizedBytecodes) { 318 VM._assert(synthesizedBytecodes.get(this) != null); 319 } 320 } 321 synchronized(osrPrologues) { 322 osrPrologues.remove(this); 323 } 324 synchronized(synthesizedBytecodes) { 325 synthesizedBytecodes.remove(this); 326 } 327 synchronized(savedOperandWords) { 328 this.operandWords = (short)(savedOperandWords.get(this).intValue()); 329 savedOperandWords.remove(this); 330 } 331 } 332 333 /** 334 * Returns the OSR prologue length for adjusting various tables and maps. 335 * @return the length of prologue if the method is in state for OSR, 336 * 0 otherwise. 337 */ 338 public int getOsrPrologueLength() { 339 if(isForOsrSpecialization()) { 340 synchronized(osrPrologues) { 341 return osrPrologues.get(this).length; 342 } 343 } else { 344 return 0; 345 } 346 } 347 348 /** 349 * Returns a bytecode stream of osr prologue 350 * @return osr prologue bytecode stream 351 */ 352 public BytecodeStream getOsrPrologue() { 353 if (VM.VerifyAssertions) { 354 synchronized (synthesizedBytecodes) { 355 VM._assert(synthesizedBytecodes.get(this) != null); 356 } 357 } 358 byte[] osrPrologue; 359 synchronized(osrPrologues) { 360 osrPrologue = osrPrologues.get(this); 361 } 362 return new BytecodeStream(this, osrPrologue); 363 } 364 365 /** 366 * Returns the synthesized bytecode stream with osr prologue 367 * @return bytecode stream 368 */ 369 public BytecodeStream getOsrSynthesizedBytecodes() { 370 byte[] bytecodes; 371 synchronized(synthesizedBytecodes) { 372 bytecodes = synthesizedBytecodes.get(this); 373 if (VM.VerifyAssertions) VM._assert(bytecodes != null); 374 } 375 return new BytecodeStream(this, bytecodes); 376 } 377 378 /* 379 * Methods to access and compute method summary information 380 */ 381 382 /** 383 * @return An estimate of the expected size of the machine code instructions 384 * that will be generated by the opt compiler if the method is inlined. 385 */ 386 public int inlinedSizeEstimate() { 387 return summarySize & 0xFFFF; 388 } 389 390 /** 391 * @return {@code true} if the method contains a Magic.xxx or Address.yyy 392 */ 393 public boolean hasMagic() { 394 return (summaryFlags & HAS_MAGIC) != 0; 395 } 396 397 /** 398 * @return {@code true} if the method contains a monitorenter/exit or is synchronized 399 */ 400 public boolean hasSynch() { 401 return (summaryFlags & HAS_SYNCH) != 0; 402 } 403 404 /** 405 * @return {@code true} if the method contains an allocation 406 */ 407 public boolean hasAllocation() { 408 return (summaryFlags & HAS_ALLOCATION) != 0; 409 } 410 411 /** 412 * @return {@code true} if the method contains an athrow 413 */ 414 public boolean hasThrow() { 415 return (summaryFlags & HAS_THROW) != 0; 416 } 417 418 /** 419 * @return {@code true} if the method contains an invoke 420 */ 421 public boolean hasInvoke() { 422 return (summaryFlags & HAS_INVOKE) != 0; 423 } 424 425 /** 426 * @return {@code true} if the method contains a getfield or getstatic 427 */ 428 public boolean hasFieldRead() { 429 return (summaryFlags & HAS_FIELD_READ) != 0; 430 } 431 432 /** 433 * @return {@code true} if the method contains a putfield or putstatic 434 */ 435 public boolean hasFieldWrite() { 436 return (summaryFlags & HAS_FIELD_WRITE) != 0; 437 } 438 439 /** 440 * @return {@code true} if the method contains an array load 441 */ 442 public boolean hasArrayRead() { 443 return (summaryFlags & HAS_ARRAY_READ) != 0; 444 } 445 446 /** 447 * @return {@code true} if the method contains an array store 448 */ 449 public boolean hasArrayWrite() { 450 return (summaryFlags & HAS_ARRAY_WRITE) != 0; 451 } 452 453 /** 454 * @return {@code true} if the method contains a jsr 455 */ 456 public boolean hasJSR() { 457 return (summaryFlags & HAS_JSR) != 0; 458 } 459 460 /** 461 * @return {@code true} if the method contains a conditional branch 462 */ 463 public boolean hasCondBranch() { 464 return (summaryFlags & HAS_COND_BRANCH) != 0; 465 } 466 467 /** 468 * @return {@code true} if the method contains a switch 469 */ 470 public boolean hasSwitch() { 471 return (summaryFlags & HAS_SWITCH) != 0; 472 } 473 474 /** 475 * @return {@code true} if the method contains a backwards branch 476 */ 477 public boolean hasBackwardsBranch() { 478 return (summaryFlags & HAS_BACK_BRANCH) != 0; 479 } 480 481 @Override 482 public boolean isRuntimeServiceMethod() { 483 return (summaryFlags & IS_RS_METHOD) != 0; 484 } 485 486 /** 487 * Set the value of the 'runtime service method' flag to the argument 488 * value. A method is considered to be a runtime service method if it 489 * is only/primarily invoked "under the covers" from the generated code 490 * and thus is not subject to inlining via the normal mechanisms. 491 * For example, the implementations of bytecodes such as new or checkcast 492 * or the implementation of yieldpoints. 493 * @param value {@code true} if this is a runtime service method, false it is not. 494 */ 495 public void setRuntimeServiceMethod(boolean value) { 496 if (value) { 497 summaryFlags |= IS_RS_METHOD; 498 } else { 499 summaryFlags &= ~IS_RS_METHOD; 500 } 501 } 502 503 @Override 504 public boolean mayWrite(RVMField field) { 505 if (!hasFieldWrite()) return false; 506 FieldReference it = field.getMemberRef().asFieldReference(); 507 BytecodeStream bcodes = getBytecodes(); 508 while (bcodes.hasMoreBytecodes()) { 509 int opcode = bcodes.nextInstruction(); 510 if (opcode == JBC_putstatic || opcode == JBC_putfield) { 511 FieldReference fr = bcodes.getFieldReference(); 512 if (!fr.definitelyDifferent(it)) return true; 513 } else { 514 bcodes.skipInstruction(); 515 } 516 } 517 return false; 518 } 519 520 /** 521 * For use by {@link RVMClass#allBootImageTypesResolved()} only. 522 */ 523 void recomputeSummary(int[] constantPool) { 524 if (hasFieldRead()) { 525 // Now that all bootimage classes are resolved, we may be able to lower the 526 // estimated machine code size of some getstatics, so recompute summary. 527 computeSummary(constantPool); 528 } 529 530 } 531 532 /** 533 * This method computes a summary of interesting method characteristics 534 * and stores an encoding of the summary as an int. 535 */ 536 private void computeSummary(int[] constantPool) { 537 int calleeSize = 0; 538 if (isSynchronized()) { 539 summaryFlags |= HAS_SYNCH; 540 calleeSize += 2 * SYNCH_COST; // NOTE: ignoring catch/unlock/rethrow block. Probably the right thing to do. 541 } 542 543 BytecodeStream bcodes = getBytecodes(); 544 while (bcodes.hasMoreBytecodes()) { 545 switch (bcodes.nextInstruction()) { 546 // Array loads: null check, bounds check, index computation, load 547 case JBC_iaload: 548 case JBC_laload: 549 case JBC_faload: 550 case JBC_daload: 551 case JBC_aaload: 552 case JBC_baload: 553 case JBC_caload: 554 case JBC_saload: 555 summaryFlags |= HAS_ARRAY_READ; 556 calleeSize += ARRAY_LOAD_COST; 557 break; 558 559 // Array stores: null check, bounds check, index computation, load 560 case JBC_iastore: 561 case JBC_lastore: 562 case JBC_fastore: 563 case JBC_dastore: 564 case JBC_bastore: 565 case JBC_castore: 566 case JBC_sastore: 567 summaryFlags |= HAS_ARRAY_WRITE; 568 calleeSize += ARRAY_STORE_COST; 569 break; 570 case JBC_aastore: 571 summaryFlags |= HAS_ARRAY_WRITE; 572 calleeSize += ARRAY_STORE_COST + STORE_CHECK_COST; 573 break; 574 575 // primitive computations (likely to be very cheap) 576 case JBC_iadd: 577 case JBC_fadd: 578 case JBC_dadd: 579 case JBC_isub: 580 case JBC_fsub: 581 case JBC_dsub: 582 case JBC_imul: 583 case JBC_fmul: 584 case JBC_dmul: 585 case JBC_idiv: 586 case JBC_fdiv: 587 case JBC_ddiv: 588 case JBC_irem: 589 case JBC_frem: 590 case JBC_drem: 591 case JBC_ineg: 592 case JBC_fneg: 593 case JBC_dneg: 594 case JBC_ishl: 595 case JBC_ishr: 596 case JBC_lshr: 597 case JBC_iushr: 598 case JBC_iand: 599 case JBC_ior: 600 case JBC_ixor: 601 case JBC_iinc: 602 calleeSize += SIMPLE_OPERATION_COST; 603 break; 604 605 // long computations may be different cost than primitive computations 606 case JBC_ladd: 607 case JBC_lsub: 608 case JBC_lmul: 609 case JBC_ldiv: 610 case JBC_lrem: 611 case JBC_lneg: 612 case JBC_lshl: 613 case JBC_lushr: 614 case JBC_land: 615 case JBC_lor: 616 case JBC_lxor: 617 calleeSize += LONG_OPERATION_COST; 618 break; 619 620 // Some conversion operations are very cheap 621 case JBC_int2byte: 622 case JBC_int2char: 623 case JBC_int2short: 624 calleeSize += SIMPLE_OPERATION_COST; 625 break; 626 // Others are a little more costly 627 case JBC_i2l: 628 case JBC_l2i: 629 calleeSize += LONG_OPERATION_COST; 630 break; 631 // Most are roughly as expensive as a call 632 case JBC_i2f: 633 case JBC_i2d: 634 case JBC_l2f: 635 case JBC_l2d: 636 case JBC_f2i: 637 case JBC_f2l: 638 case JBC_f2d: 639 case JBC_d2i: 640 case JBC_d2l: 641 case JBC_d2f: 642 calleeSize += CALL_COST; 643 break; 644 645 // approximate compares as 1 simple operation 646 case JBC_lcmp: 647 case JBC_fcmpl: 648 case JBC_fcmpg: 649 case JBC_dcmpl: 650 case JBC_dcmpg: 651 calleeSize += SIMPLE_OPERATION_COST; 652 break; 653 654 // most control flow is cheap; jsr is more expensive 655 case JBC_ifeq: 656 case JBC_ifne: 657 case JBC_iflt: 658 case JBC_ifge: 659 case JBC_ifgt: 660 case JBC_ifle: 661 case JBC_if_icmpeq: 662 case JBC_if_icmpne: 663 case JBC_if_icmplt: 664 case JBC_if_icmpge: 665 case JBC_if_icmpgt: 666 case JBC_if_icmple: 667 case JBC_if_acmpeq: 668 case JBC_if_acmpne: 669 case JBC_ifnull: 670 case JBC_ifnonnull: 671 summaryFlags |= HAS_COND_BRANCH; 672 if (bcodes.getBranchOffset() < 0) summaryFlags |= HAS_BACK_BRANCH; 673 calleeSize += SIMPLE_OPERATION_COST; 674 continue; // we've processed all of the bytes, so avoid the call to skipInstruction() 675 case JBC_goto: 676 if (bcodes.getBranchOffset() < 0) summaryFlags |= HAS_BACK_BRANCH; 677 calleeSize += SIMPLE_OPERATION_COST; 678 continue; // we've processed all of the bytes, so avoid the call to skipInstruction() 679 case JBC_goto_w: 680 if (bcodes.getWideBranchOffset() < 0) summaryFlags |= HAS_BACK_BRANCH; 681 calleeSize += SIMPLE_OPERATION_COST; 682 continue; // we've processed all of the bytes, so avoid the call to skipInstruction() 683 case JBC_jsr: 684 case JBC_jsr_w: 685 summaryFlags |= HAS_JSR; 686 calleeSize += JSR_COST; 687 break; 688 689 case JBC_tableswitch: 690 case JBC_lookupswitch: 691 summaryFlags |= HAS_SWITCH; 692 calleeSize += SWITCH_COST; 693 break; 694 695 case JBC_putstatic: 696 case JBC_putfield: 697 summaryFlags |= HAS_FIELD_WRITE; 698 calleeSize += SIMPLE_OPERATION_COST; 699 break; 700 701 case JBC_getstatic: 702 summaryFlags |= HAS_FIELD_READ; 703 704 // Treat getstatic of primitive values from final static fields 705 // as "free" since we expect it be a compile time constant by the 706 // time the opt compiler compiles the method. 707 FieldReference fldRef = bcodes.getFieldReference(constantPool); 708 if (fldRef.getFieldContentsType().isPrimitiveType()) { 709 RVMField fld = fldRef.peekResolvedField(); 710 if (fld == null || !fld.isFinal()){ 711 calleeSize += SIMPLE_OPERATION_COST; 712 } 713 } else { 714 calleeSize += SIMPLE_OPERATION_COST; 715 } 716 continue; // we've processed all of the bytes, so avoid the call to skipInstruction() 717 718 case JBC_getfield: 719 summaryFlags |= HAS_FIELD_READ; 720 calleeSize += SIMPLE_OPERATION_COST; 721 break; 722 723 // Various flavors of calls. Assign them call cost (differentiate?) 724 case JBC_invokevirtual: 725 case JBC_invokespecial: 726 case JBC_invokestatic: 727 // Special case Magic's as being cheaper. 728 MethodReference meth = bcodes.getMethodReference(constantPool); 729 if (meth.getType().isMagicType()) { 730 summaryFlags |= HAS_MAGIC; 731 calleeSize += MAGIC_COST; 732 } else { 733 summaryFlags |= HAS_INVOKE; 734 calleeSize += CALL_COST; 735 } 736 continue; // we've processed all of the bytes, so avoid the call to skipInstruction() 737 738 case JBC_invokeinterface: 739 summaryFlags |= HAS_INVOKE; 740 calleeSize += CALL_COST; 741 break; 742 743 case JBC_xxxunusedxxx: 744 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 745 break; 746 747 case JBC_new: 748 case JBC_newarray: 749 case JBC_anewarray: 750 summaryFlags |= HAS_ALLOCATION; 751 calleeSize += ALLOCATION_COST; 752 break; 753 754 case JBC_arraylength: 755 calleeSize += SIMPLE_OPERATION_COST; 756 break; 757 758 case JBC_athrow: 759 summaryFlags |= HAS_THROW; 760 calleeSize += THROW_COST; 761 break; 762 763 case JBC_checkcast: 764 case JBC_instanceof: 765 calleeSize += CLASS_CHECK_COST; 766 break; 767 768 case JBC_monitorenter: 769 case JBC_monitorexit: 770 summaryFlags |= HAS_SYNCH; 771 calleeSize += SYNCH_COST; 772 break; 773 774 case JBC_multianewarray: 775 summaryFlags |= HAS_ALLOCATION; 776 calleeSize += CALL_COST; 777 break; 778 } 779 bcodes.skipInstruction(); 780 } 781 if (calleeSize > Character.MAX_VALUE) { 782 summarySize = Character.MAX_VALUE; 783 } else { 784 summarySize = (char) calleeSize; 785 } 786 } 787 788 /** 789 * @return LocalVariableTable associated with this method 790 */ 791 public LocalVariableTable getLocalVariableTable() { 792 return localVariableTables.get(this); 793 } 794 }