001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003,2004 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba.vna;
021:
022: import java.util.HashMap;
023:
024: import org.apache.bcel.Constants;
025: import org.apache.bcel.classfile.ConstantClass;
026: import org.apache.bcel.generic.ArrayInstruction;
027: import org.apache.bcel.generic.CHECKCAST;
028: import org.apache.bcel.generic.ConstantPoolGen;
029: import org.apache.bcel.generic.GETFIELD;
030: import org.apache.bcel.generic.GETSTATIC;
031: import org.apache.bcel.generic.IINC;
032: import org.apache.bcel.generic.INVOKEINTERFACE;
033: import org.apache.bcel.generic.INVOKESPECIAL;
034: import org.apache.bcel.generic.INVOKESTATIC;
035: import org.apache.bcel.generic.INVOKEVIRTUAL;
036: import org.apache.bcel.generic.Instruction;
037: import org.apache.bcel.generic.InstructionHandle;
038: import org.apache.bcel.generic.InvokeInstruction;
039: import org.apache.bcel.generic.LDC;
040: import org.apache.bcel.generic.MONITORENTER;
041: import org.apache.bcel.generic.MethodGen;
042: import org.apache.bcel.generic.PUTFIELD;
043: import org.apache.bcel.generic.PUTSTATIC;
044:
045: import edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor;
046: import edu.umd.cs.findbugs.ba.AnalysisContext;
047: import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
048: import edu.umd.cs.findbugs.ba.Debug;
049: import edu.umd.cs.findbugs.ba.Hierarchy;
050: import edu.umd.cs.findbugs.ba.InvalidBytecodeException;
051: import edu.umd.cs.findbugs.ba.RepositoryLookupFailureCallback;
052: import edu.umd.cs.findbugs.ba.XField;
053:
054: /**
055: * Visitor which models the effects of bytecode instructions
056: * on value numbers of values in the operand stack frames.
057: *
058: * @see ValueNumber
059: * @see ValueNumberFrame
060: * @see ValueNumberAnalysis
061: * @author David Hovemeyer
062: */
063: public class ValueNumberFrameModelingVisitor extends
064: AbstractFrameModelingVisitor<ValueNumber, ValueNumberFrame>
065: implements Debug, ValueNumberAnalysisFeatures {
066:
067: /* ----------------------------------------------------------------------
068: * Fields
069: * ---------------------------------------------------------------------- */
070:
071: private MethodGen methodGen;
072: private ValueNumberFactory factory;
073: private ValueNumberCache cache;
074: private LoadedFieldSet loadedFieldSet;
075: private HashMap<String, ValueNumber> classObjectValueMap;
076: private HashMap<Object, ValueNumber> constantValueMap;
077: private HashMap<ValueNumber, String> stringConstantMap;
078: private RepositoryLookupFailureCallback lookupFailureCallback;
079: private InstructionHandle handle;
080:
081: /* ----------------------------------------------------------------------
082: * Public interface
083: * ---------------------------------------------------------------------- */
084:
085: /**
086: * Constructor.
087: *
088: * @param methodGen the method being analyzed
089: * @param factory factory for ValueNumbers for the method
090: * @param cache cache of input/output transformations for each instruction
091: * @param loadedFieldSet fields loaded/stored by each instruction and entire method
092: * @param lookupFailureCallback callback to use to report class lookup failures
093: */
094: public ValueNumberFrameModelingVisitor(MethodGen methodGen,
095: ValueNumberFactory factory, ValueNumberCache cache,
096: LoadedFieldSet loadedFieldSet,
097: RepositoryLookupFailureCallback lookupFailureCallback) {
098:
099: super (methodGen.getConstantPool());
100: this .methodGen = methodGen;
101: this .factory = factory;
102: this .cache = cache;
103: this .loadedFieldSet = loadedFieldSet;
104: this .classObjectValueMap = new HashMap<String, ValueNumber>();
105: this .constantValueMap = new HashMap<Object, ValueNumber>();
106: this .stringConstantMap = new HashMap<ValueNumber, String>();
107: this .lookupFailureCallback = lookupFailureCallback;
108: }
109:
110: @Override
111: public ValueNumber getDefaultValue() {
112: return factory.createFreshValue();
113: }
114:
115: /**
116: * Set the instruction handle of the instruction currently being visited.
117: * This must be called before the instruction accepts this visitor!
118: */
119: public void setHandle(InstructionHandle handle) {
120: this .handle = handle;
121: }
122:
123: /* ----------------------------------------------------------------------
124: * Instruction modeling
125: * ---------------------------------------------------------------------- */
126:
127: /**
128: * Determine whether redundant load elimination
129: * should be performed for the heap location referenced by
130: * the current instruction.
131: *
132: * @return true if we should do redundant load elimination
133: * for the current instruction, false if not
134: */
135: private boolean doRedundantLoadElimination() {
136: if (!REDUNDANT_LOAD_ELIMINATION)
137: return false;
138:
139: XField xfield = loadedFieldSet.getField(handle);
140: if (xfield == null)
141: return false;
142:
143: if (!xfield.isReferenceType())
144: return false;
145:
146: // Don't do redundant load elimination for fields that
147: // are loaded in only one place.
148: if (false && loadedFieldSet.getLoadStoreCount(xfield)
149: .getLoadCount() <= 1)
150: return false;
151:
152: return true;
153: }
154:
155: /**
156: * Determine whether forward substitution
157: * should be performed for the heap location referenced by
158: * the current instruction.
159: *
160: * @return true if we should do forward substitution
161: * for the current instruction, false if not
162: */
163: private boolean doForwardSubstitution() {
164: if (!REDUNDANT_LOAD_ELIMINATION)
165: return false;
166:
167: XField xfield = loadedFieldSet.getField(handle);
168: if (xfield == null)
169: return false;
170:
171: if (!xfield.isReferenceType())
172: return false;
173:
174: // Don't do forward substitution for fields that
175: // are never read.
176: if (!loadedFieldSet.isLoaded(xfield))
177: return false;
178:
179: return true;
180: }
181:
182: private void checkConsumedAndProducedValues(Instruction ins,
183: ValueNumber[] consumedValueList,
184: ValueNumber[] producedValueList) {
185: int numConsumed = ins.consumeStack(getCPG());
186: int numProduced = ins.produceStack(getCPG());
187:
188: if (numConsumed == Constants.UNPREDICTABLE)
189: throw new InvalidBytecodeException(
190: "Unpredictable stack consumption for " + ins);
191: if (numProduced == Constants.UNPREDICTABLE)
192: throw new InvalidBytecodeException(
193: "Unpredictable stack production for " + ins);
194:
195: if (consumedValueList.length != numConsumed) {
196: throw new IllegalStateException(
197: "Wrong number of values consumed for " + ins
198: + ": expected " + numConsumed + ", got "
199: + consumedValueList.length);
200: }
201:
202: if (producedValueList.length != numProduced) {
203: throw new IllegalStateException(
204: "Wrong number of values produced for " + ins
205: + ": expected " + numProduced + ", got "
206: + producedValueList.length);
207: }
208: }
209:
210: /**
211: * This is the default instruction modeling method.
212: */
213: @Override
214: public void modelNormalInstruction(Instruction ins,
215: int numWordsConsumed, int numWordsProduced) {
216:
217: int flags = 0;
218: if (ins instanceof InvokeInstruction)
219: flags = ValueNumber.RETURN_VALUE;
220: else if (ins instanceof ArrayInstruction)
221: flags = ValueNumber.ARRAY_VALUE;
222:
223: // Get the input operands to this instruction.
224: ValueNumber[] inputValueList = popInputValues(numWordsConsumed);
225:
226: // See if we have the output operands in the cache.
227: // If not, push default (fresh) values for the output,
228: // and add them to the cache.
229: ValueNumber[] outputValueList = getOutputValues(inputValueList,
230: numWordsProduced, flags);
231:
232: if (VERIFY_INTEGRITY) {
233: checkConsumedAndProducedValues(ins, inputValueList,
234: outputValueList);
235: }
236:
237: // Push output operands on stack.
238: pushOutputValues(outputValueList);
239: }
240:
241: @Override
242: public void visitGETFIELD(GETFIELD obj) {
243: try {
244: XField xfield = Hierarchy.findXField(obj, getCPG());
245: if (xfield != null) {
246: if (xfield.isVolatile())
247: getFrame().killAllLoads();
248:
249: if (doRedundantLoadElimination()) {
250: loadInstanceField(xfield, obj);
251: return;
252: }
253: }
254: } catch (ClassNotFoundException e) {
255: lookupFailureCallback.reportMissingClass(e);
256: }
257:
258: handleNormalInstruction(obj);
259: }
260:
261: @Override
262: public void visitPUTFIELD(PUTFIELD obj) {
263: if (doForwardSubstitution()) {
264: try {
265: XField xfield = Hierarchy.findXField(obj, getCPG());
266: if (xfield != null) {
267: storeInstanceField(xfield, obj, false);
268: return;
269: }
270: } catch (ClassNotFoundException e) {
271: lookupFailureCallback.reportMissingClass(e);
272: }
273: }
274: handleNormalInstruction(obj);
275: }
276:
277: private static final ValueNumber[] EMPTY_INPUT_VALUE_LIST = new ValueNumber[0];
278:
279: @Override
280: public void visitGETSTATIC(GETSTATIC obj) {
281: ConstantPoolGen cpg = getCPG();
282:
283: String fieldName = obj.getName(cpg);
284: String fieldSig = obj.getSignature(cpg);
285: ValueNumberFrame frame = getFrame();
286:
287: if (RLE_DEBUG) {
288: System.out.println("GETSTATIC of " + fieldName + " : "
289: + fieldSig);
290: }
291: // Is this an access of a Class object?
292: if (fieldName.startsWith("class$")
293: && fieldSig.equals("Ljava/lang/Class;")) {
294: String className = fieldName.substring("class$".length())
295: .replace('$', '.');
296: if (RLE_DEBUG)
297: System.out.println("[found load of class object "
298: + className + "]");
299: ValueNumber value = getClassObjectValue(className);
300: frame.pushValue(value);
301: return;
302: }
303: try {
304: XField xfield = Hierarchy.findXField(obj, getCPG());
305: if (xfield != null) {
306: if (xfield.isVolatile())
307: getFrame().killAllLoads();
308: if (doRedundantLoadElimination()) {
309: loadStaticField(xfield, obj);
310: return;
311: }
312:
313: }
314: } catch (ClassNotFoundException e) {
315: lookupFailureCallback.reportMissingClass(e);
316: }
317: handleNormalInstruction(obj);
318: }
319:
320: @Override
321: public void visitPUTSTATIC(PUTSTATIC obj) {
322: if (doForwardSubstitution()) {
323: try {
324: XField xfield = Hierarchy.findXField(obj, getCPG());
325: if (xfield != null) {
326: storeStaticField(xfield, obj, false);
327: return;
328: }
329: } catch (ClassNotFoundException e) {
330: lookupFailureCallback.reportMissingClass(e);
331: }
332: }
333: handleNormalInstruction(obj);
334: }
335:
336: @Override
337: public void visitINVOKESTATIC(INVOKESTATIC obj) {
338: if (REDUNDANT_LOAD_ELIMINATION) {
339: ConstantPoolGen cpg = getCPG();
340: String targetClassName = obj.getClassName(cpg);
341: String methodName = obj.getName(cpg);
342: String methodSig = obj.getSignature(cpg);
343:
344: if ((methodName.equals("forName")
345: && targetClassName.equals("java.lang.Class") || methodName
346: .equals("class$"))
347: && methodSig
348: .equals("(Ljava/lang/String;)Ljava/lang/Class;")) {
349: // Access of a Class object
350: ValueNumberFrame frame = getFrame();
351: try {
352: ValueNumber arg = frame.getTopValue();
353: String className = stringConstantMap.get(arg);
354: if (className != null) {
355: frame.popValue();
356: if (RLE_DEBUG)
357: System.out
358: .println("[found access of class object "
359: + className + "]");
360: frame.pushValue(getClassObjectValue(className));
361: return;
362: }
363: } catch (DataflowAnalysisException e) {
364: throw new InvalidBytecodeException(
365: "stack underflow", methodGen, handle, e);
366: }
367: } else if (Hierarchy.isInnerClassAccess(obj, cpg)) {
368: // Possible access of field via an inner-class access method
369: XField xfield = loadedFieldSet.getField(handle);
370: if (xfield != null) {
371: if (loadedFieldSet.instructionIsLoad(handle)) {
372: // Load via inner-class accessor
373: if (doRedundantLoadElimination()) {
374: if (xfield.isStatic())
375: loadStaticField(xfield, obj);
376: else
377: loadInstanceField(xfield, obj);
378: return;
379: }
380: } else {
381: // Store via inner-class accessor
382: if (doForwardSubstitution()) {
383: // Some inner class access store methods
384: // return the value stored.
385: boolean pushValue = !methodSig
386: .endsWith(")V");
387:
388: if (xfield.isStatic())
389: storeStaticField(xfield, obj, pushValue);
390: else
391: storeInstanceField(xfield, obj,
392: pushValue);
393:
394: return;
395: }
396: }
397: } else {
398: // Don't know what this method invocation is doing.
399: // Kill all loads.
400: killLoadsOfObjectsPassed(obj);
401: getFrame().killAllLoadsOf(null);
402: }
403: } else {
404: // Don't know what this method invocation is doing.
405: // Kill all loads.
406: killLoadsOfObjectsPassed(obj);
407: getFrame().killAllLoadsOf(null);
408: }
409: }
410:
411: handleNormalInstruction(obj);
412: }
413:
414: private void killLoadsOfObjectsPassed(InvokeInstruction ins) {
415: try {
416: int passed = getNumWordsConsumed(ins);
417: ValueNumber[] arguments = new ValueNumber[passed];
418: getFrame().killLoadsWithSimilarName(ins.getClassName(cpg),
419: ins.getMethodName(cpg));
420: getFrame().getTopStackWords(arguments);
421: for (ValueNumber v : arguments)
422: getFrame().killAllLoadsOf(v);
423:
424: } catch (DataflowAnalysisException e) {
425: AnalysisContext.logError(
426: "Error in killLoadsOfObjectsPassed", e);
427: }
428: }
429:
430: @Override
431: public void visitMONITORENTER(MONITORENTER obj) {
432: // Don't know what this sync invocation is doing.
433: // Kill all loads.
434: getFrame().killAllLoads();
435: handleNormalInstruction(obj);
436: }
437:
438: @Override
439: public void visitINVOKESPECIAL(INVOKESPECIAL obj) {
440: // Don't know what this method invocation is doing.
441: // Kill all loads.
442: killLoadsOfObjectsPassed(obj);
443: handleNormalInstruction(obj);
444: }
445:
446: @Override
447: public void visitINVOKEINTERFACE(INVOKEINTERFACE obj) {
448: // Don't know what this method invocation is doing.
449: // Kill all loads.
450: if (obj.getMethodName(cpg).equals("lock"))
451: getFrame().killAllLoads();
452: else
453: killLoadsOfObjectsPassed(obj);
454: handleNormalInstruction(obj);
455: }
456:
457: @Override
458: public void visitINVOKEVIRTUAL(INVOKEVIRTUAL obj) {
459: // Don't know what this method invocation is doing.
460: // Kill all loads.
461: if (obj.getMethodName(cpg).equals("lock"))
462: getFrame().killAllLoads();
463: else
464: killLoadsOfObjectsPassed(obj);
465: handleNormalInstruction(obj);
466: }
467:
468: @Override
469: public void visitLDC(LDC obj) {
470: Object constantValue = obj.getValue(cpg);
471: ValueNumber value;
472: if (constantValue instanceof ConstantClass) {
473: ConstantClass constantClass = (ConstantClass) constantValue;
474: String className = constantClass.getBytes(cpg
475: .getConstantPool());
476: value = getClassObjectValue(className);
477: } else {
478: value = constantValueMap.get(constantValue);
479: if (value == null) {
480: value = factory.createFreshValue();
481: constantValueMap.put(constantValue, value);
482:
483: // Keep track of String constants
484:
485: if (constantValue instanceof String) {
486: stringConstantMap
487: .put(value, (String) constantValue);
488: }
489: }
490: }
491: getFrame().pushValue(value);
492: }
493:
494: @Override
495: public void visitIINC(IINC obj) {
496: if (obj.getIncrement() == 0) {
497: // A no-op.
498: return;
499: }
500:
501: // IINC is a special case because its input and output are not on the stack.
502: // However, we still want to use the value number cache to ensure that
503: // this operation is modeled consistently. (If we do nothing, we miss
504: // the fact that the referenced local is modified.)
505:
506: int local = obj.getIndex();
507:
508: ValueNumber[] input = new ValueNumber[] { getFrame().getValue(
509: local) };
510: ValueNumberCache.Entry entry = new ValueNumberCache.Entry(
511: handle, input);
512: ValueNumber[] output = cache.lookupOutputValues(entry);
513: if (output == null) {
514: output = new ValueNumber[] { factory.createFreshValue() };
515: cache.addOutputValues(entry, output);
516: }
517:
518: getFrame().setValue(local, output[0]);
519: }
520:
521: @Override
522: public void visitCHECKCAST(CHECKCAST obj) {
523: // Do nothing
524: }
525:
526: /* ----------------------------------------------------------------------
527: * Implementation
528: * ---------------------------------------------------------------------- */
529:
530: /**
531: * Pop the input values for the given instruction from the
532: * current frame.
533: */
534: private ValueNumber[] popInputValues(int numWordsConsumed) {
535: ValueNumberFrame frame = getFrame();
536: ValueNumber[] inputValueList = new ValueNumber[numWordsConsumed];
537:
538: // Pop off the input operands.
539: try {
540: frame.getTopStackWords(inputValueList);
541: while (numWordsConsumed-- > 0) {
542: frame.popValue();
543: }
544: } catch (DataflowAnalysisException e) {
545: throw new InvalidBytecodeException(
546: "Error getting input operands", e);
547: }
548:
549: return inputValueList;
550: }
551:
552: /**
553: * Push given output values onto the current frame.
554: */
555: private void pushOutputValues(ValueNumber[] outputValueList) {
556: ValueNumberFrame frame = getFrame();
557: for (ValueNumber aOutputValueList : outputValueList)
558: frame.pushValue(aOutputValueList);
559: }
560:
561: /**
562: * Get output values for current instruction from the ValueNumberCache.
563: */
564: private ValueNumber[] getOutputValues(ValueNumber[] inputValueList,
565: int numWordsProduced) {
566: return getOutputValues(inputValueList, numWordsProduced, 0);
567: }
568:
569: private ValueNumber[] getOutputValues(ValueNumber[] inputValueList,
570: int numWordsProduced, int flags) {
571: ValueNumberCache.Entry entry = new ValueNumberCache.Entry(
572: handle, inputValueList);
573: ValueNumber[] outputValueList = cache.lookupOutputValues(entry);
574: if (outputValueList == null) {
575: outputValueList = new ValueNumber[numWordsProduced];
576: for (int i = 0; i < numWordsProduced; ++i) {
577: ValueNumber freshValue = factory.createFreshValue();
578: freshValue.setFlags(flags);
579: outputValueList[i] = freshValue;
580: }
581: if (false && RLE_DEBUG) {
582: System.out.println("<<cache fill for "
583: + handle.getPosition() + ": "
584: + vlts(inputValueList) + " ==> "
585: + vlts(outputValueList) + ">>");
586: }
587: cache.addOutputValues(entry, outputValueList);
588: } else if (false && RLE_DEBUG) {
589: System.out.println("<<cache hit for "
590: + handle.getPosition() + ": "
591: + vlts(inputValueList) + " ==> "
592: + vlts(outputValueList) + ">>");
593: }
594: return outputValueList;
595: }
596:
597: private static String vlts(ValueNumber[] vl) {
598: StringBuffer buf = new StringBuffer();
599: for (ValueNumber aVl : vl) {
600: if (buf.length() > 0)
601: buf.append(',');
602: buf.append(aVl.getNumber());
603: }
604: return buf.toString();
605: }
606:
607: /**
608: * Load an instance field.
609: *
610: * @param instanceField the field
611: * @param obj the Instruction loading the field
612: */
613: private void loadInstanceField(XField instanceField, Instruction obj) {
614: if (RLE_DEBUG) {
615: System.out.println("[loadInstanceField for field "
616: + instanceField + " in instruction " + handle);
617: }
618:
619: ValueNumberFrame frame = getFrame();
620:
621: try {
622: ValueNumber reference = frame.popValue();
623:
624: AvailableLoad availableLoad = new AvailableLoad(reference,
625: instanceField);
626: if (RLE_DEBUG)
627: System.out.println("[getfield of " + availableLoad
628: + "]");
629: ValueNumber[] loadedValue = frame
630: .getAvailableLoad(availableLoad);
631:
632: if (loadedValue == null) {
633: // Get (or create) the cached result for this instruction
634: ValueNumber[] inputValueList = new ValueNumber[] { reference };
635: loadedValue = getOutputValues(inputValueList,
636: getNumWordsProduced(obj));
637:
638: // Make the load available
639: frame.addAvailableLoad(availableLoad, loadedValue);
640: if (RLE_DEBUG) {
641: System.out.println("[Making load available "
642: + availableLoad + " <- "
643: + vlts(loadedValue) + "]");
644: }
645: } else {
646: // Found an available load!
647: if (RLE_DEBUG) {
648: System.out.println("[Found available load "
649: + availableLoad + " <- "
650: + vlts(loadedValue) + "]");
651: }
652: }
653:
654: pushOutputValues(loadedValue);
655:
656: if (VERIFY_INTEGRITY) {
657: checkConsumedAndProducedValues(obj,
658: new ValueNumber[] { reference }, loadedValue);
659: }
660: } catch (DataflowAnalysisException e) {
661: throw new InvalidBytecodeException(
662: "Error loading from instance field", e);
663: }
664: }
665:
666: /**
667: * Load a static field.
668: *
669: * @param staticField the field
670: * @param obj the Instruction loading the field
671: */
672: private void loadStaticField(XField staticField, Instruction obj) {
673: if (RLE_DEBUG) {
674: System.out.println("[loadStaticField for field "
675: + staticField + " in instruction " + handle);
676: }
677:
678: ValueNumberFrame frame = getFrame();
679:
680: AvailableLoad availableLoad = new AvailableLoad(staticField);
681: ValueNumber[] loadedValue = frame
682: .getAvailableLoad(availableLoad);
683:
684: if (loadedValue == null) {
685: // Make the load available
686: int numWordsProduced = getNumWordsProduced(obj);
687: loadedValue = getOutputValues(EMPTY_INPUT_VALUE_LIST,
688: numWordsProduced);
689:
690: frame.addAvailableLoad(availableLoad, loadedValue);
691:
692: if (RLE_DEBUG)
693: System.out.println("[making load of " + staticField
694: + " available]");
695: } else {
696: if (RLE_DEBUG)
697: System.out.println("[found available load of "
698: + staticField + "]");
699: }
700:
701: if (VERIFY_INTEGRITY) {
702: checkConsumedAndProducedValues(obj, new ValueNumber[0],
703: loadedValue);
704: }
705:
706: pushOutputValues(loadedValue);
707: }
708:
709: /**
710: * Store an instance field.
711: *
712: * @param instanceField the field
713: * @param obj the instruction which stores the field
714: * @param pushStoredValue push the stored value onto the stack
715: * (because we are modeling an inner-class field access method)
716: */
717: private void storeInstanceField(XField instanceField,
718: Instruction obj, boolean pushStoredValue) {
719: if (RLE_DEBUG) {
720: System.out.println("[storeInstanceField for field "
721: + instanceField + " in instruction " + handle);
722: }
723:
724: ValueNumberFrame frame = getFrame();
725:
726: int numWordsConsumed = getNumWordsConsumed(obj);
727: /*
728: System.out.println("Instruction is " + handle);
729: System.out.println("numWordsConsumed="+numWordsConsumed);
730: */
731: ValueNumber[] inputValueList = popInputValues(numWordsConsumed);
732: ValueNumber reference = inputValueList[0];
733: ValueNumber[] storedValue = new ValueNumber[inputValueList.length - 1];
734: System.arraycopy(inputValueList, 1, storedValue, 0,
735: inputValueList.length - 1);
736:
737: if (pushStoredValue)
738: pushOutputValues(storedValue);
739:
740: // Kill all previous loads of the same field,
741: // in case there is aliasing we don't know about
742: frame.killLoadsOfField(instanceField);
743:
744: // Forward substitution
745: frame.addAvailableLoad(new AvailableLoad(reference,
746: instanceField), storedValue);
747:
748: if (RLE_DEBUG)
749: System.out.println("[making store of " + instanceField
750: + " available]");
751:
752: if (VERIFY_INTEGRITY) {
753: /*
754: System.out.println("pushStoredValue="+pushStoredValue);
755: */
756: checkConsumedAndProducedValues(obj, inputValueList,
757: pushStoredValue ? storedValue : new ValueNumber[0]);
758: }
759: }
760:
761: /**
762: * Store a static field.
763: *
764: * @param staticField the static field
765: * @param obj the instruction which stores the field
766: * @param pushStoredValue push the stored value onto the stack
767: * (because we are modeling an inner-class field access method)
768: */
769: private void storeStaticField(XField staticField, Instruction obj,
770: boolean pushStoredValue) {
771: if (RLE_DEBUG) {
772: System.out.println("[storeStaticField for field "
773: + staticField + " in instruction " + handle);
774: }
775:
776: ValueNumberFrame frame = getFrame();
777:
778: AvailableLoad availableLoad = new AvailableLoad(staticField);
779:
780: int numWordsConsumed = getNumWordsConsumed(obj);
781: ValueNumber[] inputValueList = popInputValues(numWordsConsumed);
782:
783: if (pushStoredValue)
784: pushOutputValues(inputValueList);
785:
786: // Kill loads of this field
787: frame.killLoadsOfField(staticField);
788:
789: // Make load available
790: frame.addAvailableLoad(availableLoad, inputValueList);
791:
792: if (RLE_DEBUG)
793: System.out.println("[making store of " + staticField
794: + " available]");
795:
796: if (VERIFY_INTEGRITY) {
797: checkConsumedAndProducedValues(obj, inputValueList,
798: pushStoredValue ? inputValueList
799: : new ValueNumber[0]);
800: }
801: }
802:
803: /**
804: * Get the ValueNumber for given class's Class object.
805: *
806: * @param className the class
807: */
808: public ValueNumber getClassObjectValue(String className) {
809: // TODO: Check to see if we need to do this
810: className = className.replace('/', '.');
811: ValueNumber value = classObjectValueMap.get(className);
812: if (value == null) {
813: value = factory.createFreshValue();
814: value.setFlag(ValueNumber.CONSTANT_CLASS_OBJECT);
815: classObjectValueMap.put(className, value);
816: }
817: return value;
818: }
819:
820: }
821:
822: // vim:ts=4
|