Skip to content

Commit ac298fa

Browse files
mvicsokolovaelizarov
authored andcommitted
TraceFormat references removed on JVM and JS
1 parent a855073 commit ac298fa

File tree

5 files changed

+78
-14
lines changed

5 files changed

+78
-14
lines changed

atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformer.kt

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,9 +1052,9 @@ class AtomicFUTransformer(
10521052
return next.next
10531053
}
10541054

1055-
// erases pushing atomic factory trace arguments
1055+
// removes pushing atomic factory trace arguments
10561056
// returns the first value argument push
1057-
private fun eraseTraceInit(atomicFactory: MethodInsnNode, isArrayFactory: Boolean): AbstractInsnNode {
1057+
private fun removeTraceInit(atomicFactory: MethodInsnNode, isArrayFactory: Boolean): AbstractInsnNode {
10581058
val initStart = FlowAnalyzer(atomicFactory).getInitStart(1)
10591059
if (isArrayFactory) return initStart
10601060
var lastArg = atomicFactory.previous
@@ -1067,7 +1067,7 @@ class AtomicFUTransformer(
10671067
return initStart
10681068
}
10691069

1070-
private fun eraseTraceInfo(append: AbstractInsnNode): AbstractInsnNode {
1070+
private fun removeTraceAppend(append: AbstractInsnNode): AbstractInsnNode {
10711071
// remove append trace instructions: from append invocation up to getfield Trace or accessor to Trace field
10721072
val afterAppend = append.next
10731073
var start = append
@@ -1089,11 +1089,11 @@ class AtomicFUTransformer(
10891089
} else {
10901090
instructions.remove(start.previous)
10911091
}
1092-
if (start.next is VarInsnNode) {
1093-
val v = (start.next as VarInsnNode).`var`
1094-
localVariables.removeIf { it.index == v }
1095-
}
10961092
while (start != afterAppend) {
1093+
if (start is VarInsnNode) {
1094+
// remove all local store instructions
1095+
localVariables.removeIf { it.index == (start as VarInsnNode).`var` }
1096+
}
10971097
val next = start.next
10981098
instructions.remove(start)
10991099
start = next
@@ -1114,7 +1114,7 @@ class AtomicFUTransformer(
11141114
val f = fields[fieldId]!!
11151115
val isArray = AFU_CLASSES[i.owner]?.let { it.originalType.sort == ARRAY } ?: false
11161116
// erase pushing arguments for trace initialisation
1117-
val newInitStart = eraseTraceInit(i, isArray)
1117+
val newInitStart = removeTraceInit(i, isArray)
11181118
// in FU mode wrap values of top-level primitive atomics into corresponding *RefVolatile class
11191119
if (!vh && f.isStatic && !f.isArray) {
11201120
return putPrimitiveTypeWrapper(i, newInitStart, f, next)
@@ -1153,6 +1153,20 @@ class AtomicFUTransformer(
11531153
return fixupLoadedAtomicVar(f, j)
11541154
}
11551155
methodId == TRACE_FACTORY || methodId == TRACE_PARTIAL_ARGS_FACTORY -> {
1156+
if (methodId == TRACE_FACTORY) {
1157+
// remove trace format initialization
1158+
var checkcastTraceFormat = i
1159+
while (checkcastTraceFormat.opcode != CHECKCAST) checkcastTraceFormat = checkcastTraceFormat.previous
1160+
val astoreTraceFormat = checkcastTraceFormat.next
1161+
val tranceFormatInitStart = FlowAnalyzer(checkcastTraceFormat.previous).getInitStart(1).previous
1162+
var initInsn = checkcastTraceFormat
1163+
while (initInsn != tranceFormatInitStart) {
1164+
val prev = initInsn.previous
1165+
instructions.remove(initInsn)
1166+
initInsn = prev
1167+
}
1168+
instructions.insertBefore(astoreTraceFormat, InsnNode(ACONST_NULL))
1169+
}
11561170
// remove trace factory and following putfield
11571171
val argsSize = getMethodType(methodId.desc).argumentTypes.size
11581172
val putfield = i.next
@@ -1170,7 +1184,7 @@ class AtomicFUTransformer(
11701184
return next
11711185
}
11721186
methodId == TRACE_APPEND -> {
1173-
return eraseTraceInfo(i)
1187+
return removeTraceAppend(i)
11741188
}
11751189
methodId in removeMethods -> {
11761190
abort(

atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/AtomicFUTransformerJS.kt

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ private const val MANGLED_VALUE_PROP = "kotlinx\$atomicfu\$value"
1717

1818
private const val TRACE_CONSTRUCTOR = "atomicfu\\\$Trace\\\$"
1919
private const val TRACE_APPEND = "atomicfu\\\$Trace\\\$append\\\$"
20+
private const val TRACE_NAMED = "atomicfu\\\$Trace\\\$named\\\$"
21+
private const val TRACE_FORMAT = "TraceFormat"
22+
private const val TRACE_FORMAT_CONSTRUCTOR = "atomicfu\\\$$TRACE_FORMAT\\\$"
23+
private const val TRACE_FORMAT_FORMAT = "atomicfu\\\$TraceFormat\\\$format\\\$"
2024

2125
private const val RECEIVER = "\$receiver"
2226
private const val SCOPE = "scope"
2327
private const val FACTORY = "factory"
2428
private const val REQUIRE = "require"
29+
private const val PROTOTYPE = "prototype"
2530
private const val KOTLINX_ATOMICFU = "'kotlinx-atomicfu'"
2631
private const val KOTLINX_ATOMICFU_PACKAGE = "kotlinx.atomicfu"
2732
private const val KOTLIN_TYPE_CHECK = "Kotlin.isType"
@@ -33,6 +38,7 @@ private const val GET_ELEMENT = "get\\\$atomicfu"
3338
private const val LOCKS = "locks"
3439
private const val REENTRANT_LOCK_ATOMICFU_SINGLETON = "$LOCKS.reentrantLock\\\$atomicfu"
3540

41+
3642
private val MANGLE_VALUE_REGEX = Regex(".${Pattern.quote(MANGLED_VALUE_PROP)}")
3743
// matches index until the first occurence of ')', parenthesised index expressions not supported
3844
private val ARRAY_GET_ELEMENT_REGEX = Regex(".$GET_ELEMENT\\((.*)\\)")
@@ -44,6 +50,7 @@ class AtomicFUTransformerJS(
4450
private val atomicConstructors = mutableSetOf<String>()
4551
private val atomicArrayConstructors = mutableMapOf<String, String?>()
4652
private val traceConstructors = mutableSetOf<String>()
53+
private val traceFormatObjects = mutableSetOf<String>()
4754

4855
override fun transform() {
4956
info("Transforming to $outputDir")
@@ -122,10 +129,10 @@ class AtomicFUTransformerJS(
122129
}
123130
}
124131
Token.FUNCTION -> {
125-
// erasing 'kotlinx-atomicfu' module passed as parameter
126132
if (node is FunctionNode) {
127133
val it = node.params.listIterator()
128134
while (it.hasNext()) {
135+
// erasing 'kotlinx-atomicfu' module passed as parameter
129136
if (isAtomicfuModule(it.next())) {
130137
it.remove()
131138
}
@@ -208,13 +215,19 @@ class AtomicFUTransformerJS(
208215
} else if (initializer.matches(Regex(kotlinxAtomicfuModuleName(TRACE_CONSTRUCTOR)))) {
209216
traceConstructors.add(varInit.target.toSource())
210217
node.replaceChild(stmt, EmptyLine())
211-
} else if (initializer.matches(Regex(kotlinxAtomicfuModuleName(LOCKS)))){
218+
} else if (initializer.matches(Regex(kotlinxAtomicfuModuleName("""($LOCKS|$TRACE_FORMAT_CONSTRUCTOR|$TRACE_NAMED)""")))) {
212219
node.replaceChild(stmt, EmptyLine())
213220
}
214221
}
215222
}
216223
}
217224
}
225+
if (node is PropertyGet && node.property.toSource().matches(Regex(TRACE_FORMAT_FORMAT))) {
226+
val target = node.target
227+
if (target is PropertyGet && target.property.toSource().matches(Regex(PROTOTYPE))) {
228+
traceFormatObjects.add(target.target.toSource())
229+
}
230+
}
218231
if (node is VariableInitializer && node.initializer is PropertyGet) {
219232
val initializer = node.initializer.toSource()
220233
if (initializer.matches(Regex(REENTRANT_LOCK_ATOMICFU_SINGLETON))) {
@@ -333,6 +346,35 @@ class AtomicFUTransformerJS(
333346
}
334347
}
335348
}
349+
if (node is Assignment && node.left is PropertyGet) {
350+
val left = node.left as PropertyGet
351+
if (traceFormatObjects.contains(left.target.toSource())) {
352+
if (node.right is FunctionCall) {
353+
// TraceFormatObject initialization
354+
(node.right as FunctionCall).arguments = listOf(Name().also { it.identifier = "null" })
355+
}
356+
}
357+
}
358+
// remove TraceFormatObject constructor definition
359+
if (node is FunctionNode && traceFormatObjects.contains(node.name)) {
360+
val body = node.body
361+
for (stmt in body) { body.replaceChild(stmt, EmptyLine()) }
362+
}
363+
// remove TraceFormat from TraceFormatObject interfaces
364+
if (node is Assignment && node.left is PropertyGet && node.right is ObjectLiteral) {
365+
val left = node.left as PropertyGet
366+
val metadata = node.right as ObjectLiteral
367+
if (traceFormatObjects.contains(left.target.toSource())) {
368+
for (e in metadata.elements) {
369+
if (e.right is ArrayLiteral) {
370+
val array = (e.right as ArrayLiteral).toSource()
371+
if (array.contains(TRACE_FORMAT)) {
372+
(e.right as ArrayLiteral).elements = emptyList()
373+
}
374+
}
375+
}
376+
}
377+
}
336378
return true
337379
}
338380

@@ -543,7 +585,7 @@ class AtomicFUTransformerJS(
543585
}
544586
}
545587

546-
private class EmptyLine: EmptyExpression() {
588+
private class EmptyLine : EmptyExpression() {
547589
override fun toSource(depth: Int) = "\n"
548590
}
549591

atomicfu/src/commonMain/kotlin/kotlinx/atomicfu/TraceFormat.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,29 @@
22
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5+
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
6+
57
package kotlinx.atomicfu
68

9+
import kotlin.internal.InlineOnly
10+
import kotlin.js.JsName
11+
712
/**
813
* Trace string formatter.
914
*/
15+
@JsName("atomicfu\$TraceFormat\$")
1016
public open class TraceFormat {
1117
/**
1218
* Formats trace at the given [index] with the given [text] as string.
1319
*/
20+
@JsName("atomicfu\$TraceFormat\$format\$")
1421
public open fun format(index: Int, text: String): String = "$index: $text"
1522
}
1623

1724
/**
1825
* Creates trace string formatter with the given [format] code block.
1926
*/
27+
@InlineOnly
2028
public inline fun TraceFormat(crossinline format: (index: Int, text: String) -> String): TraceFormat =
2129
object : TraceFormat() {
2230
override fun format(index: Int, text: String): String = format(index, text)

atomicfu/src/commonTest/kotlin/bytecode_test/TraceUseTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import kotlinx.atomicfu.*
88
import kotlin.test.*
99

1010
class TraceUseTest {
11-
// todo: figure out what to do with trace format (removing it is not supported right now)
12-
val trace = Trace(size = 64)
11+
val trace = Trace(size = 64, format = TraceFormat { i, t -> "[$i$t]" } )
1312
val current = atomic(0, trace.named("current"))
1413

1514
@Test

atomicfu/src/jsMain/kotlin/kotlinx/atomicfu/Trace.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package kotlinx.atomicfu
88
@Suppress("FunctionName")
99
public actual fun Trace(size: Int, format: TraceFormat): TraceBase = TraceBase.None
1010

11+
@JsName("atomicfu\$Trace\$named\$")
1112
public actual fun TraceBase.named(name: String): TraceBase = TraceBase.None
1213

1314
public actual val traceFormatDefault: TraceFormat = TraceFormat()

0 commit comments

Comments
 (0)