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    }