All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opalj.br.fpcf.properties.pointsto.AllocationSitePointsToSet.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
package fpcf
package properties
package pointsto

import org.opalj.collection.immutable.IntTrieSet
import org.opalj.collection.immutable.LongLinkedSet
import org.opalj.collection.immutable.LongTrieSetWithList
import org.opalj.collection.immutable.UIDSet
import org.opalj.fpcf.Entity
import org.opalj.fpcf.FallbackReason
import org.opalj.fpcf.OrderedProperty
import org.opalj.fpcf.PropertyIsNotDerivedByPreviouslyExecutedAnalysis
import org.opalj.fpcf.PropertyKey
import org.opalj.fpcf.PropertyMetaInformation
import org.opalj.fpcf.PropertyStore

/**
 * Represent the set of types that have allocations reachable from the respective entry points.
 *
 * @author Florian Kuebler
 */
sealed trait AllocationSitePointsToSetPropertyMetaInformation extends PropertyMetaInformation {

    final type Self = AllocationSitePointsToSet
}

sealed trait AllocationSitePointsToSet
    extends PointsToSetLike[AllocationSite, LongLinkedSet, AllocationSitePointsToSet]
    with OrderedProperty
    with AllocationSitePointsToSetPropertyMetaInformation {

    final def key: PropertyKey[AllocationSitePointsToSet] = AllocationSitePointsToSet.key

    override def toString: String = s"PointsTo(size=${elements.size})"

    override def checkIsEqualOrBetterThan(e: Entity, other: AllocationSitePointsToSet): Unit = {
        if (!types.subsetOf(other.types)) {
            throw new IllegalArgumentException(s"$e: illegal refinement of property $other to $this")
        }
    }

    protected[this] def orderedTypes: List[ReferenceType]
    override def types: UIDSet[ReferenceType]

    override def included(other: AllocationSitePointsToSet): AllocationSitePointsToSet = {
        included(other, 0)
    }

    override def included(
        other: AllocationSitePointsToSet, seenElements: Int
    ): AllocationSitePointsToSet = {
        var newAllocationSites = elements
        var newTypes = types
        var newOrderedTypes = orderedTypes

        other.forNewestNElements(other.numElements - seenElements) { allocationSite =>
            val tpe = ReferenceType.lookup(allocationSiteLongToTypeId(allocationSite))
            val oldAllocationSites = newAllocationSites
            newAllocationSites += allocationSite
            if (newAllocationSites ne oldAllocationSites) {
                val oldTypes = newTypes
                newTypes += tpe
                if (newTypes ne oldTypes)
                    newOrderedTypes ::= tpe
            }
        }

        if (newAllocationSites eq elements)
            return this;

        AllocationSitePointsToSet(newAllocationSites, newTypes, newOrderedTypes)
    }

    override def included(
        other: AllocationSitePointsToSet, typeFilter: ReferenceType => Boolean
    ): AllocationSitePointsToSet = {
        if (typeFilter eq PointsToSetLike.noFilter)
            return included(other);

        var newTypes = types
        var newOrderedTypes = orderedTypes

        val newAllocationSites = other.elements.foldLeft(elements) { (r, allocationSite) =>
            val tpe = ReferenceType.lookup(allocationSiteLongToTypeId(allocationSite))
            if (typeFilter(tpe)) {
                val newAllocationSites = r + allocationSite
                if (newAllocationSites ne r) {
                    val oldTypes = newTypes
                    newTypes += tpe
                    if (newTypes ne oldTypes)
                        newOrderedTypes ::= tpe
                }
                newAllocationSites
            } else {
                r
            }
        }

        if (newAllocationSites eq elements)
            return this;

        AllocationSitePointsToSet(newAllocationSites, newTypes, newOrderedTypes)
    }

    override def included(
        other:        AllocationSitePointsToSet,
        seenElements: Int,
        typeFilter:   ReferenceType => Boolean
    ): AllocationSitePointsToSet = {
        if (typeFilter eq PointsToSetLike.noFilter)
            return included(other, seenElements);

        var newAllocationSites = elements
        var newTypes = types
        var newOrderedTypes = orderedTypes

        other.forNewestNElements(other.numElements - seenElements) { allocationSite =>
            val tpe = ReferenceType.lookup(allocationSiteLongToTypeId(allocationSite))
            if (typeFilter(tpe)) {
                val oldAllocationSites = newAllocationSites
                newAllocationSites += allocationSite
                if (newAllocationSites ne oldAllocationSites) {
                    val oldTypes = newTypes
                    newTypes += tpe
                    if (newTypes ne oldTypes)
                        newOrderedTypes ::= tpe
                }
            }
        }

        if (newAllocationSites eq elements)
            return this;

        AllocationSitePointsToSet(newAllocationSites, newTypes, newOrderedTypes)
    }

    override def filter(typeFilter: ReferenceType => Boolean): AllocationSitePointsToSet = {
        if (typeFilter eq PointsToSetLike.noFilter)
            return this;

        var newTypes = UIDSet.empty[ReferenceType]
        var newOrderedTypes = List.empty[ReferenceType]

        val newAllocationSites =
            elements.foldLeft(LongTrieSetWithList.empty) { (r, allocationSite) =>
                val tpe = ReferenceType.lookup(allocationSiteLongToTypeId(allocationSite))
                if (typeFilter(tpe)) {
                    val newAllocationSites = r + allocationSite
                    if (newAllocationSites ne r) {
                        val oldTypes = newTypes
                        newTypes += tpe
                        if (newTypes ne oldTypes)
                            newOrderedTypes ::= tpe
                    }
                    newAllocationSites
                } else {
                    r
                }
            }

        if (newAllocationSites.size == elements.size)
            return this;

        AllocationSitePointsToSet(newAllocationSites, newTypes, newOrderedTypes)
    }

    assert {
        var asTypes = IntTrieSet.empty
        elements.foreach { allocationSite =>
            asTypes += allocationSiteLongToTypeId(allocationSite)
        }

        val typeIds = types.foldLeft(IntTrieSet.empty) { (r, t) => r + t.id }
        typeIds == asTypes
    }
    assert(numElements >= numTypes)
}

object AllocationSitePointsToSet extends AllocationSitePointsToSetPropertyMetaInformation {

    def apply(
        allocationSite: AllocationSite, allocatedType: ReferenceType
    ): AllocationSitePointsToSet = {
        new AllocationSitePointsToSet1(allocationSite, allocatedType)
    }

    def apply(
        allocationSiteNew: AllocationSite,
        allocatedTypeNew:  ReferenceType,
        allocationSiteOld: AllocationSite,
        allocatedTypeOld:  ReferenceType
    ): AllocationSitePointsToSet = {
        assert(allocationSiteOld != allocationSiteNew)
        new AllocationSitePointsToSetN(
            LongTrieSetWithList(allocationSiteNew, allocationSiteOld),
            UIDSet(allocatedTypeOld, allocatedTypeNew),
            if (allocatedTypeNew != allocatedTypeOld)
                List(allocatedTypeNew, allocatedTypeOld)
            else
                List(allocatedTypeNew)
        )
    }

    def apply(
        elements: LongLinkedSet, types: UIDSet[ReferenceType], orderedTypes: List[ReferenceType]
    ): AllocationSitePointsToSet = {

        if (elements.isEmpty) {
            NoAllocationSites
        } else if (elements.size == 1) {
            new AllocationSitePointsToSet1(elements.head, orderedTypes.head)
        } else {
            new AllocationSitePointsToSetN(elements, types, orderedTypes)
        }
    }

    final val key: PropertyKey[AllocationSitePointsToSet] = {
        val name = "opalj.AllocationSitePointsToSet"
        PropertyKey.create(
            name,
            (_: PropertyStore, reason: FallbackReason, _: Entity) => reason match {
                case PropertyIsNotDerivedByPreviouslyExecutedAnalysis => NoAllocationSites
                case _ =>
                    throw new IllegalStateException(s"no analysis is scheduled for property: $name")
            }
        )
    }
}

case class AllocationSitePointsToSetN private[pointsto] (
        override val elements:                     LongLinkedSet,
        override val types:                        UIDSet[ReferenceType],
        override protected[this] val orderedTypes: List[ReferenceType]
) extends AllocationSitePointsToSet {

    override def numTypes: Int = types.size
    override def numElements: Int = elements.size

    override def forNewestNTypes[U](n: Int)(f: ReferenceType => U): Unit = {
        orderedTypes.take(n).map(f)
    }

    override def forNewestNElements[U](n: Int)(f: AllocationSite => U): Unit = {
        elements.forFirstN(n)(f)
    }

    // TODO: should the order matter?
    override def equals(obj: Any): Boolean = {
        obj match {
            case that: AllocationSitePointsToSetN =>
                (this eq that) || {
                    that.elements.size == this.elements.size &&
                        that.numTypes == this.numTypes &&
                        // TODO: we should assert that:
                        //  that.elements == this.elements => that.orderedTypes == this.orderedTypes
                        that.elements == this.elements
                }
            case _ => false
        }
    }

    override def hashCode: Int = elements.hashCode()

    override def getNewestElement(): AllocationSite = elements.head
}

object NoAllocationSites extends AllocationSitePointsToSet {

    override def included(other: AllocationSitePointsToSet): AllocationSitePointsToSet = {
        other
    }

    override def included(
        other: AllocationSitePointsToSet, seenElements: Int
    ): AllocationSitePointsToSet = {
        other
    }

    override def included(
        other: AllocationSitePointsToSet, typeFilter: ReferenceType => Boolean
    ): AllocationSitePointsToSet = {
        other.filter(typeFilter)
    }

    override def filter(typeFilter: ReferenceType => Boolean): AllocationSitePointsToSet = {
        this
    }

    override def numTypes: Int = 0

    override def types: UIDSet[ReferenceType] = UIDSet.empty

    override protected[this] def orderedTypes: List[ReferenceType] = List.empty

    override def numElements: Int = 0

    override def elements: LongLinkedSet = LongTrieSetWithList.empty

    override def forNewestNTypes[U](n: Int)(f: ReferenceType => U): Unit = {
        assert(n == 0)
    }

    override def forNewestNElements[U](n: Int)(f: AllocationSite => U): Unit = {
        assert(n == 0)
    }

    override def getNewestElement(): AllocationSite = throw new NoSuchElementException
}

case class AllocationSitePointsToSet1(
        allocationSite: AllocationSite, allocatedType: ReferenceType
) extends AllocationSitePointsToSet {

    override def numTypes: Int = 1

    override def types: UIDSet[ReferenceType] = UIDSet(allocatedType)

    override protected[this] def orderedTypes: List[ReferenceType] = List(allocatedType)

    override def numElements: Int = 1

    override def elements: LongLinkedSet = LongTrieSetWithList(allocationSite)

    override def included(other: AllocationSitePointsToSet): AllocationSitePointsToSet = {
        other match {
            case AllocationSitePointsToSet1(`allocationSite`, `allocatedType`) =>
                this

            case AllocationSitePointsToSet1(otherAllocationSite, otherAllocatedType) =>
                AllocationSitePointsToSet(
                    otherAllocationSite, otherAllocatedType, allocationSite, allocatedType
                )

            case NoAllocationSites =>
                this

            case AllocationSitePointsToSetN(otherAllocationSites, otherTypes, otherOrderedTypes) =>
                val newAllocations = otherAllocationSites.foldLeft(elements) { (l, as) =>
                    if (as != allocationSite) {
                        l + as
                    } else {
                        l
                    }
                }

                val newOrderedTypes = otherOrderedTypes.foldLeft(List(allocatedType)) { (l, at) =>
                    if (at != allocatedType) at :: l else l
                }

                new AllocationSitePointsToSetN(
                    newAllocations,
                    otherTypes + allocatedType,
                    newOrderedTypes
                )
            case _ =>
                throw new IllegalArgumentException(s"unexpected list $other")
        }
    }

    override def included(
        other: AllocationSitePointsToSet, seenElements: Int
    ): AllocationSitePointsToSet = {
        assert(seenElements >= 0 && seenElements <= other.numElements)
        // Note, that we can not assert, that seenElements is between 0 and 1, as this can
        // happen by unordered partial results.
        included(other)
    }

    override def included(
        other: AllocationSitePointsToSet, typeFilter: ReferenceType => Boolean
    ): AllocationSitePointsToSet = {
        if (typeFilter eq PointsToSetLike.noFilter)
            return included(other);

        var newTypes = types
        var newOrderedTypes = orderedTypes

        val newAllocationSites = other.elements.foldLeft(elements) { (r, allocationSite) =>
            val tpe = ReferenceType.lookup(allocationSiteLongToTypeId(allocationSite))
            if (typeFilter(tpe)) {
                val newAllocationSites = r + allocationSite
                if (newAllocationSites ne r) {
                    val oldTypes = newTypes
                    newTypes += tpe
                    if (newTypes ne oldTypes)
                        newOrderedTypes ::= tpe
                }
                newAllocationSites
            } else {
                r
            }
        }

        if (newAllocationSites.size == 1)
            return this;

        AllocationSitePointsToSet(newAllocationSites, newTypes, newOrderedTypes)
    }

    override def included(
        other:        AllocationSitePointsToSet,
        seenElements: Int,
        typeFilter:   ReferenceType => Boolean
    ): AllocationSitePointsToSet = {
        if (typeFilter eq PointsToSetLike.noFilter)
            return included(other, seenElements);

        var newAllocationSites = elements
        var newTypes = types
        var newOrderedTypes = orderedTypes

        other.forNewestNElements(other.numElements - seenElements) { allocationSite =>
            val tpe = ReferenceType.lookup(allocationSiteLongToTypeId(allocationSite))
            if (typeFilter(tpe)) {
                val oldAllocationSites = newAllocationSites
                newAllocationSites += allocationSite
                if (newAllocationSites ne oldAllocationSites) {
                    val oldTypes = newTypes
                    newTypes += tpe
                    if (newTypes ne oldTypes)
                        newOrderedTypes ::= tpe
                }
            }
        }

        if (newAllocationSites.size == 1)
            return this;

        AllocationSitePointsToSet(newAllocationSites, newTypes, newOrderedTypes)
    }

    override def filter(typeFilter: ReferenceType => Boolean): AllocationSitePointsToSet = {
        if ((typeFilter eq PointsToSetLike.noFilter) || typeFilter(allocatedType)) {
            this
        } else {
            NoAllocationSites
        }
    }

    override def forNewestNTypes[U](n: Int)(f: ReferenceType => U): Unit = {
        assert(n == 0 || n == 1)
        if (n == 1)
            f(allocatedType)
    }

    override def forNewestNElements[U](n: Int)(f: AllocationSite => U): Unit = {
        assert(n == 0 || n == 1)
        if (n == 1)
            f(allocationSite)
    }

    override def equals(obj: Any): Boolean = {
        obj match {
            case that: AllocationSitePointsToSet1 =>
                that.allocationSite == this.allocationSite

            case _ => false
        }
    }

    override def hashCode: Int = (allocationSite ^ (allocationSite >> 32)).toInt

    override def getNewestElement(): AllocationSite = allocationSite
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy