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 becuase 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 (null --> none)
109 */
110 private final byte[] bytecodes;
111
112 /**
113 * try/catch/finally blocks for this method (null --> none)
114 */
115 private final ExceptionHandlerMap exceptionHandlerMap;
116
117 /**
118 * pc to source-line info (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 /**
176 * Generate the code for this method
177 */
178 protected CompiledMethod genCode() throws VerifyError {
179 if (VM.writingBootImage) {
180 return BootImageCompiler.compile(this);
181 } else {
182 return RuntimeCompiler.compile(this);
183 }
184 }
185
186 /**
187 * Space required by this method for its local variables, in words.
188 * Note: local variables include parameters
189 */
190 @Uninterruptible
191 public int getLocalWords() {
192 return localWords;
193 }
194
195 /**
196 * Space required by this method for its operand stack, in words.
197 */
198 @Uninterruptible
199 public int getOperandWords() {
200 return operandWords;
201 }
202
203 /**
204 * Get a representation of the bytecodes in the code attribute of this method.
205 * @return object representing the bytecodes
206 */
207 public BytecodeStream getBytecodes() {
208 return new BytecodeStream(this, bytecodes);
209 }
210
211 /**
212 * Fill in DynamicLink object for the invoke at the given bytecode index
213 * @param dynamicLink the dynamicLink object to initialize
214 * @param bcIndex the bcIndex of the invoke instruction
215 */
216 @Uninterruptible
217 public void getDynamicLink(DynamicLink dynamicLink, int bcIndex) {
218 if (VM.VerifyAssertions) VM._assert(bytecodes != null);
219 if (VM.VerifyAssertions) VM._assert(bcIndex + 2 < bytecodes.length);
220 int bytecode = bytecodes[bcIndex] & 0xFF;
221 if (VM.VerifyAssertions) {
222 VM._assert((BytecodeConstants.JBC_invokevirtual <= bytecode) &&
223 (bytecode <= BytecodeConstants.JBC_invokeinterface));
224 }
225 int constantPoolIndex = ((bytecodes[bcIndex + 1] & 0xFF) << BITS_IN_BYTE) | (bytecodes[bcIndex + 2] & 0xFF);
226 dynamicLink.set(getDeclaringClass().getMethodRef(constantPoolIndex), bytecode);
227 }
228
229 /**
230 * Size of bytecodes for this method
231 */
232 public int getBytecodeLength() {
233 return bytecodes.length;
234 }
235
236 /**
237 * Exceptions caught by this method.
238 * @return info (null --> method doesn't catch any exceptions)
239 */
240 @Uninterruptible
241 public ExceptionHandlerMap getExceptionHandlerMap() {
242 return exceptionHandlerMap;
243 }
244
245 /**
246 * Return the line number information for the argument bytecode index.
247 * @return The line number, a positive integer. Zero means unable to find.
248 */
249 @Uninterruptible
250 public int getLineNumberForBCIndex(int bci) {
251 if (lineNumberMap == null) return 0;
252 int idx;
253 for (idx = 0; idx < lineNumberMap.length; idx++) {
254 int pc = lineNumberMap[idx] & 0xffff; // lower 16 bits are bcIndex
255 if (bci < pc) {
256 if (idx == 0) idx++; // add 1, so we can subtract 1 below.
257 break;
258 }
259 }
260 return lineNumberMap[--idx] >>> 16; // upper 16 bits are line number
261 }
262
263 // Extra methods for on-stack replacement
264 // BaselineCompiler and BC2IR should check if a method is
265 // for specialization by calling isForOsrSpecialization, the compiler
266 // uses synthesized bytecodes (prologue + original bytecodes) for
267 // OSRing method. Other interfaces of method are not changed, therefore,
268 // dynamic linking and gc referring to bytecodes are safe.
269
270 /**
271 * Checks if the method is in state for OSR specialization now
272 * @return true, if it is (with prologue)
273 */
274 public boolean isForOsrSpecialization() {
275 synchronized(synthesizedBytecodes) {
276 return synthesizedBytecodes.get(this) != null;
277 }
278 }
279
280 /**
281 * Sets method in state for OSR specialization, i.e, the subsequent calls
282 * of {@link #getBytecodes} return the stream of specialized bytecodes.
283 *
284 * NB: between flag and action, it should not allow GC or threadSwitch happen.
285 * @param prologue The bytecode of prologue
286 * @param newStackHeight The prologue may change the default height of
287 * stack
288 */
289 public void setForOsrSpecialization(byte[] prologue, short newStackHeight) {
290 if (VM.VerifyAssertions) {
291 synchronized (synthesizedBytecodes) {
292 VM._assert(synthesizedBytecodes.get(this) == null);
293 }
294 }
295
296 byte[] newBytecodes = new byte[prologue.length + bytecodes.length];
297 System.arraycopy(prologue, 0, newBytecodes, 0, prologue.length);
298 System.arraycopy(bytecodes, 0, newBytecodes, prologue.length, bytecodes.length);
299
300 synchronized(osrPrologues) {
301 osrPrologues.put(this, prologue);
302 }
303 synchronized(synthesizedBytecodes) {
304 synthesizedBytecodes.put(this, newBytecodes);
305 }
306 synchronized(savedOperandWords) {
307 savedOperandWords.put(this, Integer.valueOf(operandWords));
308 }
309 if (newStackHeight > operandWords) {
310 this.operandWords = newStackHeight;
311 }
312 }
313
314 /**
315 * Restores the original state of the method.
316 */
317 public void finalizeOsrSpecialization() {
318 if (VM.VerifyAssertions) {
319 synchronized (synthesizedBytecodes) {
320 VM._assert(synthesizedBytecodes.get(this) != null);
321 }
322 }
323 synchronized(osrPrologues) {
324 osrPrologues.remove(this);
325 }
326 synchronized(synthesizedBytecodes) {
327 synthesizedBytecodes.remove(this);
328 }
329 synchronized(savedOperandWords) {
330 this.operandWords = (short)(savedOperandWords.get(this).intValue());
331 savedOperandWords.remove(this);
332 }
333 }
334
335 /**
336 * Returns the OSR prologue length for adjusting various tables and maps.
337 * @return the length of prologue if the method is in state for OSR,
338 * 0 otherwise.
339 */
340 public int getOsrPrologueLength() {
341 if(isForOsrSpecialization()) {
342 synchronized(osrPrologues) {
343 return osrPrologues.get(this).length;
344 }
345 } else {
346 return 0;
347 }
348 }
349
350 /**
351 * Returns a bytecode stream of osr prologue
352 * @return osr prologue bytecode stream
353 */
354 public BytecodeStream getOsrPrologue() {
355 if (VM.VerifyAssertions) {
356 synchronized (synthesizedBytecodes) {
357 VM._assert(synthesizedBytecodes.get(this) != null);
358 }
359 }
360 byte[] osrPrologue;
361 synchronized(osrPrologues) {
362 osrPrologue = osrPrologues.get(this);
363 }
364 return new BytecodeStream(this, osrPrologue);
365 }
366
367 /**
368 * Returns the synthesized bytecode stream with osr prologue
369 * @return bytecode stream
370 */
371 public BytecodeStream getOsrSynthesizedBytecodes() {
372 byte[] bytecodes;
373 synchronized(synthesizedBytecodes) {
374 bytecodes = synthesizedBytecodes.get(this);
375 if (VM.VerifyAssertions) VM._assert(bytecodes != null);
376 }
377 return new BytecodeStream(this, bytecodes);
378 }
379
380 /*
381 * Methods to access and compute method summary information
382 */
383
384 /**
385 * @return An estimate of the expected size of the machine code instructions
386 * that will be generated by the opt compiler if the method is inlined.
387 */
388 public int inlinedSizeEstimate() {
389 return summarySize & 0xFFFF;
390 }
391
392 /**
393 * @return true if the method contains a Magic.xxx or Address.yyy
394 */
395 public boolean hasMagic() {
396 return (summaryFlags & HAS_MAGIC) != 0;
397 }
398
399 /**
400 * @return true if the method contains a monitorenter/exit or is synchronized
401 */
402 public boolean hasSynch() {
403 return (summaryFlags & HAS_SYNCH) != 0;
404 }
405
406 /**
407 * @return true if the method contains an allocation
408 */
409 public boolean hasAllocation() {
410 return (summaryFlags & HAS_ALLOCATION) != 0;
411 }
412
413 /**
414 * @return true if the method contains an athrow
415 */
416 public boolean hasThrow() {
417 return (summaryFlags & HAS_THROW) != 0;
418 }
419
420 /**
421 * @return true if the method contains an invoke
422 */
423 public boolean hasInvoke() {
424 return (summaryFlags & HAS_INVOKE) != 0;
425 }
426
427 /**
428 * @return true if the method contains a getfield or getstatic
429 */
430 public boolean hasFieldRead() {
431 return (summaryFlags & HAS_FIELD_READ) != 0;
432 }
433
434 /**
435 * @return true if the method contains a putfield or putstatic
436 */
437 public boolean hasFieldWrite() {
438 return (summaryFlags & HAS_FIELD_WRITE) != 0;
439 }
440
441 /**
442 * @return true if the method contains an array load
443 */
444 public boolean hasArrayRead() {
445 return (summaryFlags & HAS_ARRAY_READ) != 0;
446 }
447
448 /**
449 * @return true if the method contains an array store
450 */
451 public boolean hasArrayWrite() {
452 return (summaryFlags & HAS_ARRAY_WRITE) != 0;
453 }
454
455 /**
456 * @return true if the method contains a jsr
457 */
458 public boolean hasJSR() {
459 return (summaryFlags & HAS_JSR) != 0;
460 }
461
462 /**
463 * @return true if the method contains a conditional branch
464 */
465 public boolean hasCondBranch() {
466 return (summaryFlags & HAS_COND_BRANCH) != 0;
467 }
468
469 /**
470 * @return true if the method contains a switch
471 */
472 public boolean hasSwitch() {
473 return (summaryFlags & HAS_SWITCH) != 0;
474 }
475
476 /**
477 * @return true if the method contains a backwards branch
478 */
479 public boolean hasBackwardsBranch() {
480 return (summaryFlags & HAS_BACK_BRANCH) != 0;
481 }
482
483 /**
484 * @return true if the method is the implementation of a runtime service
485 * that is called "under the covers" from the generated code and thus is not subject to
486 * inlining via the normal mechanisms.
487 */
488 public boolean isRuntimeServiceMethod() {
489 return (summaryFlags & IS_RS_METHOD) != 0;
490 }
491
492 /**
493 * Set the value of the 'runtime service method' flag to the argument
494 * value. A method is considered to be a runtime service method if it
495 * is only/primarily invoked "under the covers" from the generated code
496 * and thus is not subject to inlining via the normal mechanisms.
497 * For example, the implementations of bytecodes such as new or checkcast
498 * or the implementation of yieldpoints.
499 * @param value true if this is a runtime service method, false it is not.
500 */
501 public void setRuntimeServiceMethod(boolean value) {
502 if (value) {
503 summaryFlags |= IS_RS_METHOD;
504 } else {
505 summaryFlags &= ~IS_RS_METHOD;
506 }
507 }
508
509 /**
510 * @return true if the method may write to a given field
511 */
512 public boolean mayWrite(RVMField field) {
513 if (!hasFieldWrite()) return false;
514 FieldReference it = field.getMemberRef().asFieldReference();
515 BytecodeStream bcodes = getBytecodes();
516 while (bcodes.hasMoreBytecodes()) {
517 int opcode = bcodes.nextInstruction();
518 if (opcode == JBC_putstatic || opcode == JBC_putfield) {
519 FieldReference fr = bcodes.getFieldReference();
520 if (!fr.definitelyDifferent(it)) return true;
521 } else {
522 bcodes.skipInstruction();
523 }
524 }
525 return false;
526 }
527
528 /**
529 * For use by {@link RVMClass#allBootImageTypesResolved()} only.
530 */
531 void recomputeSummary(int[] constantPool) {
532 if (hasFieldRead()) {
533 // Now that all bootimage classes are resolved, we may be able to lower the
534 // estimated machine code size of some getstatics, so recompute summary.
535 computeSummary(constantPool);
536 }
537
538 }
539
540 /**
541 * This method computes a summary of interesting method characteristics
542 * and stores an encoding of the summary as an int.
543 */
544 private void computeSummary(int[] constantPool) {
545 int calleeSize = 0;
546 if (isSynchronized()) {
547 summaryFlags |= HAS_SYNCH;
548 calleeSize += 2 * SYNCH_COST; // NOTE: ignoring catch/unlock/rethrow block. Probably the right thing to do.
549 }
550
551 BytecodeStream bcodes = getBytecodes();
552 while (bcodes.hasMoreBytecodes()) {
553 switch (bcodes.nextInstruction()) {
554 // Array loads: null check, bounds check, index computation, load
555 case JBC_iaload:
556 case JBC_laload:
557 case JBC_faload:
558 case JBC_daload:
559 case JBC_aaload:
560 case JBC_baload:
561 case JBC_caload:
562 case JBC_saload:
563 summaryFlags |= HAS_ARRAY_READ;
564 calleeSize += ARRAY_LOAD_COST;
565 break;
566
567 // Array stores: null check, bounds check, index computation, load
568 case JBC_iastore:
569 case JBC_lastore:
570 case JBC_fastore:
571 case JBC_dastore:
572 case JBC_bastore:
573 case JBC_castore:
574 case JBC_sastore:
575 summaryFlags |= HAS_ARRAY_WRITE;
576 calleeSize += ARRAY_STORE_COST;
577 break;
578 case JBC_aastore:
579 summaryFlags |= HAS_ARRAY_WRITE;
580 calleeSize += ARRAY_STORE_COST + STORE_CHECK_COST;
581 break;
582
583 // primitive computations (likely to be very cheap)
584 case JBC_iadd:
585 case JBC_fadd:
586 case JBC_dadd:
587 case JBC_isub:
588 case JBC_fsub:
589 case JBC_dsub:
590 case JBC_imul:
591 case JBC_fmul:
592 case JBC_dmul:
593 case JBC_idiv:
594 case JBC_fdiv:
595 case JBC_ddiv:
596 case JBC_irem:
597 case JBC_frem:
598 case JBC_drem:
599 case JBC_ineg:
600 case JBC_fneg:
601 case JBC_dneg:
602 case JBC_ishl:
603 case JBC_ishr:
604 case JBC_lshr:
605 case JBC_iushr:
606 case JBC_iand:
607 case JBC_ior:
608 case JBC_ixor:
609 case JBC_iinc:
610 calleeSize += SIMPLE_OPERATION_COST;
611 break;
612
613 // long computations may be different cost than primitive computations
614 case JBC_ladd:
615 case JBC_lsub:
616 case JBC_lmul:
617 case JBC_ldiv:
618 case JBC_lrem:
619 case JBC_lneg:
620 case JBC_lshl:
621 case JBC_lushr:
622 case JBC_land:
623 case JBC_lor:
624 case JBC_lxor:
625 calleeSize += LONG_OPERATION_COST;
626 break;
627
628 // Some conversion operations are very cheap
629 case JBC_int2byte:
630 case JBC_int2char:
631 case JBC_int2short:
632 calleeSize += SIMPLE_OPERATION_COST;
633 break;
634 // Others are a little more costly
635 case JBC_i2l:
636 case JBC_l2i:
637 calleeSize += LONG_OPERATION_COST;
638 break;
639 // Most are roughly as expensive as a call
640 case JBC_i2f:
641 case JBC_i2d:
642 case JBC_l2f:
643 case JBC_l2d:
644 case JBC_f2i:
645 case JBC_f2l:
646 case JBC_f2d:
647 case JBC_d2i:
648 case JBC_d2l:
649 case JBC_d2f:
650 calleeSize += CALL_COST;
651 break;
652
653 // approximate compares as 1 simple operation
654 case JBC_lcmp:
655 case JBC_fcmpl:
656 case JBC_fcmpg:
657 case JBC_dcmpl:
658 case JBC_dcmpg:
659 calleeSize += SIMPLE_OPERATION_COST;
660 break;
661
662 // most control flow is cheap; jsr is more expensive
663 case JBC_ifeq:
664 case JBC_ifne:
665 case JBC_iflt:
666 case JBC_ifge:
667 case JBC_ifgt:
668 case JBC_ifle:
669 case JBC_if_icmpeq:
670 case JBC_if_icmpne:
671 case JBC_if_icmplt:
672 case JBC_if_icmpge:
673 case JBC_if_icmpgt:
674 case JBC_if_icmple:
675 case JBC_if_acmpeq:
676 case JBC_if_acmpne:
677 case JBC_ifnull:
678 case JBC_ifnonnull:
679 summaryFlags |= HAS_COND_BRANCH;
680 if (bcodes.getBranchOffset() < 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_goto:
684 if (bcodes.getBranchOffset() < 0) summaryFlags |= HAS_BACK_BRANCH;
685 calleeSize += SIMPLE_OPERATION_COST;
686 continue; // we've processed all of the bytes, so avoid the call to skipInstruction()
687 case JBC_goto_w:
688 if (bcodes.getWideBranchOffset() < 0) summaryFlags |= HAS_BACK_BRANCH;
689 calleeSize += SIMPLE_OPERATION_COST;
690 continue; // we've processed all of the bytes, so avoid the call to skipInstruction()
691 case JBC_jsr:
692 case JBC_jsr_w:
693 summaryFlags |= HAS_JSR;
694 calleeSize += JSR_COST;
695 break;
696
697 case JBC_tableswitch:
698 case JBC_lookupswitch:
699 summaryFlags |= HAS_SWITCH;
700 calleeSize += SWITCH_COST;
701 break;
702
703 case JBC_putstatic:
704 case JBC_putfield:
705 summaryFlags |= HAS_FIELD_WRITE;
706 calleeSize += SIMPLE_OPERATION_COST;
707 break;
708
709 case JBC_getstatic:
710 summaryFlags |= HAS_FIELD_READ;
711
712 // Treat getstatic of primitive values from final static fields
713 // as "free" since we expect it be a compile time constant by the
714 // time the opt compiler compiles the method.
715 FieldReference fldRef = bcodes.getFieldReference(constantPool);
716 if (fldRef.getFieldContentsType().isPrimitiveType()) {
717 RVMField fld = fldRef.peekResolvedField();
718 if (fld == null || !fld.isFinal()){
719 calleeSize += SIMPLE_OPERATION_COST;
720 }
721 } else {
722 calleeSize += SIMPLE_OPERATION_COST;
723 }
724 continue; // we've processed all of the bytes, so avoid the call to skipInstruction()
725
726 case JBC_getfield:
727 summaryFlags |= HAS_FIELD_READ;
728 calleeSize += SIMPLE_OPERATION_COST;
729 break;
730
731 // Various flavors of calls. Assign them call cost (differentiate?)
732 case JBC_invokevirtual:
733 case JBC_invokespecial:
734 case JBC_invokestatic:
735 // Special case Magic's as being cheaper.
736 MethodReference meth = bcodes.getMethodReference(constantPool);
737 if (meth.getType().isMagicType()) {
738 summaryFlags |= HAS_MAGIC;
739 calleeSize += MAGIC_COST;
740 } else {
741 summaryFlags |= HAS_INVOKE;
742 calleeSize += CALL_COST;
743 }
744 continue; // we've processed all of the bytes, so avoid the call to skipInstruction()
745
746 case JBC_invokeinterface:
747 summaryFlags |= HAS_INVOKE;
748 calleeSize += CALL_COST;
749 break;
750
751 case JBC_xxxunusedxxx:
752 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
753 break;
754
755 case JBC_new:
756 case JBC_newarray:
757 case JBC_anewarray:
758 summaryFlags |= HAS_ALLOCATION;
759 calleeSize += ALLOCATION_COST;
760 break;
761
762 case JBC_arraylength:
763 calleeSize += SIMPLE_OPERATION_COST;
764 break;
765
766 case JBC_athrow:
767 summaryFlags |= HAS_THROW;
768 calleeSize += THROW_COST;
769 break;
770
771 case JBC_checkcast:
772 case JBC_instanceof:
773 calleeSize += CLASS_CHECK_COST;
774 break;
775
776 case JBC_monitorenter:
777 case JBC_monitorexit:
778 summaryFlags |= HAS_SYNCH;
779 calleeSize += SYNCH_COST;
780 break;
781
782 case JBC_multianewarray:
783 summaryFlags |= HAS_ALLOCATION;
784 calleeSize += CALL_COST;
785 break;
786 }
787 bcodes.skipInstruction();
788 }
789 if (calleeSize > Character.MAX_VALUE) {
790 summarySize = Character.MAX_VALUE;
791 } else {
792 summarySize = (char) calleeSize;
793 }
794 }
795
796 /**
797 * @return LocalVariableTable associated with this method
798 */
799 public LocalVariableTable getLocalVariableTable() {
800 return localVariableTables.get(this);
801 }
802 }