Library Program
Instructions and structures representing programs.
@author Patryk Czarnik
Require Import Relations.
Require Import Common.
Require Import ArithOps.
Require Import ValuesNTypes.
Require Import ProgramStructures.
Require Import List.
Declare Module M_ProgramStructures : PROGRAM_STRUCTURES.
Module M_ProgramStructuresFacts := ProgramStructuresFacts M_ProgramStructures.
Import M_ProgramStructures.M_ValuesAndTypes.
Import M_ProgramStructures.
Import M_ProgramStructuresFacts.
Module M_ProgramStructuresFacts := ProgramStructuresFacts M_ProgramStructures.
Import M_ProgramStructures.M_ValuesAndTypes.
Import M_ProgramStructures.
Import M_ProgramStructuresFacts.
Instructions
Frame-level instructions
Inductive TGenericOp: Set :=
| Op_nop
| Op_dup
| Op_dup_x1
| Op_dup_x2
| Op_dup2
| Op_dup2_x1
| Op_dup2_x2
| Op_pop
| Op_pop2
| Op_swap.
| Op_nop
| Op_dup
| Op_dup_x1
| Op_dup_x2
| Op_dup2
| Op_dup2_x1
| Op_dup2_x2
| Op_pop
| Op_pop2
| Op_swap.
Subsequent stack instructions. Most of them are still super-instructions
repersenting classes of JVM instructions, e.g. all binary arithemtic
operations are represented here as Op_binop.
Generic stack operation.
Constant insertion operation.
Unary arithemtic operation. In fact, only one operator neg is handled here.
Binary arithemtic operation.
Arithmetic cast operation.
Comparison returning integer.
Instructions making use of local variables array.
Load value from a variable onto stack.
Store value from stack in a variable.
Increment value of a variable.
Instructions that may affect control flow within a frame – conditional and unconditional jumps.
Jump unconditionally.
Compare to zero.
Compare two values.
tableswitch instruction. The high value can be computed as low + (length table) - 1.
lookupswitch instruction.
Instructions that operate within the top most frame of a thread.
Stack-only operation.
Local variable operation.
Conditional and unconditional jumps.
Jump to a subroutine.
This is a different case than FI-Cond,
because the current PC value is used in the result operand stack.
Knowledge of PC is not required in FI_Cond semantics.
Return from a subroutine.
This is a separate case of frame instruction, because
it makes use of local variables array and at the same time
it changes PC.
Inductive TGetOp: Set :=
| Op_getfield (cn: TClassName) (field: TShortName)
| Op_getstatic (cn: TClassName) (field: TShortName)
| Op_getarray (k: TArrayIKind)
| Op_array_length
| Op_checkcast (rt: TReferenceType)
| Op_instanceof (rt: TReferenceType).
| Op_getfield (cn: TClassName) (field: TShortName)
| Op_getstatic (cn: TClassName) (field: TShortName)
| Op_getarray (k: TArrayIKind)
| Op_array_length
| Op_checkcast (rt: TReferenceType)
| Op_instanceof (rt: TReferenceType).
Specific operations requiring writing the heap.
Inductive TPutOp: Set :=
| Op_putfield (cn: TClassName) (field: TShortName)
| Op_putstatic (cn: TClassName) (field: TShortName)
| Op_putarray (k: TArrayIKind).
| Op_putfield (cn: TClassName) (field: TShortName)
| Op_putstatic (cn: TClassName) (field: TShortName)
| Op_putarray (k: TArrayIKind).
Specific operations requiring writing the heap
with allocation of new locations.
Inductive TNewOp: Set :=
| Op_newobject (cn: TClassName)
| Op_newarray (bt: TBaseType)
| Op_newarray_ref (rt: TReferenceType)
| Op_newmultiarray (rt: TReferenceType) (dimensions: nat).
| Op_newobject (cn: TClassName)
| Op_newarray (bt: TBaseType)
| Op_newarray_ref (rt: TReferenceType)
| Op_newmultiarray (rt: TReferenceType) (dimensions: nat).
Monitor operations.
Heap instructions: reading, writing, or creating new locations.
Inductive THeapInstr: Set :=
| HI_Get (get_op: TGetOp)
| HI_Put (put_op: TPutOp)
| HI_New (new_op: TNewOp)
| HI_Monitor (mon_op: TMonitorOp).
| HI_Get (get_op: TGetOp)
| HI_Put (put_op: TPutOp)
| HI_New (new_op: TNewOp)
| HI_Monitor (mon_op: TMonitorOp).
Other operations and ulimate definition of CoJaq instruction
The root of instructions hierarchy.
In-frame instructions
Heap access instructions
Invocation of a method
Return from a method
Throwing an exception
Program and its components
- Program components are declared and specified by axioms here. It allows for different implementations of the module.
- Program and its components, cosidered here as tangible objects, are accessible with deterministic functions rather than relations. Partial functions have option result type.
Gets the instruction that is pointed by the given PC.
Returns the next PC after the given one within the given program.
The returned PC may not be a valid one (i.e. getInstruction may be equal to None
instr is pointed by pc in code.
Complete JVM method.
Returns signature of the given method.
Returns declared visibility level of the given method.
Is the method static?
Is the method abstract?
Is the method synchonized?
Is the method an instance initialisation method? ("constructor")
Is the method a class initialisation method? ("static block")
Returns code of the given method.
Some methods may have no body (abstract and native ones);
in such case None is returned.
Abstract method has no body.
Returns the pc pointing to the first instruction to be
executed in a method.
Exception handler declared within a method.
All exception handlers declared for a method.
Is the given PC within the scope of the given exception handler?
The name of the class of exceptions caught by the given exception handler.
Beginning of handler block.
Returns the declared type of a field.
Returns the name of a field.
Returns the declared visibility level of a field.
States whether a field is declared final.
States whether a field is static.
Returns the qualified name of the class.
Is class abstract? True for abstract classes and interfaces.
Is this an interface in fact?
States if the ACC_SUPER flag is set in this class.
Returns a method from a class by the signature of the method.
Returns the field from the class and its superclasses.
Returns the list of dynamic fields from the class and its superclasses.
Returns the list of dynamic fields with initial values from the class
and its superclasses.
The directs superclass of a class. For Object it is None.
Returns a list of all direct (explicitly declared) interfaces implemented by this class
or a list of direct superinterfaces if this class is in fact an interface.
The Object class.
The Throwable class.
Object is the root of class hierarchy --- it does not have a parent.
Any class different from Object has a parent class.
Axiom PparentClass: ∀ c, parentClass c = None → c = class_Object.
Axiom PparentClassDifferent: ∀ c1 c2, parentClass c1 = Some c2 → c1 ≠ c2.
Axiom PparentClassDifferent: ∀ c1 c2, parentClass c1 = Some c2 → c1 ≠ c2.
isParentClass c1 c2 holds iff c1 is the direct parent class of c2.
isAncestorClass c1 c2 holds iff c1 is an acestor of c2 in the class hierarchy.
isAncestorClassOrSelf c1 c2 holds iff c1 is equal to c2 or c1 is an acestor of c2 in the class hierarchy.
Definition isAncestorClassOrSelf: TClass → TClass → Prop :=
clos_refl_trans TClass isParentClass.
Definition isDirectSuperTypeClass (c1 c2: TClass) :=
parentClass c2 = Some c1
∨ In c1 (getClassInterfaces c2).
Definition isSuperTypeClass: TClass → TClass → Prop :=
clos_trans TClass isDirectSuperTypeClass.
Definition isSuperTypeClassOrSelf: TClass → TClass → Prop :=
clos_refl_trans TClass isDirectSuperTypeClass.
clos_refl_trans TClass isParentClass.
Definition isDirectSuperTypeClass (c1 c2: TClass) :=
parentClass c2 = Some c1
∨ In c1 (getClassInterfaces c2).
Definition isSuperTypeClass: TClass → TClass → Prop :=
clos_trans TClass isDirectSuperTypeClass.
Definition isSuperTypeClassOrSelf: TClass → TClass → Prop :=
clos_refl_trans TClass isDirectSuperTypeClass.
The class hierarchy is well-founded.
Returns a class for the given name.
Returns a method for the given qualified name.
Definition getMethodFromProgram (p: TProgram) (qmn: TQualifiedMethodName): option TMethod :=
match qmn with (cn, mn) ⇒
match getClass p cn with
| None ⇒ None
| Some c ⇒
match getMethod mn c with
| None ⇒ None
| Some m ⇒ Some m
end
end
end.
match qmn with (cn, mn) ⇒
match getClass p cn with
| None ⇒ None
| Some c ⇒
match getMethod mn c with
| None ⇒ None
| Some m ⇒ Some m
end
end
end.
Returns code block of a method for the given qualified name.
Parameter getMethodBodyFromProgram: TProgram → TQualifiedMethodName → option TCode.
Axiom PgetMethodBodyFromProgram: ∀ p c m cn msig code,
getMethodBodyFromProgram p (cn, msig) = Some code ↔
(getClass p cn = Some c ∧
getMethod msig c = Some m ∧
getMethodCode m = Some code).
Axiom PgetMethodBodyFromProgram: ∀ p c m cn msig code,
getMethodBodyFromProgram p (cn, msig) = Some code ↔
(getClass p cn = Some c ∧
getMethod msig c = Some m ∧
getMethodCode m = Some code).
Subtype relation
Subtype relation for reference types, as defined for instanceof and checkcast instructions.
Fixpoint subtypeRef (p: TProgram) (rt1: TReferenceType) (rt2: TReferenceType) {struct rt1}: Prop :=
match rt1, rt2 with
| RTObject cn1, RTObject cn2 ⇒
match getClass p cn1, getClass p cn2 with
| None, None ⇒ False
| None, Some _ ⇒ False
| Some _, None ⇒ False
| Some c1, Some c2 ⇒
isInterfaceClass c1 = true ∧ c2 = class_Object
∨ isSuperTypeClassOrSelf c2 c1
end
| RTObject cn1, RTArray ct2 ⇒ False
| RTArray ct1, RTObject cn2 ⇒
In cn2 (StandardNames.Object :: StandardNames.arrayInterfaces)
| RTArray ct1, RTArray ct2 ⇒
match ct1, ct2 with
| BaseType bt1, BaseType bt2 ⇒
bt1 = bt2
| BaseType _, ReferenceType _ ⇒ False
| ReferenceType _, BaseType _ ⇒ False
| ReferenceType crt1, ReferenceType crt2 ⇒
subtypeRef p crt1 crt2
end
end.
Inductive validHandlerInd (p: TProgram) (pc: TPC) (exn_cn: TClassName): list THandler → option THandler → Prop :=
| ValidHandler_Nil: validHandlerInd p pc exn_cn nil None
| ValidHandler_Found: ∀ handler tl caught_class thrown_class,
getClass p (handlerType handler) = Some caught_class →
getClass p exn_cn = Some thrown_class →
isAncestorClassOrSelf caught_class thrown_class →
handlerInScope handler pc = true →
validHandlerInd p pc exn_cn (cons handler tl) (Some handler)
| ValidHandler_Cons: ∀ bad_handler valid_handler tl caught_class thrown_class,
getClass p (handlerType bad_handler) = Some caught_class →
getClass p exn_cn = Some thrown_class →
( ¬ isAncestorClassOrSelf caught_class thrown_class
∨ ¬ handlerInScope bad_handler pc = true) →
validHandlerInd p pc exn_cn tl (Some valid_handler) →
validHandlerInd p pc exn_cn (cons bad_handler tl) (Some valid_handler).
match rt1, rt2 with
| RTObject cn1, RTObject cn2 ⇒
match getClass p cn1, getClass p cn2 with
| None, None ⇒ False
| None, Some _ ⇒ False
| Some _, None ⇒ False
| Some c1, Some c2 ⇒
isInterfaceClass c1 = true ∧ c2 = class_Object
∨ isSuperTypeClassOrSelf c2 c1
end
| RTObject cn1, RTArray ct2 ⇒ False
| RTArray ct1, RTObject cn2 ⇒
In cn2 (StandardNames.Object :: StandardNames.arrayInterfaces)
| RTArray ct1, RTArray ct2 ⇒
match ct1, ct2 with
| BaseType bt1, BaseType bt2 ⇒
bt1 = bt2
| BaseType _, ReferenceType _ ⇒ False
| ReferenceType _, BaseType _ ⇒ False
| ReferenceType crt1, ReferenceType crt2 ⇒
subtypeRef p crt1 crt2
end
end.
Inductive validHandlerInd (p: TProgram) (pc: TPC) (exn_cn: TClassName): list THandler → option THandler → Prop :=
| ValidHandler_Nil: validHandlerInd p pc exn_cn nil None
| ValidHandler_Found: ∀ handler tl caught_class thrown_class,
getClass p (handlerType handler) = Some caught_class →
getClass p exn_cn = Some thrown_class →
isAncestorClassOrSelf caught_class thrown_class →
handlerInScope handler pc = true →
validHandlerInd p pc exn_cn (cons handler tl) (Some handler)
| ValidHandler_Cons: ∀ bad_handler valid_handler tl caught_class thrown_class,
getClass p (handlerType bad_handler) = Some caught_class →
getClass p exn_cn = Some thrown_class →
( ¬ isAncestorClassOrSelf caught_class thrown_class
∨ ¬ handlerInScope bad_handler pc = true) →
validHandlerInd p pc exn_cn tl (Some valid_handler) →
validHandlerInd p pc exn_cn (cons bad_handler tl) (Some valid_handler).
Points the valid exception handler for a given actual class of thrown exception.
Definition validExceptionHandler (p: TProgram) (m: TMethod) (pc: TPC) (exn_cn: TClassName) (maybe_handler: option THandler): Prop :=
validHandlerInd p pc exn_cn (methodExnHandlers m) maybe_handler.
End PROGRAM.
validHandlerInd p pc exn_cn (methodExnHandlers m) maybe_handler.
End PROGRAM.
Program with constructors
Include PROGRAM.
Require Import List.
Import M_ProgramStructures.M_ValuesAndTypes.
Import M_ProgramStructures.
Open Local Scope type_scope.
Require Import List.
Import M_ProgramStructures.M_ValuesAndTypes.
Import M_ProgramStructures.
Open Local Scope type_scope.
PC and offsets
- an "offset" is here represented with a natural number equal to the position of the target instruction.
Returns the position represented by the given PC.
Parameter pcToPosition: TPC → nat.
Axiom PpcPosition: ∀ pc,
pcFromPosition (pcToPosition pc) = pc.
Axiom PpositionPc: ∀ n,
pcToPosition (pcFromPosition n) = n.
Axiom PpcPosition: ∀ pc,
pcFromPosition (pcToPosition pc) = pc.
Axiom PpositionPc: ∀ n,
pcToPosition (pcFromPosition n) = n.
Creates an offset basing on a natural number
being the target of a jump.
The offset always leads to the given position
(the starting point of a jump is not meaningful!).
Axiom PmakeOffset: ∀ (n:nat) (pc:TPC),
pcToPosition (jump (offsetFromPosition n) pc) = n.
Axiom PmakeOffset_pc: ∀ (n:nat) (pc:TPC),
jump (offsetFromPosition n) pc = pcFromPosition n.
pcToPosition (jump (offsetFromPosition n) pc) = n.
Axiom PmakeOffset_pc: ∀ (n:nat) (pc:TPC),
jump (offsetFromPosition n) pc = pcFromPosition n.
Creates a code block containing the given instructions in the given order.
PC relates directly to the position of instruction on the list.
Axiom PgetInstructionIffNth: ∀ linstr pc,
getInstruction (codeFromList linstr) pc =
nth_error linstr (pcToPosition pc).
getInstruction (codeFromList linstr) pc =
nth_error linstr (pcToPosition pc).
makeMethod sets the signature, which is then returned by getSignature.
makeMethod sets the method code, which is then returned by getCode.
Methods created from a list begins at position 0.
Axiom PmakeMethod_methodBeginning: ∀ msig linstr,
pcToPosition (getMethodBeginning (makeMethod msig (codeFromList linstr))) = O.
pcToPosition (getMethodBeginning (makeMethod msig (codeFromList linstr))) = O.
For methods created from a list, next moves to the next position.
Axiom PcodeFromList_next: ∀ pc linstr,
pcToPosition (next (codeFromList linstr) pc) = S (pcToPosition pc).
pcToPosition (next (codeFromList linstr) pc) = S (pcToPosition pc).
For methods created from a list, next moves to the next position.
Axiom PcodeFromList_next_pc: ∀ n linstr,
next (codeFromList linstr) (pcFromPosition n) = pcFromPosition (S n).
next (codeFromList linstr) (pcFromPosition n) = pcFromPosition (S n).
Classes and programs
makeClass sets the class name, which is then returned by getClassName.
If a method identified by its signature existed in the methods list,
then, and only then, getMethod obtains that method from class created as
makeClass name methods.
Axiom PgetMethodIffIn: ∀ cn methods m,
In m methods ↔ getMethod (getMethodSignature m) (makeClass cn methods) = Some m.
In m methods ↔ getMethod (getMethodSignature m) (makeClass cn methods) = Some m.
Creates a program from a set of classes.
If a class identified by its name existed in the classes list,
then, and only then, getClass obtains that class from program created as
makeProgram classes.
Axiom PgetClassIffIn: ∀ classes c,
In c classes ↔ getClass (makeProgram classes) (getClassName c) = Some c.
End PROGRAM_W_CONSTRUCTORS.
In c classes ↔ getClass (makeProgram classes) (getClassName c) = Some c.
End PROGRAM_W_CONSTRUCTORS.