-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Static memory snapshot: add support for Unsafe, VarHandle, and AtomicFieldUpdater #429
Conversation
src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt
Outdated
Show resolved
Hide resolved
881a74a
to
fb813ab
Compare
Please note that you don't need to have special support for atomicfu -- it compiles to either AFU or VarHandle |
d95fd4d
to
2fd1a05
Compare
@@ -25,6 +25,57 @@ import java.util.* | |||
import kotlin.coroutines.* | |||
import kotlin.coroutines.intrinsics.* | |||
|
|||
fun shouldTransformClass(className: String): Boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems the code was moved from somewhere, but I do not see it removed in the original location.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I would suggest keeping the transformation-related logic in the corresponding package.
@@ -37,11 +37,22 @@ internal object AtomicFieldUpdaterNames { | |||
val offsetField = updater.javaClass.getDeclaredField("offset") | |||
val offset = UNSAFE.getLong(updater, UNSAFE.objectFieldOffset(offsetField)) | |||
|
|||
return findFieldNameByOffsetViaUnsafe(targetType, offset) | |||
return findFieldNameByOffsetViaUnsafe(targetType, offset).let { fieldName -> | |||
if (fieldName != null) AtomicFieldUpdaterDescriptor(targetType, fieldName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please always add { .. }
when the else
branch is present.
src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also don't forget to rebase on develop
.
isVarHandle(owner) && | ||
( | ||
VarHandleNames.isInstanceVarHandle(owner) && staticMemorySnapshot.isTracked(params.firstOrNull()) || | ||
VarHandleNames.isArrayVarHandle(owner) && staticMemorySnapshot.isTracked(params.firstOrNull()) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you check staticMemorySnapshot.isTracked
in case of VarHandle API, but not in case of AFU or Unsafe APIs?
Also, wouldn't the staticMemorySnapshot.trackField
methods check itself if the object is tracked or not?
else { | ||
null | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using let
is overkill here.
val fieldName = findFieldNameByOffsetViaUnsafe(targetType, offset) ?: return null
return AtomicFieldUpdaterDescriptor(targetType, fieldName)
private fun getDeclaringClass(obj: Any?, className: String, fieldName: String): Class<*> { | ||
return Class.forName(className).let { | ||
private fun getDeclaringClass(obj: Any?, clazz: Class<*>, fieldName: String): Class<*> { | ||
return clazz.let { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using let
is overkill here
} | ||
|
||
fun trackField(obj: Any?, accessClassName: String, fieldName: String) { | ||
if (obj != null && obj !in trackedObjects) return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please replace this line and all related lines with isTracked(obj)
override fun verifyResults(scenario: ExecutionScenario?, results: ExecutionResult?): Boolean { | ||
checkForExceptions(results) | ||
check(intArray === refIntArray) | ||
check(intArray.contentEquals(intArrayOf(2, 1, 4, 3, 6, 5, 8, 7, 10, 9))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please extract intArrayOf(2, 1, 4, 3, 6, 5, 8, 7, 10, 9)
into separate variable
override fun verifyResults(scenario: ExecutionScenario?, results: ExecutionResult?): Boolean { | ||
checkForExceptions(results) | ||
check(intList === refIntList) | ||
check(intList.toIntArray().contentEquals(intArrayOf(2, 1, 4, 3, 6, 5, 8, 7, 10, 9))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please extract intArrayOf(2, 1, 4, 3, 6, 5, 8, 7, 10, 9)
into separate variable
.../kotlinx/lincheck_test/strategy/modelchecking/snapshot/VarHandleModificationsSnapshotTest.kt
Show resolved
Hide resolved
.../kotlinx/lincheck_test/strategy/modelchecking/snapshot/VarHandleModificationsSnapshotTest.kt
Show resolved
Hide resolved
…ity methods of Arrays and Collections classes
2ef2af9
to
dce3e40
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few final nitpicks.
src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/SnapshotTracker.kt
Show resolved
Hide resolved
src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt
Outdated
Show resolved
Hide resolved
src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt
Outdated
Show resolved
Hide resolved
@ndkoval I am good with the current state of this PR. What about you? Should we merge it? |
|
||
private val arrayValue = intArrayOf(2, 1, 4, 3, 6, 5, 8, 7, 10, 9) | ||
|
||
// TODO: parallel operations are not supported because of java.lang.ClassCastException: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this TODO be left?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arrays
API has parallel*
versions of methods, I added this todo to add them later, when I fix the issue with System.arraycopy
.
I updated the TODO
message a little bit.
@@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater | |||
internal object AtomicFieldUpdaterNames { | |||
|
|||
@Suppress("DEPRECATION") | |||
internal fun getAtomicFieldUpdaterName(updater: Any): String? { | |||
internal fun getAtomicFieldUpdaterName(updater: Any): AtomicFieldUpdaterDescriptor? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the function be renamed?
else it.findField(fieldName).declaringClass | ||
} | ||
private fun getDeclaringClass(obj: Any?, clazz: Class<*>, fieldName: String): Class<*> { | ||
return if (obj != null) clazz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using both clauses in if
, please wrap the branches with brackets, it makes the flow more visible when reading the code
staticMemorySnapshot.trackField(obj, afuDesc.targetType, afuDesc.fieldName) | ||
} | ||
// TODO: System.arraycopy | ||
// TODO: reflexivity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reflection
Partly resolves issue #389.
This PR is aimed to add support for tracking fields that are accessed via:
Notably,
System.arraycopy(..)
is currently not supported.