
org.opalj.br.fpcf.properties.Context.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
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.locks.ReentrantReadWriteLock
import org.opalj.br.analyses.DeclaredMethods
import org.opalj.br.analyses.DeclaredMethodsKey
import org.opalj.br.analyses.ProjectInformationKey
import org.opalj.br.analyses.ProjectInformationKeys
import org.opalj.br.analyses.SomeProject
import scala.collection.mutable
/**
* Provides the context in which a method was invoked or an object was allocated.
*
* @author Dominik Helm
*/
trait Context {
val hasContext: Boolean = true
/** The method itself */
def method: DeclaredMethod
/** An identifier for the context */
def id: Int
}
object Context {
def unapply(context: Context): Option[DeclaredMethod] = {
if (context.hasContext) Some(context.method)
else None
}
}
/**
* Represents unknown contexts.
*/
case object NoContext extends Context {
override val hasContext: Boolean = false
override def method: DeclaredMethod = throw new UnsupportedOperationException()
val id: Int = -1
}
/**
* A simple context that provides the bare minumum for context-insensitive analyses.
*/
case class SimpleContext private[properties] (method: DeclaredMethod) extends Context {
override def id: Int = method.id
}
object SimpleContextsKey extends ProjectInformationKey[SimpleContexts, Nothing] {
override def requirements(project: SomeProject): ProjectInformationKeys =
Seq(DeclaredMethodsKey)
override def compute(p: SomeProject): SimpleContexts = {
new SimpleContexts(p.get(DeclaredMethodsKey))
}
}
class SimpleContexts private[properties] (declaredMethods: DeclaredMethods) {
@volatile private var id2Context = new Array[SimpleContext](declaredMethods._UNSAFE_size)
def apply(method: DeclaredMethod): SimpleContext = {
val id = method.id
if (id < id2Context.length) {
var context = id2Context(id)
if (context ne null) context
else {
synchronized {
context = id2Context(id)
if (context ne null) context
else {
val newContext = SimpleContext(method)
id2Context(id) = newContext
newContext
}
}
}
} else {
synchronized {
if (id < id2Context.length) {
val context = id2Context(id)
if (context ne null) context
else {
val newContext = SimpleContext(method)
id2Context(id) = newContext
newContext
}
} else {
val newContext = SimpleContext(method)
val newMap = java.util.Arrays.copyOf(
id2Context, Math.max(declaredMethods._UNSAFE_size, id + 1)
)
newMap(id) = newContext
id2Context = newMap
newContext
}
}
}
}
}
/**
* A context that includes a call string
*/
class CallStringContext private[properties] (
val id: Int,
val method: DeclaredMethod,
val callString: List[(DeclaredMethod, Int)]
) extends Context {
override def toString: String = {
s"CallStringContext($method, $callString)"
}
}
object CallStringContextsKey extends ProjectInformationKey[CallStringContexts, Nothing] {
override def requirements(project: SomeProject): ProjectInformationKeys =
Seq(DeclaredMethodsKey)
override def compute(p: SomeProject): CallStringContexts = {
new CallStringContexts()
}
}
class CallStringContexts {
@volatile private var id2Context = new Array[CallStringContext](32768)
private val context2id = new mutable.HashMap[(DeclaredMethod, List[(DeclaredMethod, Int)]), CallStringContext]()
private val nextId = new AtomicInteger(1)
private val rwLock = new ReentrantReadWriteLock()
def apply(id: Int): CallStringContext = {
id2Context(id)
}
def apply(
method: DeclaredMethod,
callString: List[(DeclaredMethod, Int)]
): CallStringContext = {
val key = (method, callString)
val readLock = rwLock.readLock()
readLock.lock()
try {
val contextO = context2id.get(key)
if (contextO.isDefined) {
return contextO.get;
}
} finally {
readLock.unlock()
}
val writeLock = rwLock.writeLock()
writeLock.lock()
try {
val contextO = context2id.get(key)
if (contextO.isDefined) {
return contextO.get;
}
val context = new CallStringContext(nextId.getAndIncrement(), method, callString)
context2id.put(key, context)
val curMap = id2Context
if (context.id < curMap.length) {
curMap(context.id) = context
} else {
val newMap = java.util.Arrays.copyOf(curMap, curMap.length * 2)
newMap(context.id) = context
id2Context = newMap
}
context
} finally {
writeLock.unlock()
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy