A highly-configurable framework for the (abstract) interpretation of Java bytecode that relies on OPAL's resolved representation (org.opalj.br) of Java bytecode.
A highly-configurable framework for the (abstract) interpretation of Java bytecode that relies on OPAL's resolved 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.
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.
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.
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%.
(STILL IN DESIGN!!!!)
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 (frist) 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"!
When we have a fork, check if all paths...
Customization of the abstract interpreter is done by creating new subclasses that override the relevant methods (in particular: AI#isInterrupted and AI#tracer).
,OPAL does not make assumptions about the number of domain objects 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.
Encapsulates the intermediate result of an aborted abstract interpretation of a method.
Encapsulates the final result of the successful abstract interpretation of a method.
A general, non-recoverable exception occurred during the abstract interpretation of a method.
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.
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.
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.
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.
BoundedInterruptableAI for an abstract interpreter that can easily be interrupted and which also interrupts itself if a certain threshold is exceeded.
An abstract interpreter that interrupts itself after the evaluation of
the given number of instructions or if the callback function doInterrupt
returns
false
or if the maximum allowed time is exceeded.
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 not Nothing
) must not return a result and/or throw an
exception if the computation did not finish.
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
returns
true
the methods result
and hasResult
are defined.
The result of the computation. Typically a DomainValue
;
if the computation is executed for its side
effect (e.g., as in case of a monitorenter
or monitorexit
instruction)
the type of V
maybe Nothing
.
The exception(s) that maybe thrown by the computation. Typically,
a DomainValue
which represents a reference value with type
java.lang.Throwable
or a subtype thereof. If multiple exceptions may be
thrown it may also be a set or Iterable
of DomainValue
s (e.g.,
ExceptionValues
).
The precise requirements on the result of a computation are determined by the Domain object's methods that perform computations.
Encapsulates the result of a computation that returned normally (but which did not return some value) or that threw an exception/multiple exceptions.
Encapsulates the result of a computation that returned normally and that did not throw an exception.
Encapsulates the result of a computation that either returned normally or threw an 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.
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.
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 it generates all exceptions that may be thrown.
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.
This trait defines concrete methods that facilitate unit testing of
partial domains that build on top of this CoreDomain
such as the
IntegerValuesDomain.
Domain For an explanation of the underlying concepts and ideas.
A Domain that supports the tracking of correlations between values.
Provides basic support for tracking the correlation between domain values stored in different registers/in different stack slots.
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.
This class is thread-safe. I.e., one instance can be used to run multiple abstract interpretations in parallel.
Mixin this trait if a domain needs to perform some custom initialization.
Mixin this trait if a domain needs to perform some custom initialization.
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.
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.
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 an
int
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:
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.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.
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.
OPAL assumes that – at least conceptually – every method/code block is associated with its own instance of a domain object.
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
.
Defines the public interface between the abstract interpreter and the domain
that implements the functionality related to the handling of double
values.
Defines the primary factory methods for Double values.
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
...).
Interface related to the handling of field access instructions.
Defines the public interface between the abstract interpreter and the domain
that implements the functionality related to the handling of float
values.
Defines factory methods to create concrete representations of constant float values.
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.
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:
Mixing in this trait is strictly necessary when aliases are traced using a DomainValue's reference.
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.
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.
Defines a factory method to create IntegerRange
values.
Defines the public interface between the abstract interpreter and the domain
that implements the functionality related to the handling of int
eger values.
Defines the primary factory methods to create Integer
values.
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$.
An abstract interpreter that can be interrupted by calling the AI's interrupt
method
or by calling the executing thread's interrupt method.
The value has the primitive type.
Characterizes a reference value.
Characterizes a reference value. Captures the information about the values a domain value may refer to. For example, in the following:
val o = If(...) new Object() else "STRING"
o is a reference value (IsReferenceValue
) that (may) refers to two "simple" base values:
new Object()
and "STRING"
; however, it is a decision of the the underlying domain whether
the information about the base values is made available or not. Furthermore, if the base values
are actually used, the constraints in effect for the overall abstraction should be considered
to get the most precise result.
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]
with
AnIntegerValue[#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.
Join stabilization is always done for all domain values once this trait is mixed in.
Defines the public interface between the abstract interpreter and the domain that implements the functionality related to the handling of long values.
Defines the primary factory methods to create long
values.
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 and
MetaInformationUpdate
s in the same way.
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.
Defines all methods related to the invocation of other methods.
Domain that defines all methods related to monitor instructions.
A tracer that forwards every call to all registered tracers.
Defines the methods that performs type conversions between primitive values with different computational types.
Domain that defines all methods that perform computations related to RefernceValues
.
Definition of factory methods to create ReferenceValues
.
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 a Monitorexit
instruction, but no Monitorenter
instruction.
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.
This type alias serves comprehension purposes only.
Identifies updates where something was updated without further qualifying the update.
Identifies updates where something was updated without further qualifying the update.
This class (and its companion object) are primarily used for pattern matching purposes.
Characterizes updates where the abstract state was updated such that it is required to continue the abstract interpretation.
Enables specialized processing of subroutine calls by domains; this is generally only relevant for those domains that record the control-flow graph.
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.
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.
Makes a project's class hierarchy available to a Domain
.
Makes a project's class hierarchy available to a Domain
.
Implements a Domain's isSubtypeOf(...)
by delegating to
the corresponding method defined in org.opalj.br.ClassHierarchy.
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.
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.
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).
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.
Encapsulates the result of a computation that threw an exception.
An abstract interpreter that interrupts itself after some configurable (maxEffort) time has passed.
Encapsulates the available type information about a DomainValue
.
Defines additional, generally useful factory methods to create DomainValue
s.
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.
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 an UpdateType
object never has any payload, it just characterizes
an update. However, by passing a value to an UpdateType
the UpdateType
is turned into a corresponding org.opalj.ai.Update object.
val updateType : UpdateType = ... val update : Update = updateType(<someValue>)
A ValueOrigin
identifies the origin of a value.
A ValueOrigin
identifies the origin of a value.
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.
In general, parameters are identified by using negative origin information as described below. But, given that
this
reference in case of instance methods andlong
and double
values* require two slots
the smallest number used to encode that the value is an actual parameter is -256
.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*/){...}
-1
is used to identify the implicit this
reference.-2
identifies the value of the parameter d
.-4
identifies the parameter o
. (The parameter d
is a value of
computational-type category 2 and needs two stack/operands values.)In case of the three address code the parameters are normalized (see org.opalj.tac.TACAI for further details).
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.
The value -333
is used to encode that the value is an implicit constant
(ConstantValueOrigin). This value is used for the implicit value of IF_XXX
instructions to facilitates a generalized handling of ifs.
Values in the range [ SpecialValuesOriginOffset (-10,000,000
) ,
VMLevelValuesOriginOffset (-100,000
) ] are used to identify values that are
created by the VM (in particular exceptions) while evaluating the instruction with
the pc = -origin-100,000
.
For further information see isVMLevelValue, ValueOriginForVMLevelValue, pcOfVMLevelValue.
Defines the concept of a value in a Domain
.
Defines the concept of a value in a Domain
.
Domain For an explanation of the underlying concepts and ideas.
Factory to create AIResult
objects.
Factory to create AIResult
objects. Primarily used to return the
result of an abstract interpretation of a method.
Instance of the base abstract interpreter.
Defines an extractor method for instances of IsReferenceValue
objects.
Defines an extractor method for instances of IsReferenceValue
objects.
To ensure that the generic type can be matched, it may be necessary to first cast a generic org.opalj.ai.ValuesDomain.DomainValue to a org.opalj.ai.ValuesDomain.DomainReferenceValue.
val d : Domain = ... val d.DomainReferenceValue(v) = /*some domain value; e.g., operands.head*/ val BaseReferenceValues(values) = v values...
Facilitates matching against values of computational type category 1.
Facilitates matching against values of computational type category 1.
case v @ CTC1() => ...
Facilitates matching against values of computational type category 2.
Facilitates matching against values of computational type category 2.
case v @ CTC2() => ...
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 */}
Represents a computation that completed normally.
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.
Enumeration of how method calls are treated when the set of exceptions thrown by the target method is not completely known.
Defines common helper methods.
Factory for InterpretationFailedExceptions.
Defines and extractor for the null-property of reference values.
Indicates that the (given) structure was not updated.
Indicates that the (given) structure was not updated.
The abstract interpretation framework itself does not distinguish between a
NoUpdate
and a MetaInformationUpdate
; the abstract interpretation will not
be continued in both cases.
Special value that is added to the work list to mark the beginning of a subroutine call.
Special value ("pc") that is added to the list of evaluated instructions
to mark the end of the evaluation of a subroutine.
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.
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.
Facilitates matching against updates that actually encapsulate an updated value.
Identifies the upper bound for those origin values that encode special information.
Extractor for reference values.
Specifies that no type information is available.
Specifies that no type information is available.
Recall that the computational type of a value always has to
be available, but that a
ValuesDomain.typeOfValue(...)
query does not need to take the computational type
into account. (Whenever the core framework requires the computational type of a
value it uses the respective method.) However, in case that the
underlying value may be an array or exception
value the reported type must not be TypeUnknown
.
Identifies the upper bound for those origin values that encode origin information about VM level values.
Creates the origin information for a VM level value (typically an exception) that
was (implicitly) created while evaluating the instruction with the given
program counter (pc
).
Creates the origin information for a VM level value (typically an exception) that
was (implicitly) created while evaluating the instruction with the given
program counter (pc
).
pcOfVMLevelValue for further information.
Collects the result of a match of a partial function against an instruction's operands.
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.
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 these Domain
s can be used to create a final Domain
) and
those that can be stacked and basically refine the overall functionality.
Examples
Domain
's respective methods. However, it does provide a
default implementation. Hence, a typical pattern is:class MyDomain extends Domain with ... with DefaultHandlingOfMethodResults with RecordThrownExceptions
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 for Domain
s that are used for the evaluation of methods. However
domains that are used to adapt/transfer values should be thread safe
(see ValuesCoordinatingDomain for further details).
Returns true
if the value with the given origin was (implicitly) created
by the JVM while executing an instruction with the program counter
pcOfVMLevelValue(origin)
.
Returns true
if the value with the given origin was (implicitly) created
by the JVM while executing an instruction with the program counter
pcOfVMLevelValue(origin)
.
ValueOriginForVMLevelValue for further information.
Maps the operands to the target domain while ensuring that two operands that are identical before are identical afterwards.
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's
perform(...)(<initialOperands = Nil>,initialLocals)
method.
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.
The method that will be evaluated using the given operands.
The Domain that will be use to perform the abstract interpretation.
Creates a human-readable textual representation of the current memory layout.
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 variable 0
has the origin -1
.
true
if method is static and, hence, has no implicit
parameter for this
.
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 unifor 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 be null
.
true
if the method is static (we have no this
reference).
The method descriptor.
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.)
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.
Iterates over all im-/explicit parameter related variables.
Iterates over all im-/explicit parameter related variables.
Has to be true
iff the method for which the abstract interpretation was
performed is static.
Returns the program counter (pc
) of the instruction that (implicitly) led to the
creation of the VM level value (typically an Exception
).
Returns the program counter (pc
) of the instruction that (implicitly) led to the
creation of the VM level value (typically an Exception
).
ValueOriginForVMLevelValue for further information.
Common utility functionality.
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 indomain
) are not considered to be part of the core of OPAL/the abstract interpreter.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).org.opalj.ai.Domain - The core interface between the abstract interpretation framework and the abstract domain that is responsible for performing the abstract computations.
org.opalj.ai.AI - Implements the abstract interpreter that processes a methods code and uses an analysis-specific domain to perform the abstract computations.