This PR implements several refactorings of the byte-code transformation part of the Lincheck.
Some of the refactorings are needed in preparation of the new model checking strategy merge, the others aim to just simplify the code.
LincheckClassVisitor.kt is split into several files to simplify future development and reduce number of potential merge-conflicts. Independent bytecode transformers are moved into separate files and grouped logically.
ObjectAtomicWriteTrackerTransformer is split into AtomicFieldUpdaterTransformer, VarHandleTransformer and UnsafeTransformer (but common methods of these transformers are still shared). This is because in the new strategy the byte-code transformation to track methods of these APIs (AFU, VH and Unsafe) is significantly more complicated. So it makes sense to split them and handle each API separatly.
as a part of this, I have also added handling of some missing VH and Unsafe methods, for example, putObject, putReference, compareAndSetReference, compareAndSetReferenceRelease, etc.
Several common code patterns are extracted into separate functions and moved into TransformationUtils.kt:
storeLocals(valueTypes: Array<Type>, localTypes: Array<Type>) stores #N top values from the stack into local variables, performing boxing if requested by the caller.
copyLocals(valueTypes: Array<Type>, localTypes: Array<Type>) same as storeLocals but copies the values from the stack without modifying the stack.
storeArguments(methodDescriptor: String) and copyArguments(methodDescriptor: String) wrappers around storeLocals and copyLocals to save method arguments from the stack to local variables.
pushNull pushes null to the stack.
pushArray(locals: IntArray) wraps local variables into an array (boxing them if necessary) and pushes this array onto the stack.
Leave only one beforeReadField and beforeWriteField methods, passing isStatic and isFinal as arguments. This change allows the ManagedStrategy itself decide how to handle static and final fields (because in the new strategy we might also want to track accesses to final fields).
This PR implements several refactorings of the byte-code transformation part of the Lincheck.
Some of the refactorings are needed in preparation of the new model checking strategy merge, the others aim to just simplify the code.
LincheckClassVisitor.kt
is split into several files to simplify future development and reduce number of potential merge-conflicts. Independent bytecode transformers are moved into separate files and grouped logically.ObjectAtomicWriteTrackerTransformer
is split intoAtomicFieldUpdaterTransformer
,VarHandleTransformer
andUnsafeTransformer
(but common methods of these transformers are still shared). This is because in the new strategy the byte-code transformation to track methods of these APIs (AFU, VH and Unsafe) is significantly more complicated. So it makes sense to split them and handle each API separatly.putObject
,putReference
,compareAndSetReference
,compareAndSetReferenceRelease
, etc.Several common code patterns are extracted into separate functions and moved into
TransformationUtils.kt
:storeLocals(valueTypes: Array<Type>, localTypes: Array<Type>)
stores#N
top values from the stack into local variables, performing boxing if requested by the caller.copyLocals(valueTypes: Array<Type>, localTypes: Array<Type>)
same asstoreLocals
but copies the values from the stack without modifying the stack.storeArguments(methodDescriptor: String)
andcopyArguments(methodDescriptor: String)
wrappers aroundstoreLocals
andcopyLocals
to save method arguments from the stack to local variables.pushNull
pushesnull
to the stack.pushArray(locals: IntArray)
wraps local variables into an array (boxing them if necessary) and pushes this array onto the stack.Leave only one
beforeReadField
andbeforeWriteField
methods, passingisStatic
andisFinal
as arguments. This change allows theManagedStrategy
itself decide how to handle static and final fields (because in the new strategy we might also want to track accesses to final fields).Minor renamings:
onMethodCallFinishedSuccessfully
-->onMethodCallReturn
onMethodCallThrewException
-->onMethodCallException
onWriteToObjectFieldOrArrayCell
-->afterReflectiveSetter
(because it is only called from reflections APIs, such as VarHandle or AFU).