package ai
Implementation of an abstract interpretation (ai) framework – also referred to as OPAL.
Please note that OPAL/the abstract interpreter just refers to the classes and traits
defined in this package (ai
). The classes and traits defined in the sub-packages
(in particular in domain
) are not considered to be part of the core of OPAL/the
abstract interpreter.
- Source
- package.scala
- Note
This framework assumes that the analyzed bytecode is valid; i.e., the JVM's bytecode verifier would be able to verify the code. Furthermore, load-time errors (e.g.,
LinkageErrors
) are – by default – completely ignored to facilitate the analysis of parts of a project. In general, if the presented bytecode is not valid, the result is undefined (i.e., OPAL may report meaningless results, crash or run indefinitely).- See also
org.opalj.ai.AI - Implements the abstract interpreter that processes a methods code and uses an analysis-specific domain to perform the abstract computations.
org.opalj.ai.Domain - The core interface between the abstract interpretation framework and the abstract domain that is responsible for performing the abstract computations.
- Alphabetic
- By Inheritance
- ai
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Package Members
- package common
- package domain
This package contains definitions of common domains that can be used for the implementation of analyses.
This package contains definitions of common domains that can be used for the implementation of analyses.
Types of Domains
In general, we distinguish two types of domains. First, domains that define a general interface (on top of the one defined by Domain), but do not directly provide an implementation. Hence, whenever you develop a new
Domain
you should consider implementing/using these domains to maximize reusability. Second,Domain
s that implement a specific interface (trait). In this case, we further distinguish between domains that provide a default implementation (per interface only one of theseDomain
s can be used to create a finalDomain
) and those that can be stacked and basically refine the overall functionality.Examples
- Domains That Define a General Interface
- Origin defines two types which domains that provide information abou the origin of a value should consider to implement.
- TheProject defines a standard mechanism how a domain can access the current project.
- ...
- Domains That Provide a Default Implementation
- Origin defines the functionality to return a value's origin if the value supports that.
- org.opalj.ai.domain.TheProject default implementation of the class hierarchy related methods using the project's class hierarchy.
- org.opalj.ai.domain.DefaultHandlingOfMethodResults basically implements a Domain's methods related to return instructions an uncaught exceptions.
- ...
- Domains That Implement Stackable Functionality
- org.opalj.ai.domain.RecordThrownExceptions records information about all uncaught exceptions
by intercepting a
Domain
's respective methods. However, it does provide a default implementation. Hence, a typical pattern is:
- org.opalj.ai.domain.RecordThrownExceptions records information about all uncaught exceptions
by intercepting a
class MyDomain extends Domain with ... with DefaultHandlingOfMethodResults with RecordThrownExceptions
Thread Safety
Unless explicitly documented, a domain is never thread-safe. The general programming model is to use one
Domain
object per code block/method and therefore, thread-safety is not required forDomain
s that are used for the evaluation of methods. However domains that are used to adapt/transfer values should be thread safe (see org.opalj.ai.domain.ValuesCoordinatingDomain for further details). - Domains That Define a General Interface
- package fpcf
- package project
- package util
Common utility functionality.
Type Members
- abstract class AI[D <: Domain] extends AnyRef
A highly-configurable framework for the (abstract) interpretation of Java bytecode.
A highly-configurable framework for the (abstract) interpretation of Java bytecode. The framework is built upon OPAL's standard representation (org.opalj.br) of Java bytecode.
This framework basically traverses all instructions of a method in depth-first order until an instruction is hit where multiple control flows potentially join. This instruction is then only analyzed if no further instruction can be evaluated where no paths join (org.opalj.br.Code.cfPCs). Each instruction is then evaluated using a given (abstract) org.opalj.ai.Domain. The evaluation of a subroutine (Java code < 1.5) - in case of an unhandled exception – is always first completed before the evaluation of the parent (sub)routine is continued.
Interacting with OPAL's Abstract Interpreter
The primary means how to make use of this framework is to perform an abstract interpretation of a method using a customized
Domain
. That customized domain can be used, e.g., to build a call graph or to do other intra-/interprocedural analyses while the code is analyzed. Additionally, it is possible to analyze the result of an abstract interpretation. The latter is particularly facilitated by the 3-address code.Thread Safety
This class is thread-safe. However, to make it possible to use one abstract interpreter instance for the concurrent abstract interpretation of independent methods, the AITracer (if any) has to be thread-safe too.
Hence, it is possible to use a single instance to analyze multiple methods in parallel. However, if you want to be able to selectively abort the abstract interpretation of some methods or want to selectively trace the interpretation of some methods, then you should use multiple abstract interpreter instances. Creating new instances is usually extremely cheap as this class does not have any significant associated state.
Subclasses are not required to be thread-safe and may have more complex state.
- Note
OPAL does not make assumptions about the number of domains that are used. However, if a single domain object is used by multiple instances of this class and the abstract interpretations are executed concurrently, then the domain has to be thread-safe. The latter is trivially the case when the domain object itself does not have any state; however, most domain objects have some state.
,Useless Joins Avoidance
OPAL tries to minimize unnecessary joins by using the results of a naive live variables analysis (limited to the registers only!). This analysis helps to prevent unnecessary joins and also helps to reduce the overall number of processing steps. E.g., in the following case the swallowed exceptions that may occur whenever transformIt is called, would lead to an unnecessary join though the exception is not required!
if (enc != null) { try { return transformIt(transformIt(enc)); } catch (RuntimeException re) {} } return "";
This analysis leads to an overall reduction in the number of evaluated instruction of about 4,5%. Additionally, it also reduces the effort spent on "expensive" joins which leads to an overall(!) improvement for the l1.DefaultDomain of ~8,5%. TODO ==Dead Variables Elimination based on Definitive Paths== (STILL IN DESIGN!!!!)
Idea
Given an instruction i which may result in a fork of the control-flow (e.g., a conditional branch or an invoke instruction that may throw a catched exception). If the (first) evaluation of i definitively rules out several possible paths and - on all paths that are taken - some values are dead, but live on some of the other paths, then the respectively current values will never be propagated to the remaining paths, even if the remaining paths are eventually taken! This helps in variety of cases such as, e.g.,
var s : Object = null for{/* it can statically be determined that this path is taken at least once!*/} { s = "something else" } doIt(s); // here, "s" is guaranteed not to reference the orignal value "null"!
Implementation
When we have a fork, check if all paths...
Customizing the Abstract Interpretation Framework
Customization of the abstract interpreter is done by creating new subclasses that override the relevant methods (in particular: AI#isInterrupted and AI#tracer).
- sealed abstract class AIAborted extends AIResult
Encapsulates the intermediate result of an aborted abstract interpretation of a method.
- sealed abstract class AICompleted extends AIResult
Encapsulates the final result of the successful abstract interpretation of a method.
- class AIException extends RuntimeException
A general, non-recoverable exception occurred during the abstract interpretation of a method.
- sealed abstract class AIResult extends AnyRef
Encapsulates the result of the abstract interpretation of a method.
Encapsulates the result of the abstract interpretation of a method. If the abstract interpretation was cancelled, the result encapsulates the current state of the evaluation which can be used to continue the abstract interpretation later on if necessary/desired.
- trait AITracer extends AnyRef
Defines the interface between the abstract interpreter and a module for tracing and debugging the interpreter's progress.
Defines the interface between the abstract interpreter and a module for tracing and debugging the interpreter's progress. In general, a tracer is first registered with an abstract interpreter. After that, when a method is analyzed, the AI calls the tracer's methods at the respective points in time.
A tracer is registered with an abstract interpreter by creating a new subclass of AI and overriding the method AI.tracer.
- Note
All data structures passed to the tracer are the original data structures used by the abstract interpreter. Hence, if a value is mutated (e.g., for debugging purposes) it has to be guaranteed that the state remains meaningful. Hence, using the AITracer it is possible to develop a debugger for OPAL and to enable the user to perform certain mutations.
- final type ALocalsArray[T >: Null <: DomainValue] = Array[Locals[T]]
- final type AnOperandsArray[T >: Null <: DomainValue] = Array[Operands[T]]
- class BaseAI extends AI[Domain]
A base abstract interpreter that can be used with any domain that has no special requirements on the abstract interpreter.
A base abstract interpreter that can be used with any domain that has no special requirements on the abstract interpreter. The base interpreter can be interrupted by calling the
interrupt
method of the AI's thread.- See also
BoundedInterruptableAI for an abstract interpreter that can easily be interrupted and which also interrupts itself if a certain threshold is exceeded.
- class BoundedInterruptableAI[D <: Domain] extends InstructionCountBoundedAI[D]
An abstract interpreter that interrupts itself after the evaluation of the given number of instructions or if the callback function
doInterrupt
returnsfalse
or if the maximum allowed time is exceeded. - sealed abstract class Computation[+V, +E] extends AnyRef
Encapsulates the result of a computation in a domain.
Encapsulates the result of a computation in a domain. In general, the result is either some value
V
or some exception(s)E
. In some cases, however, when the domain cannot precisely determine the result, it may be both: some exceptional value(s) and a value.In the latter case the abstract interpreter will generally follow all possible paths. A computation that declares to return a result (i.e., the type
V
is notNothing
) must not return a result and/or throw an exception if the computation did not finish.Querying Computations
Before accessing a computation's result (result or exceptions) it first has to be checked whether the computation returned normally (returnsNormally) or threw an exception (throwsException). Only if
returnsNormally
returnstrue
the methodsresult
andhasResult
are defined.- V
The result of the computation. Typically a
DomainValue
; if the computation is executed for its side effect (e.g., as in case of amonitorenter
ormonitorexit
instruction) the type ofV
maybeNothing
.- E
The exception(s) that maybe thrown by the computation. Typically, a
DomainValue
which represents a reference value with typejava.lang.Throwable
or a subtype thereof. If multiple exceptions may be thrown it may also be a set orIterable
ofDomainValue
s (e.g.,ExceptionValues
).
- Note
The precise requirements on the result of a computation are determined by the Domain object's methods that perform computations.
- final case class ComputationWithSideEffectOrException[+E](exceptions: E) extends Computation[Nothing, E] with Product with Serializable
Encapsulates the result of a computation that returned normally (but which did not return some value) or that threw an exception/multiple exceptions.
- final case class ComputedValue[+V](result: V) extends Computation[V, Nothing] with Product with Serializable
Encapsulates the result of a computation that returned normally and that did not throw an exception.
- final case class ComputedValueOrException[+V, +E](result: V, exceptions: E) extends Computation[V, E] with Product with Serializable
Encapsulates the result of a computation that either returned normally or threw an exception.
- trait Configuration extends AnyRef
Centralizes all configuration options related to how a domain should handle situations in which the information about a value is (often) not completely available and which could lead to some kind of exception.
Centralizes all configuration options related to how a domain should handle situations in which the information about a value is (often) not completely available and which could lead to some kind of exception.
Basically all domains that perform some kind of abstraction should mix in this trait and query the respective method to decide if a respective exception should be thrown if it is possible that an exception may be thrown.
Usage
If you need to adapt a setting just override the respective method in your domain.
In general, the org.opalj.ai.domain.ThrowAllPotentialExceptionsConfiguration should be used as a foundation as it generates all exceptions that may be thrown; however, configuring the behavior of method calls may be worth while.
- trait CoreDomainFunctionality extends ValuesDomain with SubroutinesDomain
Defines the core functionality that is shared across all Domains that implement the operations related to different kinds of values and instructions.
Defines the core functionality that is shared across all Domains that implement the operations related to different kinds of values and instructions. It primarily defines the abstraction for DomainValues.
- Note
This trait defines concrete methods that facilitate unit testing of partial domains that build on top of this
CoreDomain
such as the IntegerValuesDomain.- See also
Domain For an explanation of the underlying concepts and ideas.
- trait CorrelationalDomain extends Domain with CorrelationalDomainSupport
A Domain that supports the tracking of correlations between values.
- trait CorrelationalDomainSupport extends JoinStabilization with IdentityBasedCorrelationChangeDetection
Provides basic support for tracking the correlation between domain values stored in different registers/in different stack slots.
- class CountingAI[D <: Domain] extends InterruptableAI[D]
An abstract interpreter that counts the number of instruction evaluations that are performed.
An abstract interpreter that counts the number of instruction evaluations that are performed. This is particularly helpful to determine the effect of optimizations or the choice of the domain.
Thread Safety
This class is thread-safe. I.e., one instance can be used to run multiple abstract interpretations in parallel.
- trait CustomInitialization extends AnyRef
Mixin this trait if a domain needs to perform some custom initialization.
Mixin this trait if a domain needs to perform some custom initialization.
Usage
It is sufficient to mixin this trait in a Domain that needs custom initialization. The abstract interpreter will then perform the initialization.
This information is set immediately before the abstract interpretation is started/continued. I.e., this makes it potentially possible to reuse a Domain object for the interpretation of multiple methods.
- trait Domain extends CoreDomainFunctionality with IntegerValuesDomain with LongValuesDomain with FloatValuesDomain with DoubleValuesDomain with ReferenceValuesDomain with FieldAccessesDomain with MethodCallsDomain with MonitorInstructionsDomain with ReturnInstructionsDomain with DynamicLoadsDomain with PrimitiveValuesConversionsDomain with TypedValuesFactory with Configuration
A domain is the fundamental abstraction mechanism in OPAL that enables the customization of the abstract interpretation framework towards the needs of a specific analysis.
A domain is the fundamental abstraction mechanism in OPAL that enables the customization of the abstract interpretation framework towards the needs of a specific analysis.
A domain encodes the semantics of computations (e.g., the addition of two values) with respect to the domain's values (e.g., the representation of integer values). Customizing a domain is the fundamental mechanism of adapting the AI framework to one's needs.
This trait defines the interface between the abstract interpretation framework and some (user defined) domain. I.e., this interface defines all methods that are needed by OPAL to perform an abstract interpretation.
Control Flow
OPAL controls the process of evaluating the code of a method, but requires a domain to perform the actual computations of an instruction's result. E.g., to calculate the result of adding two integer values, or to perform the comparison of two object instances, or to get the result of converting a
long
value to anint
value, the framework always consults the domain.Handling of instructions that manipulate the stack (e.g.
dup
), that move values between the stack and the locals (e.g.,Xload_Y
) or that determine the control flow is, however, completely embedded into OPAL-AI.OPAL uses the following methods to inform a domain about the progress of the abstract interpretation:
- org.opalj.ai.CoreDomainFunctionality.afterEvaluation
- org.opalj.ai.CoreDomainFunctionality.flow
- org.opalj.ai.CoreDomainFunctionality.evaluationCompleted
- org.opalj.ai.CoreDomainFunctionality.abstractInterpretationEnded
A domain that implements (
overrides
) one of these methods should always also delegate the call to its superclass to make sure that every domain interested in these events is informed.
Implementing Abstract Domains
While it is perfectly possible to implement a new domain by inheriting from this trait, it is recommended to first study the already implemented domains and to use them as a foundation. To facilitate the usage of OPAL several classes/traits that implement parts of this
Domain
trait are pre-defined and can be flexibly combined (mixed together) when needed.When you extend this trait or implement parts of it you should keep as many methods/ fields private to facilitate mix-in composition of multiple traits.
Thread Safety
When every analyzed method is associated with a unique
Domain
instance and – given that OPAL only uses one thread to analyze a given method at a time – no special care has to be taken. However, if a domain needs to consult another domain which is, e.g, associated with a project as a whole (e.g., to create a central store of values), it is then the responsibility of the domain to make sure that coordination with the world is thread safe.- Note
OPAL assumes that – at least conceptually – every method/code block is associated with its own instance of a domain object.
- case class DomainException(message: String) extends AIException with Product with Serializable
An exception related to a computation in a specific domain occurred.
An exception related to a computation in a specific domain occurred. This exception is intended to be used if the exception occurred inside the
Domain
. - trait DoubleValuesDomain extends DoubleValuesFactory
Defines the public interface between the abstract interpreter and the domain that implements the functionality related to the handling of
double
values. - trait DoubleValuesFactory extends ValuesDomain
Defines the primary factory methods for Double values.
- trait DynamicLoadsDomain extends AnyRef
Interface related to the handling of dynamic ldc/ldc_w/ldc2_w instructions.
- trait ExceptionsFactory extends ValuesDomain
Defines factory methods for those exceptions that are (also) created by the JVM when the evaluation of a specific bytecode instruction fails (e.g.,
idiv
,checkcast
,monitorexit
,return
...). - final type ExceptionsRaisedByCalledMethod = ai.ExceptionsRaisedByCalledMethods.Value
- trait FieldAccessesDomain extends AnyRef
Interface related to the handling of field access instructions.
- trait FloatValuesDomain extends FloatValuesFactory
Defines the public interface between the abstract interpreter and the domain that implements the functionality related to the handling of
float
values. - trait FloatValuesFactory extends ValuesDomain
Defines factory methods to create concrete representations of constant float values.
- trait GlobalLogContextProvider extends LogContextProvider
- trait IdentityBasedCorrelationChangeDetection extends CoreDomainFunctionality
Identifies situations (based on a reference comparison of the domain values) in which the memory layout changes such that a correlation between two values, which existed before a join was performed, no longer exists.
Identifies situations (based on a reference comparison of the domain values) in which the memory layout changes such that a correlation between two values, which existed before a join was performed, no longer exists. In this case the UpdateType is lifted from MetaInformationUpdate to StructuralUpdateType. For example, imagine that the old stack layout (before the join was executed) is as follows:
AnIntegerValue[#1]
<-AnIntegerValue[#1]
<-IntegerRange(lb=0,ub=10)[#2]
<- ...and that the stack after the join is:
AnIntegerValue[#2]
<-AnIntegerValue[#3]
<-IntegerRange(lb=0,ub=10)[#2]
<- ...Hence, the two top-most stack values are now different values and – if the result of an analysis/domain is influenced by correlation information – the continuation of the abstract interpretation is enforced.
Concrete Example
static void cfDependentValues(int i) { Object b = null; Object c = null; int j = i; // <--- j is just an alias for i while (j < 2) { Object a = maybeNull(); // returns "null" or a new instance of Object if (i == 1) b = a; // <--- b is just an alias for a else c = a; // <--- c is just an alias for a i++; j = i; } // b and c are never referring to the same object; hence a constraint related to // c does not affect b and vice versa if (c == null) { // this just constraints "c" (not "b") doIt(b); // we know nothing special about b doIt(c); // c is null } else if (b != null) { doIt(b); // b is non-null doIt(c); // we know nothing special about c } }
This trait requires that updates to a value that do not influence the represented value as such, but which may influence its correlation information, have to create a MetaInformationUpdate. Here, correlation means:
- two reference values that refer to the same object are considered aliases
- two local variables that are guaranteed to be identical in all cases, and, hence are subject to the same constraints are also correlated.
- Note
Mixing in this trait is strictly necessary when aliases are traced using a DomainValue's reference.
- class InstructionCountBoundedAI[D <: Domain] extends AI[D]
An abstract interpreter that interrupts itself after the evaluation of the given number of instructions.
An abstract interpreter that interrupts itself after the evaluation of the given number of instructions.
Thread Safety
This class is thread-safe. I.e., one instance of the InstructionCountBoundedAI can be used to run multiple abstract interpretations in parallel and to ensure that they terminate (as a whole) if the threshold is exceeded.
- trait IntegerRangeValuesFactory extends IntegerValuesFactory
Defines a factory method to create
IntegerRange
values. - trait IntegerValuesDomain extends IntegerValuesFactory
Defines the public interface between the abstract interpreter and the domain that implements the functionality related to the handling of
int
eger values. - trait IntegerValuesFactory extends ValuesDomain
Defines the primary factory methods to create
Integer
values. - sealed trait InterpretationFailedException extends AnyRef
Exception that is thrown by the abstract interpreter when the abstract interpretation of a method's implementation failed.
Exception that is thrown by the abstract interpreter when the abstract interpretation of a method's implementation failed.
To create an instance use the companion object InterpretationFailedException$.
- class InterruptableAI[D <: Domain] extends AI[D]
An abstract interpreter that can be interrupted by calling the AI's
interrupt
method or by calling the executing thread's interrupt method. - trait JoinStabilization extends CoreDomainFunctionality
Ensures that the same
DomainValue
is used whenever we merge the same pair of domain values.Ensures that the same
DomainValue
is used whenever we merge the same pair of domain values. This ensures that the relation between the values remains the same.For example, given the following two stacks:
AnIntegerValue[#1]
<-AnIntegerValue[#1]
<-IntRange(lb=0,ub=10)[#2]
<- ...AnIntegerValue[#3]
<-AnIntegerValue[#3]
<-IntRange(lb=0,ub=10)[#2]
<- ...
The result will be (assuming that the result of joining
AnIntegerValue[#1]
withAnIntegerValue[#3]
creates a new value, e.g.,AnIntegerValue[#4]
):AnIntegerValue[#4]
<-AnIntegerValue[#4]
<-IntRange(lb=0,ub=10)[#2]
<- ...
Without this trait each pair of values is joined again. In this case the result would be:
AnIntegerValue[#4]
<-AnIntegerValue[#5]
<-IntRange(lb=0,ub=10)[#2]
<- ...
Using join stabilization is necessary if constraints are propagated or (makes sense) if the merge of domain values is expensive.
- Note
Join stabilization is always done for all domain values once this trait is mixed in.
- final type Locals[T >: Null <: DomainValue] = collection.mutable.Locals[T]
- trait LogContextProvider extends AnyRef
Provides log context information.
- trait LongValuesDomain extends LongValuesFactory
Defines the public interface between the abstract interpreter and the domain that implements the functionality related to the handling of long values.
- trait LongValuesFactory extends ValuesDomain
Defines the primary factory methods to create
long
values. - final case class MetaInformationUpdate[V](value: V) extends SomeUpdate[V] with Product with Serializable
Characterizes an update that did not affect the abstract state but instead just updated some meta information.
Characterizes an update that did not affect the abstract state but instead just updated some meta information.
In general, the abstract interpretation framework handles
NoUpdate
s andMetaInformationUpdate
s in the same way.Example
If two values are merged that are seen on two different paths, but which represent the same abstract value, we may want to update the meta-information about the origin of the current value, but this information may not be part of the abstract state and hence, is not relevant for the abstract interpreter. In this case the interpreter will not reschedule subsequent instructions. However, whether or not the information about the origin of a value is considered to be part of the abstract state is a decision of the domain.
- sealed trait MetaInformationUpdateType extends UpdateType
- trait MethodCallsDomain extends AnyRef
Defines all methods related to the invocation of other methods.
- trait MonitorInstructionsDomain extends AnyRef
Domain that defines all methods related to monitor instructions.
- class MultiTracer extends AITracer
A tracer that forwards every call to all registered tracers.
- final type Operands[T >: Null <: DomainValue] = List[T]
- final type PCs = IntTrieSet
- trait PrimitiveValuesConversionsDomain extends AnyRef
Defines the methods that performs type conversions between primitive values with different computational types.
- type PrimitiveValuesFactory = IntegerValuesFactory with LongValuesFactory with FloatValuesFactory with DoubleValuesFactory
- trait ReferenceValuesDomain extends ReferenceValuesFactory
Domain that defines all methods that perform computations related to
RefernceValues
. - trait ReferenceValuesFactory extends ExceptionsFactory
Definition of factory methods to create
ReferenceValues
. - trait ReturnInstructionsDomain extends AnyRef
Defines the methods that lead to a return from a method.
Defines the methods that lead to a return from a method. In general, a return instruction can throw an
IllegalMonitorStateException
. If, e.g., the method is synchronized and the method body contains aMonitorexit
instruction, but noMonitorenter
instruction. - type SomeAI[D <: Domain] = AI[_ >: D]
Type alias that can be used if the AI can use all kinds of domains.
Type alias that can be used if the AI can use all kinds of domains.
- Note
This type alias serves comprehension purposes only.
- sealed abstract class SomeUpdate[V] extends Update[V]
Identifies updates where something was updated without further qualifying the update.
Identifies updates where something was updated without further qualifying the update.
Usage
This class (and its companion object) are primarily used for pattern matching purposes.
- final case class StructuralUpdate[V](value: V) extends SomeUpdate[V] with Product with Serializable
Characterizes updates where the abstract state was updated such that it is required to continue the abstract interpretation.
- trait SubroutinesDomain extends AnyRef
Enables specialized processing of subroutine calls by domains; this is generally only relevant for those domains that record the control-flow graph.
- type TargetDomain = ValuesDomain with ValuesFactory
- trait TheAI[D <: Domain] extends AnyRef
Makes the instance of the abstract interpreter that performs the abstract interpretation available to the domain.
Makes the instance of the abstract interpreter that performs the abstract interpretation available to the domain.
Usage
It is sufficient to mixin this trait in a Domain that needs to access the abstract interpreter. The abstract interpreter will then perform the initialization.
The concrete instance of AI that performs the abstract interpretation is set immediately before the abstract interpretation is started/continued.
- trait TheCodeStructure extends AnyRef
Mixin this trait if the domain needs information about the structure of the code.
Mixin this trait if the domain needs information about the structure of the code.
Usage
It is sufficient to mixin this trait in a Domain that needs to get access to the code array. The abstract interpreter will then perform the initialization.
This information is set immediately before the abstract interpretation is started/continued.
- final type TheLocalsArray[T >: Null <: ai.TheLocalsArray.T.d.type.Locals forSome {val d: ValuesDomain}] = Array[T]
- trait TheMemoryLayout extends AnyRef
Mixin this trait if a domain needs access to the operands (Domain#OperandsArray) and/or locals (Domain#LocalsArray).
Mixin this trait if a domain needs access to the operands (Domain#OperandsArray) and/or locals (Domain#LocalsArray).
Usage
It is sufficient to mixin this trait in a Domain that needs to get access to the memory structures. The abstract interpreter will then perform the initialization.
This information is set immediately before the abstract interpretation is started/continued.
- final type TheOperandsArray[T >: Null <: ai.TheOperandsArray.T.d.type.Operands forSome {val d: ValuesDomain}] = Array[T]
- final case class ThrowsException[+E](exceptions: E) extends Computation[Nothing, E] with Product with Serializable
Encapsulates the result of a computation that threw an exception.
- class TimeBoundedAI[D <: Domain] extends AI[D]
An abstract interpreter that interrupts itself after some configurable (maxEffort) time has passed.
- trait TypedValuesFactory extends AnyRef
Defines additional, generally useful factory methods to create
DomainValue
s. - sealed abstract class Update[+V] extends AnyRef
Encapsulates an updated value and qualifies the type of the update.
Encapsulates an updated value and qualifies the type of the update.
In general OPAL distinguishes between updates to a value that are relevant w.r.t. the abstract interpretation and those updates that just update some meta-information and which do not affect the abstract interpretation and – in particular – do not force the framework to continue the abstract interpretation.
- sealed abstract class UpdateType extends AnyRef
Specifies the type of an update.
Specifies the type of an update. The type hierarchies of Update and UpdateType are aligned and it is possible to conveniently switch between them. Contrary to an
Update
object anUpdateType
object never has any payload, it just characterizes an update. However, by passing a value to anUpdateType
theUpdateType
is turned into a corresponding org.opalj.ai.Update object.Example
val updateType : UpdateType = ... val update : Update = updateType(<someValue>)
- type ValueOrigin = Int
- final type ValueOrigins = IntTrieSet
A
ValueOrigin
identifies the origin of a value within a method.A
ValueOrigin
identifies the origin of a value within a method. In most cases the origin is equal to the program counter of the instruction that created the value. However, several negative values do have special semantics which are explained in the following.Parameter Identification
In general, parameters are identified by using negative origin information as described below. Given that
- the maximum size of the method parameters array is 255 and
- that the first slot is required for the
this
reference in case of instance methods and - that
long
anddouble
values require two slots the smallest number used to encode that the value is an actual parameter is-256
.
AI Framework
In case of the ai framework, values passed to a method get indexes as follows:
-1-(isStatic ? 0 : 1)-(the index of the parameter adjusted by the computational type of the previous parameters)
.For example, in case of an instance method with the signature:
public void (double d/*parameter index:0*/, Object o/*parameter index:1*/){...}
- The value
-1
is used to identify the implicitthis
reference. - The value
-2
identifies the value of the parameterd
. - The value
-4
identifies the parametero
. (The parameterd
is a value of computational-type category 2 and needs two stack/operands values.)
Three-address Code
In case of the three address code the parameter origins are normalized (see org.opalj.tac.TACAI for further details).
Subroutines JSR/RET
Some special values are used when methods have subroutines: (SUBROUTINE_START, SUBROUTINE_END, SUBROUTINE). These methods, never show up at the def-use or cfg level, but will show up in the evaluation trace.
Implicit JVM Constants
The value
-333
is used to encode that the value is an implicit constant (ConstantValueOrigin). This value is used for the implicit value ofIF_XXX
instructions to facilitates a generalized handling of ifs.Values in the range [ SpecialValuesOriginOffset (
-800,000,000
) , MethodExternalExceptionsOriginOffset (-1,000,000
) ] are used to identify exceptions that are created outside of the method; i.e., by an instruction which does not belong to the method. Exceptions in the range (MethodExternalExceptionsOriginOffset (-1,000,000
), ImmediateVMExceptionsOriginOffset (-100,000)] are used to identify values that are created by the VM due to an exception while evaluating an instruction. - final type ValueOriginsIterator = IntIterator
- trait ValuesDomain extends AnyRef
Defines the concept of a value in a
Domain
.Defines the concept of a value in a
Domain
.- See also
Domain For an explanation of the underlying concepts and ideas.
- type ValuesFactory = PrimitiveValuesFactory with ReferenceValuesFactory with ExceptionsFactory with TypedValuesFactory
Value Members
- final val ConstantValueOrigin: Int(-333)
Used to identify that the origin of the value is outside of the program.
Used to identify that the origin of the value is outside of the program.
For example, the VM sometimes performs comparisons against predetermined fixed values (specified in the JVM Spec.). The origin associated with such values is determined by this value.
- final val FrameworkName: String("OPAL Abstract Interpretation Framework")
- final val ImmediateVMExceptionsOriginOffset: Int(-100000)
Identifies the upper bound for those origin values that encode origin information about exceptions created by the JVM.
Identifies the upper bound for those origin values that encode origin information about exceptions created by the JVM. That is, respective values identify VM generated and thrown exceptions due to the immediate execution of the instruction; exceptions that may have been raised in a called method - even if they are created by the VM, e.g., due to a div by zero - are not considered immediate VM exceptions.
- final val MethodExternalExceptionsOriginOffset: Int(-1000000)
Identifies the upper bound for those origin values that encode origin information about values created outside the current method.
Identifies the upper bound for those origin values that encode origin information about values created outside the current method. Exception which resulted from the evaluation of a failing instruction are never method external values.
- final def NoPCs: IntTrieSet
- final def NoValueOrigins: ValueOrigins
- Annotations
- @inline()
- final val SUBROUTINE: Int(-900000009)
Special value that is added to the work list to mark the beginning of a subroutine call.
- final val SUBROUTINE_END: Int(-888888888)
Special value ("pc") that is added to the list of
evaluated instructions
to mark the end of the evaluation of a subroutine. - final val SUBROUTINE_INFORMATION_BLOCK_SEPARATOR_BOUND: Int(-800000000)
A special value that is larger than all other values used to mark boundaries and information related to the handling of subroutines and which is smaller that all other regular values.
- final val SUBROUTINE_RETURN_ADDRESS_LOCAL_VARIABLE: Int(-888880008)
- final val SUBROUTINE_RETURN_TO_TARGET: Int(-800008888)
- final val SUBROUTINE_START: Int(-800000008)
Special value ("pc") that is added to the work list/list of evaluated instructions before the program counter of the first instruction of a subroutine.
Special value ("pc") that is added to the work list/list of evaluated instructions before the program counter of the first instruction of a subroutine.
The marker SUBROUTINE is used to mark the place in the worklist where we start having information about subroutines.
- final val SpecialValuesOriginOffset: Int(-800000000)
Identifies the upper bound for those "origin values" that encode special information; that is, subroutine boundaries.
- final def ValueOriginForImmediateVMException(pc: PC): ValueOrigin
Creates the origin information for a value (typically an exception) that was (implicitly) created while evaluating the instruction with the given program counter (
pc
).Creates the origin information for a value (typically an exception) that was (implicitly) created while evaluating the instruction with the given program counter (
pc
).- returns
The origin id of the value that is the result of the evaluation of the instruction with the given PC if the evaluation has failed!
- See also
pcOfImmediateVMException for further information.
- final def ValueOriginForMethodExternalException(pc: Int): Int
Creates the origin information for a value (exception) that was created while evaluating the (invoke) instruction with the given program counter (
pc
).Creates the origin information for a value (exception) that was created while evaluating the (invoke) instruction with the given program counter (
pc
).- returns
The origin id of the value that is the result of the evaluation of the instruction with the given PC!
- See also
pcOfMethodExternalException for further information.
- def collectPCWithOperands[B](domain: ValuesDomain)(code: Code, operandsArray: OperandsArray)(f: PartialFunction[(Int, Instruction, ai.ValuesDomain.Operands), B]): Seq[B]
Collects the result of a match of a partial function against an instruction's operands.
- def foreachPCWithOperands[U](domain: ValuesDomain)(code: Code, operandsArray: OperandsArray)(f: (Int, Instruction, ai.ValuesDomain.Operands) => U): Unit
- final def isImmediateVMException(origin: ValueOrigin): Boolean
Returns
true
if the value with the given origin was (implicitly) created by the JVM while executing an instruction with the program counter pcOfImmediateVMException(origin)
.Returns
true
if the value with the given origin was (implicitly) created by the JVM while executing an instruction with the program counter pcOfImmediateVMException(origin)
.- See also
ImmediateVMExceptionsOriginOffset for further information.
- final def isImplicitOrExternalException(valueOrigin: Int): Boolean
- final def isMethodExternalExceptionOrigin(origin: ValueOrigin): Boolean
Returns
true
if the value with the given origin was (implicitly) created by the JVM while executing an instruction with the program counter pcOfMethodExternalException(origin)
.Returns
true
if the value with the given origin was (implicitly) created by the JVM while executing an instruction with the program counter pcOfMethodExternalException(origin)
.- See also
MethodExternalExceptionsOriginOffset for further information.
- def mapOperands(theOperands: Operands[_ <: DomainValue], targetDomain: ValuesDomain with ValuesFactory): Array[(targetDomain)#DomainValue]
Maps the operands to the target domain while ensuring that two operands that are identical before are identical afterwards.
- def mapOperandsToParameters(operands: Operands[_ <: DomainValue], calledMethod: Method, targetDomain: ValuesDomain with ValuesFactory): Locals[(targetDomain)#DomainValue]
Maps a list of operands (e.g., as passed to the
invokeXYZ
instructions) to the list of parameters for the given method.Maps a list of operands (e.g., as passed to the
invokeXYZ
instructions) to the list of parameters for the given method. The parameters are stored in the local variables (Locals)/registers of the method; i.e., this method creates an initial assignment for the local variables that can directly be used to pass them to AI'sperform(...)(<initialOperands = Nil>,initialLocals)
method.- operands
The list of operands used to call the given method. The length of the list must be:
calledMethod.descriptor.parametersCount + { if (calledMethod.isStatic) 0 else 1 }
. I.e., the list of operands must contain one value per parameter and – in case of instance methods – the receiver object. The list must not contain additional values. The latter is automatically ensured if this method is called (in)directly by AI and the operands were just passed through. If two or more operands are (reference) identical then the adaptation will only be performed once and the adapted value will be reused; this ensures that the relation between values remains stable.
- calledMethod
The method that will be evaluated using the given operands.
- targetDomain
The Domain that will be use to perform the abstract interpretation.
- def memoryLayoutToText(domain: Domain)(operandsArray: ai.Domain.OperandsArray, localsArray: ai.Domain.LocalsArray): String
Creates a human-readable textual representation of the current memory layout.
- def parameterIndexToValueOrigin(isStatic: Boolean, descriptor: MethodDescriptor, parameterIndex: Int): Int
Calculates the initial
ValueOrigin
associated with a method's explicit parameter.Calculates the initial
ValueOrigin
associated with a method's explicit parameter. The index of the first parameter is 0. If the method is not static the this reference stored in local variable0
has the origin-1
.- isStatic
true
if method is static and, hence, has no implicit parameter forthis
.- returns
The origin id for the specified parameter.
- See also
- def parameterVariables(aiResult: AIResult)(isStatic: Boolean, descriptor: MethodDescriptor): Array[ai.Domain.DomainValue]
Extracts the domain variables (register values) related to the method's parameters; see org.opalj.tac.Parameters for the detailed layout of the returned array.
Extracts the domain variables (register values) related to the method's parameters; see org.opalj.tac.Parameters for the detailed layout of the returned array.
Recall that at the bytecode level long and double values use two register values. The returned array will, however, abstract over the difference between so-called computational type category I and II values. Furthermore, the explicitly specified parameters are always stored in the indexes [1..parametersCount] to enable unified access to a method's parameters whether the method is static or not. Furthermore, the returned array will contain the self reference (
this
) at index 0 if the method is an instance method; otherwise index 0 will benull
.- isStatic
true
if the method is static (we have nothis
reference).- descriptor
The method descriptor.
- returns
The local variables which represent the parameters. The size of the returned array is the sum of the operand sizes of the parameters + 1 if the method is an instance method. (@see parameterIndexToValueOrigin and mapOperandsToParameters for further details.)
- Note
If a parameter (variable) is used as a variable and updated, then the returned domain value will reflect this behavior. For example, given the following code:
// Given: class X extends Object foo(X x) { do { x = new Y(); System.out.println(x) } while(true;)}
The type of the domain value will be (as expected) x; however - depending on the domain - it may contain the information that x may also reference the created object Y.
- def parameterVariablesIterator(aiResult: AIResult)(isStatic: Boolean, descriptor: MethodDescriptor): Iterator[ai.Domain.DomainValue]
Iterates over all im-/explicit parameter related variables.
Iterates over all im-/explicit parameter related variables.
- isStatic
Has to be
true
iff the method for which the abstract interpretation was performed is static.
- final def pcOfImmediateVMException(valueOrigin: ValueOrigin): PC
Returns the program counter (
pc
) of the instruction that (implicitly) led to the creation of the (method external) value (typically anException
).Returns the program counter (
pc
) of the instruction that (implicitly) led to the creation of the (method external) value (typically anException
).- See also
ValueOriginForImmediateVMException for further information.
- final def pcOfMethodExternalException(valueOrigin: Int): Int
Returns the program counter (
pc
) of the (invoke) instruction that is (indirectly) responsible for the creation of the value.Returns the program counter (
pc
) of the (invoke) instruction that is (indirectly) responsible for the creation of the value.- See also
MethodExternalExceptionsOriginOffset for further information.
- final def remapPC(pcToIndex: Array[Int])(oldValueOrigin: Int): Int
Maps
oldVo
to the value found at the location pcToIndex(oldVo) ifoldVO
actually identifies a PC.Maps
oldVo
to the value found at the location pcToIndex(oldVo) ifoldVO
actually identifies a PC. I.e., ifoldVO
is related to a parameter oldVo is returned as is. IfoldVO
identifies an implicit or a method-external value, oldVO is remapped w.r.t. to the specific category.- pcToIndex
Array which contains for each PC a new value.
- oldValueOrigin
The value origin for which the underlying PC
- if it exists - should be remapped.
- returns
The mapped value origin.
- final def underlyingPC(valueOrigin: Int): ValueOrigin
Returns the PC underlying the given value origin.
Returns the PC underlying the given value origin. If the value origin identifies a parameter the value is returned as is.
- object AICompleted
- object AIResultBuilder
Factory to create
AIResult
objects.Factory to create
AIResult
objects. Primarily used to return the result of an abstract interpretation of a method. - object BaseAI extends BaseAI
Instance of the base abstract interpreter.
- object CTC1
Facilitates matching against values of computational type category 1.
Facilitates matching against values of computational type category 1.
case v @ CTC1() => ...
Example: - object CTC2
Facilitates matching against values of computational type category 2.
Facilitates matching against values of computational type category 2.
case v @ CTC2() => ...
Example: - case object ComputationFailed extends Computation[Nothing, Nothing] with Product with Serializable
Indicates that the computation did not succeed.
Indicates that the computation did not succeed. This is typically the case for methods that contain an endless loop, such as:
while(true){.../* no break statements */}
- object ComputationWithException
- object ComputationWithResult
- object ComputationWithResultAndException
- case object ComputationWithSideEffectOnly extends Computation[Nothing, Nothing] with Product with Serializable
Represents a computation that completed normally.
- case object ExceptionsRaisedByCalledMethods extends Enumeration with Product with Serializable
Enumeration of how method calls are treated when the set of exceptions thrown by the target method is not completely known.
- object InstructionCountBoundedAI
Defines common helper methods.
- object InterpretationFailedException
Factory for InterpretationFailedExceptions.
- case object MetaInformationUpdateType extends UpdateType with MetaInformationUpdateType with Product with Serializable
- case object NoUpdate extends Update[Nothing] with Product with Serializable
Indicates that the (given) structure was not updated.
Indicates that the (given) structure was not updated.
- Note
The abstract interpretation framework itself does not distinguish between a
NoUpdate
and aMetaInformationUpdate
; the abstract interpretation will not be continued in both cases.
- case object NoUpdateType extends UpdateType with Product with Serializable
- object SomeUpdate
Facilitates matching against updates that actually encapsulate an updated value.
- case object StructuralUpdateType extends UpdateType with Product with Serializable