diff --git a/README.md b/README.md index d039f02..9bc81fb 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,12 @@ Or, using the moose name of the entity: (FamixJavaCHABuilder entryPoint: (tagcollections31 entityNamed: #'org.apache.commons.collections.map.HashedMap.readObject(ObjectInputStream)')) build. ``` +Some caches are created during the building. If you wish to save space, you can flush them executing: + +```smalltalk + model resetCallGraphCaches +``` + ### More Documentation You can find more documentation here: [documentation](resources/documentation/UserDocumentation.md) diff --git a/resources/documentation/UserDocumentation.md b/resources/documentation/UserDocumentation.md index 4e23d7f..e900353 100644 --- a/resources/documentation/UserDocumentation.md +++ b/resources/documentation/UserDocumentation.md @@ -30,6 +30,13 @@ Examples: (FamixJavaCHABuilder entryPoint: (tagcollections31 entityNamed: #'org.apache.commons.collections.map.HashedMap.readObject(ObjectInputStream)')) build. ``` +The algo is building some caches in the caches of the entities. Those caches are kept after building a call graph in case multiple needs to be built. +If you wish to flush the caches to same some memory once the call graph is built you can execute: + +```smalltalk + model resetCallGraphCaches +``` + ## CallGraph result Once a CallGraph algorithm was applied, one will get an instance of `FamixCallGraph` as a result. diff --git a/src/Famix-CallGraphs/FamixJavaCHABuilder.class.st b/src/Famix-CallGraphs/FamixJavaCHABuilder.class.st index dd33610..10c72f5 100644 --- a/src/Famix-CallGraphs/FamixJavaCHABuilder.class.st +++ b/src/Famix-CallGraphs/FamixJavaCHABuilder.class.st @@ -18,6 +18,16 @@ For example: build ``` +# Caching + +The algo is building some caches in the caches of the entities. Those caches are kept after building a call graph in case multiple needs to be built. + +If you wish to flush the caches to same some memory once the call graph is built you can execute: + +```st + model resetCallGraphCaches +``` + # Implementation detail Originaly the implementation was using an `OrderedCollection` for the worklist and a `Set` for the visited list. But to check if we already have a node created for a method and kind it was taking a lot of time. @@ -92,15 +102,15 @@ FamixJavaCHABuilder >> addErrorTo: aNode signature: signature kind: type excepti { #category : 'building' } FamixJavaCHABuilder >> build [ - self entryPoints do: [ :aNode | worklist at: aNode hash put: aNode ]. [ worklist isEmpty ] whileFalse: [ - | node | - node := worklist anyOne. - worklist removeKey: node hash. - visited at: node hash put: node. - self computeCallGraphOf: node ]. + "Usually we would treat only one node at a time but this is more costly than doing by batch" + | toVisit | + toVisit := worklist values. + worklist removeAll. + toVisit do: [ :node | visited at: node hash put: node ]. "If we do both things in the same loop sone nodes will be missing in `visited` and could lead to errors later." + toVisit do: [ :node | self computeCallGraphOf: node ] ]. "If errors occured, inspect them." graph errorNodes ifNotEmpty: [ :collection | collection inspect ]. diff --git a/src/Famix-CallGraphs/FamixJavaMethod.extension.st b/src/Famix-CallGraphs/FamixJavaMethod.extension.st index 63e4fb7..6b176ef 100644 --- a/src/Famix-CallGraphs/FamixJavaMethod.extension.st +++ b/src/Famix-CallGraphs/FamixJavaMethod.extension.st @@ -1,18 +1,21 @@ Extension { #name : 'FamixJavaMethod' } { #category : '*Famix-CallGraphs' } -FamixJavaMethod >> isEquivalentTo: aMethod [ - "A method is equivalent if their name are the same and parameters are the same. +FamixJavaMethod >> isImplementationOf: aMethod [ + "Return true if I am an implemented method equivalent to the method as parameter. - There is a tricky case with parametrics because in case a type is a type parameter, we need to find its concretization to have the real type in the context." + A method is equivalent if their name are the same and parameters are the same. We already verified the name before getting here. - self name size = aMethod name size ifFalse: [ ^ false ]. "This might seems useless since we compare the name right after, but we pass so much in this method that it has an impact on perfs. It is faster to compare integer than strings" - self name = aMethod name ifFalse: [ ^ false ]. + There is a tricky case with parametrics because in case a type is a type parameter, we need to find its concretization to have the real type in the context." + + self isMethodDefinition ifFalse: [ ^ false ]. "We reject method declarations" + + self == aMethod ifTrue: [ ^ true ]. "fastest case" self parameters size = aMethod parameters size ifFalse: [ ^ false ]. "We need to ensure the type of each parameter is the same after applying the concretizations to the type parameters" - self orederedParameters with: aMethod orederedParameters do: [ :param1 :param2 | + self orderedParameters with: aMethod orderedParameters do: [ :param1 :param2 | | realType1 realType2 | realType1 := param1 typing declaredType. @@ -36,14 +39,3 @@ FamixJavaMethod >> isEquivalentTo: aMethod [ ^ true ] - -{ #category : '*Famix-CallGraphs' } -FamixJavaMethod >> isImplementationOf: aMethod [ - "Return true if I am an implemented method equivalent to the method as parameter." - - self isMethodDefinition ifFalse: [ ^false ]. "Return false if I am a declaration and not an implementation." - - self == aMethod ifTrue: [ ^ true ]. "fastest case" - - ^ self isEquivalentTo: aMethod -] diff --git a/src/Famix-CallGraphs/FamixTMethod.extension.st b/src/Famix-CallGraphs/FamixTMethod.extension.st index c731cc3..29a2ba7 100644 --- a/src/Famix-CallGraphs/FamixTMethod.extension.st +++ b/src/Famix-CallGraphs/FamixTMethod.extension.st @@ -7,7 +7,7 @@ FamixTMethod >> asCallGraphNode [ ] { #category : '*Famix-CallGraphs' } -FamixTMethod >> orederedParameters [ +FamixTMethod >> orderedParameters [ - ^ self parameters sorted: [ :method | method sourceAnchor startPos ] ascending + ^ self cacheAt: #orderedParameters ifAbsentPut: [ self parameters sorted: [ :method | method sourceAnchor startPos ] ascending ] ] diff --git a/src/Famix-CallGraphs/FamixTType.extension.st b/src/Famix-CallGraphs/FamixTType.extension.st index 2024df7..374eedc 100644 --- a/src/Famix-CallGraphs/FamixTType.extension.st +++ b/src/Famix-CallGraphs/FamixTType.extension.st @@ -3,10 +3,20 @@ Extension { #name : 'FamixTType' } { #category : '*Famix-CallGraphs' } FamixTType >> implementesMethodEquivalentTo: aMethod [ - ^ self methods - detect: [ :method | method isImplementationOf: aMethod ] - ifFound: [ :method | true ] - ifNone: [ false ] + ^ (self methodsNamed: aMethod name) anySatisfy: [ :method | method isImplementationOf: aMethod ] +] + +{ #category : '*Famix-CallGraphs' } +FamixTType >> methodsNamed: aName [ + "We use a cache for speed reasons. We will probably get multiple time through here and we need to have a fast way to get the methods of the right name. + + Checking the size before the name for speed reasons." + + | nameSize | + nameSize := aName size. + ^ (self cacheAt: #methodsMap ifAbsentPut: [ IdentityDictionary new ]) + at: aName + ifAbsentPut: [ self methods select: [ :method | method name size = nameSize and: [ method name = aName ] ] ] ] { #category : '*Famix-CallGraphs' } diff --git a/src/Famix-CallGraphs/FamixTWithInheritances.extension.st b/src/Famix-CallGraphs/FamixTWithInheritances.extension.st index 127a01f..0163533 100644 --- a/src/Famix-CallGraphs/FamixTWithInheritances.extension.st +++ b/src/Famix-CallGraphs/FamixTWithInheritances.extension.st @@ -3,11 +3,12 @@ Extension { #name : 'FamixTWithInheritances' } { #category : '*Famix-CallGraphs' } FamixTWithInheritances >> applicableConcretizations [ - | concretizations | - concretizations := Set new. - self withSuperclassesDo: [ :class | - class superInheritances - select: [ :inheritance | inheritance isParametricAssociation ] - thenDo: [ :inheritance | concretizations addAll: inheritance concretizations ] ]. - ^ concretizations + ^ self cacheAt: #applicableConcretizations ifAbsentPut: [ + | concretizations | + concretizations := Set new. + self withSuperclassesDo: [ :class | + class superInheritances + select: [ :inheritance | inheritance isParametricAssociation ] + thenDo: [ :inheritance | concretizations addAll: inheritance concretizations ] ]. + concretizations ] ] diff --git a/src/Famix-CallGraphs/MooseModel.extension.st b/src/Famix-CallGraphs/MooseModel.extension.st new file mode 100644 index 0000000..9902bdd --- /dev/null +++ b/src/Famix-CallGraphs/MooseModel.extension.st @@ -0,0 +1,10 @@ +Extension { #name : 'MooseModel' } + +{ #category : '*Famix-CallGraphs' } +MooseModel >> resetCallGraphCaches [ + "Flushes the caches used by callgraph builders." + + (self allUsing: FamixTType) do: [ :type | type removeCache: #methodsMap ]. + (self allUsing: FamixTMethod) do: [ :type | type removeCache: #orderedParameters ]. + (self allUsing: FamixTWithInheritances) do: [ :type | type removeCache: #applicableConcretizations ] +]