// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.vm; import java.util.logging.Logger; import gov.nasa.jpf.JPF; /** * class encapsulating the lock protection status for field access * instructions. Used by on-the-fly partial order reduction in FieldInstruction * to determine if a GET/PUT_FIELD/STATIC insn has to be treated as a * boundary step (terminates a transition). If the field access is always * protected by a lock, only the corresponding sync (INVOKExx or MONITORENTER) * are boundary steps, thus the number of states can be significantly reduced. * * FieldLockInfos are only used if vm.por.sync_detection is set * * NOTE this might involve assumptions that can be violated in subsequent * paths, and might cause potential races to go undetected */ public abstract class FieldLockInfo implements Cloneable { static Logger log = JPF.getLogger("gov.nasa.jpf.vm.FieldLockInfo"); static protected final FieldLockInfo empty = new EmptyFieldLockInfo(); ThreadInfo tiLastCheck; // the thread this FieldLockInfo was last checked for public abstract FieldLockInfo checkProtection (ThreadInfo ti, ElementInfo ei, FieldInfo fi); public abstract boolean isProtected (); public abstract FieldLockInfo cleanUp (Heap heap); protected abstract int[] getCandidateLockSet(); public boolean isFinal() { return isProtected(); } public boolean needsPindown (ElementInfo ei) { return false; } /* * we need this for faster instantiation. Make sure it gets overridden in * case there is a need for per-instance parameterization */ public Object clone () throws CloneNotSupportedException { return super.clone(); } void lockAssumptionFailed (ThreadInfo ti, ElementInfo ei, FieldInfo fi) { String src = ti.getTopFrameMethodInfo().getClassInfo().getSourceFileName(); int line = ti.getLine(); StringBuilder sb = new StringBuilder( "unprotected field access of: "); sb.append(ei); sb.append('.'); sb.append(fi.getName()); sb.append( " in thread: "); sb.append( ti.getName()); sb.append( " ("); sb.append( src); sb.append(':'); sb.append(line); sb.append(")\n[SEVERE].. last lock candidates: "); appendLockSet(sb, getCandidateLockSet()); if (tiLastCheck != null) { sb.append(" set by "); sb.append(tiLastCheck); } sb.append( "\n[SEVERE].. current locks: "); appendLockSet(sb, ti.getLockedObjectReferences()); sb.append("\n[SEVERE].. if this is not a race, re-run with 'vm.por.sync_detection=false' or exclude field from checks"); log.severe(sb.toString()); } void appendLockSet (StringBuilder sb, int[] lockSet) { Heap heap = VM.getVM().getHeap(); if ((lockSet == null) || (lockSet.length == 0)) { sb.append( "{}"); } else { sb.append('{'); for (int i=0; i<lockSet.length;) { int ref = lockSet[i]; if (ref != MJIEnv.NULL) { ElementInfo ei = heap.get(ref); if (ei != null) { sb.append(ei); } else { sb.append("?@"); sb.append(lockSet[i]); } } i++; if (i<lockSet.length) sb.append(','); } sb.append('}'); } } } /** * FieldLockSet implementation for fields that are terminally considered to be unprotected */ class EmptyFieldLockInfo extends FieldLockInfo { public FieldLockInfo checkProtection (ThreadInfo ti, ElementInfo ei, FieldInfo fi) { return this; } public FieldLockInfo cleanUp (Heap heap) { return this; } public boolean isProtected () { return false; } public boolean isFinal() { return true; } protected int[] getCandidateLockSet() { return new int[0]; } public String toString() { return "EmptyFieldLockInfo"; } }