1. A system comprising: a processor; a non-transitory computer-readable storage medium; a bus connecting the processor, and the non-transitory computer-readable medium to each other, wherein the non-transitory computer-readable medium comprises computer usable program code execute-able by said processor, the computer usable program code comprising: a bottleneck identifier configured to identify a data-flow bottleneck at control locations within a first data-flow propagation graph; and a static analyzer configured to: apply a first level of abstraction to model a plurality of run-time objects of a computer software application, thereby producing a set of object abstractions, and perform static data-flow analysis of the computer software application using the set of object abstractions, thereby producing the first data-flow propagation graph; apply a second level of abstraction to model any of the said run-time objects, which are identified as created or returned by factory methods and having in the set of object abstractions a corresponding object abstraction that is traceable to the data-flow bottleneck, based on corresponding allocation sites and call sites that call factory methods encompassing the corresponding allocation sites, where applying the second level of abstraction decomposes the corresponding object abstraction into a plurality of object abstractions, thereby modifying the set of object abstractions, and perform static data-flow analysis of the computer software application using the modified set of object abstractions, wherein the static analyzer is configured to perform static data-flow analysis of the computer software application using the modified set of object abstractions to modify the data-flow propagation graph, and where the static analyzer and bottleneck identifier are configured to iteratively apply the levels of abstraction, perform the static analyses, and identify data-flow bottlenecks within the data-flow propagation graph until a termination condition is met.