private static Set < Method > findLockedMethods ( ClassContext classContext , SelfCalls selfCalls , Set < CallSite > obviouslyLockedSites ) { JavaClass javaClass = classContext . getJavaClass ( ) ; Method [ ] methodList = javaClass . getMethods ( ) ; CallGraph callGraph = selfCalls . getCallGraph ( ) ; // Initially, assume all methods are locked Set < Method > lockedMethodSet = new HashSet <> ( ) ; // Assume all public methods are unlocked for ( Method method : methodList ) { if ( method . isSynchronized ( ) ) { lockedMethodSet . add ( method ) ; } } // Explore the self-call graph to find nonpublic methods // that can be called from an unlocked context. boolean change ; do { change = false ; for ( Iterator < CallGraphEdge > i = callGraph . edgeIterator ( ) ; i . hasNext ( ) ; ) { CallGraphEdge edge = i . next ( ) ; CallSite callSite = edge . getCallSite ( ) ; if ( obviouslyLockedSites . contains ( callSite ) || lockedMethodSet . contains ( callSite . getMethod ( ) ) ) { // Calling method is locked, so the called method // is also locked. CallGraphNode target = edge . getTarget ( ) ; if ( lockedMethodSet . add ( target . getMethod ( ) ) ) { change = true ; } } } } while ( change ) ; if ( DEBUG ) { System . out . println ( "Apparently locked methods:" ) ; for ( Method method : lockedMethodSet ) { System . out . println ( "\t" + method . getName ( ) ) ; } } // We assume that any methods left in the locked set // are called only from a locked context. return lockedMethodSet ; }
Find methods that appear to always be called from a locked context . We assume that nonpublic methods will only be called from within the class which is not really a valid assumption .