Skip to content

Commit

Permalink
Skipped transformation of the nested atomic field loads (#165)
Browse files Browse the repository at this point in the history
Fixes #160
  • Loading branch information
mvicsokolova authored Dec 3, 2020
1 parent ef6ca9b commit d96ad35
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ val AbstractInsnNode?.thisOrPrevUseful: AbstractInsnNode?
return cur
}

fun getInsnOrNull(from: AbstractInsnNode?, to: AbstractInsnNode?, predicate: (AbstractInsnNode) -> Boolean): AbstractInsnNode? {
var cur: AbstractInsnNode? = from?.next
while (cur != null && cur != to && !predicate(cur)) cur = cur.next
return cur
}

private fun AbstractInsnNode?.isUseless() = this is LabelNode || this is LineNumberNode || this is FrameNode

fun InsnList.listUseful(limit: Int = Int.MAX_VALUE): List<AbstractInsnNode> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1320,11 +1320,15 @@ class AtomicFUTransformer(
i.name = f.name
}
i.desc = if (vh) VH_TYPE.descriptor else f.fuType.descriptor
val prev = i.previous
if (vh && f.getPrimitiveType(vh).sort == ARRAY) {
return insertPureVhArray(i, f)
return getInsnOrNull(from = prev, to = insertPureVhArray(i, f)) { it.isAtomicGetFieldOrGetStatic() }
}
transformed = true
return fixupLoadedAtomicVar(f, i)
// in order not to skip the transformation of atomic field loads
// check if there are any nested between the current atomic field load instruction i and it's transformed operation
// and return the first one
return getInsnOrNull(from = prev, to = fixupLoadedAtomicVar(f, i)) { it.isAtomicGetFieldOrGetStatic() }
}
}
}
Expand Down Expand Up @@ -1356,6 +1360,10 @@ class AtomicFUTransformer(
return j.next
}

private fun AbstractInsnNode.isAtomicGetFieldOrGetStatic() =
this is FieldInsnNode && (opcode == GETFIELD || opcode == GETSTATIC) &&
FieldId(owner, name, desc) in fields

private fun AbstractInsnNode.isAtomicGetValueOrSetValue() =
isInvokeVirtual() && (getObjectType((this as MethodInsnNode).owner) in AFU_TYPES) &&
(name == GET_VALUE || name == SET_VALUE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package kotlinx.atomicfu.test

import kotlinx.atomicfu.*
import kotlin.test.*

class NestedAtomicFieldLoads {
private val a = atomic(0)
private val b = atomic(1)
private val c = atomic(2)
private val ref = atomic(A(B(70)))

private val flag = atomic(false)

private val arr = AtomicIntArray(7)

private fun foo(arg1: Int, arg2: Int, arg3: Int, arg4: Int): Int = arg1 + arg2 + arg3 + arg4

private class A(val b: B)
private class B(val n: Int)

@Test
fun testNestedGetField() {
a.value = b.value + c.value
assertEquals(3, a.value)
a.value = foo(a.value, b.value, c.value, ref.value.b.n)
assertEquals(76, a.value)
}

@Test
fun testNestedAtomicInvocations() {
flag.value = a.compareAndSet(0, 56)
assertTrue(flag.value)
}

@Test
fun testArrayNestedLoads() {
arr[5].value = b.value
assertEquals(1, arr[5].value)
arr[0].value = foo(arr[5].value, b.value, c.value, ref.value.b.n)
assertEquals(74, arr[0].value)
}
}

0 comments on commit d96ad35

Please sign in to comment.