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