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 --&gt; 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}