• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.atomicfu.transformer
6 
7 import kotlinx.metadata.*
8 import kotlinx.metadata.jvm.*
9 import org.objectweb.asm.tree.*
10 
11 const val KOTLIN_METADATA_DESC = "Lkotlin/Metadata;"
12 
13 class MetadataTransformer(
14     removeFields: Set<FieldId>,
15     removeMethods: Set<MethodId>
16 ) {
17     private val removeFieldSignatures: List<JvmFieldSignature> =
18         removeFields.map { JvmFieldSignature(it.name, it.desc) }
19     private val removeMethodSignatures: List<JvmMethodSignature> =
20         removeMethods.map { JvmMethodSignature(it.name, it.desc) }
21     private var transformed = false
22 
23     @Suppress("UNCHECKED_CAST")
24     fun transformMetadata(metadataAnnotation: AnnotationNode): Boolean {
25         val map = metadataAnnotation.asMap()
26         val hdr = KotlinClassHeader(
27             kind = map["k"] as Int?,
28             metadataVersion = (map["mv"] as? List<Int>)?.toIntArray(),
29             bytecodeVersion = (map["bv"] as? List<Int>)?.toIntArray(),
30             data1 = (map["d1"] as? List<String>)?.toTypedArray(),
31             data2 = (map["d2"] as? List<String>)?.toTypedArray(),
32             extraString = map["xs"] as String?,
33             packageName = map["pn"] as String?,
34             extraInt = map["xi"] as Int?
35         )
36         val result = when (val metadata = KotlinClassMetadata.read(hdr)) {
37             is KotlinClassMetadata.Class -> {
38                 val w = KotlinClassMetadata.Class.Writer()
39                 metadata.accept(ClassFilter(w))
40                 w.write(hdr.metadataVersion, hdr.bytecodeVersion, hdr.extraInt)
41             }
42             is KotlinClassMetadata.FileFacade -> {
43                 val w = KotlinClassMetadata.FileFacade.Writer()
44                 metadata.accept(PackageFilter(w))
45                 w.write(hdr.metadataVersion, hdr.bytecodeVersion, hdr.extraInt)
46             }
47             is KotlinClassMetadata.MultiFileClassPart -> {
48                 val w = KotlinClassMetadata.MultiFileClassPart.Writer()
49                 metadata.accept(PackageFilter(w))
50                 w.write(metadata.facadeClassName, hdr.metadataVersion, hdr.bytecodeVersion, hdr.extraInt)
51             }
52             else -> return false // not transformed
53         }
54         if (!transformed) return false
55         result.apply {
56             with (metadataAnnotation) {
57                 // read resulting header & update annotation data
58                 setKey("d1", header.data1.toList())
59                 setKey("d2", header.data2.toList())
60             }
61         }
62         return true // transformed
63     }
64 
65     private inner class ClassFilter(v: KmClassVisitor?) : KmClassVisitor(v) {
66         private val supertypes = mutableListOf<KmType>()
67 
68         override fun visitSupertype(flags: Flags): KmTypeVisitor? =
69             KmType(flags).also { supertypes += it }
70 
71         override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? =
72             PropertyFilter(KmProperty(flags, name, getterFlags, setterFlags), super.visitProperty(flags, name, getterFlags, setterFlags)!!)
73         override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor =
74             FunctionFilter(KmFunction(flags, name), super.visitFunction(flags, name)!!)
75 
76         override fun visitEnd() {
77             // Skip supertype if it is SynchronizedObject (it is an alias to Any)
78             supertypes.forEach { type ->
79                 if (type.abbreviatedType?.classifier == SynchronizedObjectAlias) {
80                     transformed = true
81                 } else
82                     type.accept(super.visitSupertype(type.flags)!!)
83             }
84             super.visitEnd()
85         }
86     }
87 
88     private inner class PackageFilter(v: KmPackageVisitor?) : KmPackageVisitor(v) {
89         override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? =
90             PropertyFilter(KmProperty(flags, name, getterFlags, setterFlags), super.visitProperty(flags, name, getterFlags, setterFlags)!!)
91         override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor =
92             FunctionFilter(KmFunction(flags, name), super.visitFunction(flags, name)!!)
93     }
94 
95     private class PropertyExtensionNode : JvmPropertyExtensionVisitor() {
96         private var jvmFlags: Flags? = null
97         var fieldSignature: JvmFieldSignature? = null
98         private var getterSignature: JvmMethodSignature? = null
99         private var setterSignature: JvmMethodSignature? = null
100         private var syntheticMethodForAnnotationsDesc: JvmMethodSignature? = null
101 
102         override fun visit(
103             jvmFlags: Flags,
104             fieldSignature: JvmFieldSignature?,
105             getterSignature: JvmMethodSignature?,
106             setterSignature: JvmMethodSignature?
107         ) {
108             check(this.jvmFlags == null)
109             this.jvmFlags = jvmFlags
110             this.fieldSignature = fieldSignature
111             this.getterSignature = getterSignature
112             this.setterSignature = setterSignature
113         }
114 
115         override fun visitSyntheticMethodForAnnotations(signature: JvmMethodSignature?) {
116             check(syntheticMethodForAnnotationsDesc == null)
117             this.syntheticMethodForAnnotationsDesc = signature
118         }
119 
120         fun accept(v : JvmPropertyExtensionVisitor) {
121             if (jvmFlags != null) {
122                 v.visit(jvmFlags!!, fieldSignature, getterSignature, setterSignature)
123             }
124             syntheticMethodForAnnotationsDesc?.let { v.visitSyntheticMethodForAnnotations(it) }
125             v.visitEnd()
126         }
127     }
128 
129     private inner class PropertyFilter(
130         private val delegate: KmProperty,
131         private val v: KmPropertyVisitor
132     ) : KmPropertyVisitor(delegate) {
133         private var extension: PropertyExtensionNode? = null
134 
135         override fun visitExtensions(type: KmExtensionType): KmPropertyExtensionVisitor? {
136             check(type == JvmPropertyExtensionVisitor.TYPE)
137             check(extension == null)
138             return PropertyExtensionNode().also { extension = it }
139         }
140 
141         override fun visitEnd() {
142             if (extension?.fieldSignature in removeFieldSignatures) {
143                 // remove this function
144                 transformed = true
145                 return
146             }
147             delegate.receiverParameterType?.fixType { delegate.receiverParameterType = it }
148             delegate.returnType.fixType { delegate.returnType = it }
149             // keeping this property
150             extension?.accept(delegate.visitExtensions(JvmPropertyExtensionVisitor.TYPE) as JvmPropertyExtensionVisitor)
151             delegate.accept(v)
152         }
153     }
154 
155     private class FunctionExtensionNode : JvmFunctionExtensionVisitor() {
156         var signature: JvmMethodSignature? = null
157         private var originalInternalName: String? = null
158 
159         override fun visit(signature: JvmMethodSignature?) {
160             check(this.signature == null)
161             this.signature = signature
162         }
163 
164         override fun visitLambdaClassOriginName(internalName: String) {
165             check(originalInternalName == null)
166             originalInternalName = internalName
167         }
168 
169         fun accept(v : JvmFunctionExtensionVisitor) {
170             signature?.let { v.visit(it) }
171             originalInternalName?.let { v.visitLambdaClassOriginName(it) }
172             v.visitEnd()
173         }
174     }
175 
176     private inner class FunctionFilter(
177         private val delegate: KmFunction,
178         private val v: KmFunctionVisitor
179     ) : KmFunctionVisitor(delegate) {
180         private var extension: FunctionExtensionNode? = null
181 
182         override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor? {
183             check(type == JvmFunctionExtensionVisitor.TYPE)
184             check(extension == null)
185             return FunctionExtensionNode().also { extension = it }
186         }
187 
188         override fun visitEnd() {
189             if (extension?.signature in removeMethodSignatures) {
190                 // remove this function
191                 transformed = true
192                 return
193             }
194             // keeping this function
195             extension?.accept(delegate.visitExtensions(JvmFunctionExtensionVisitor.TYPE) as JvmFunctionExtensionVisitor)
196             delegate.accept(v)
197         }
198     }
199 
200     private fun KmType.fixType(update: (KmType) -> Unit) {
201         if (this.abbreviatedType?.classifier == ReentrantLockAlias) {
202             update(ReentrantLockType)
203             transformed = true
204         }
205     }
206 }
207 
208 private val SynchronizedObjectAlias = KmClassifier.TypeAlias("kotlinx/atomicfu/locks/SynchronizedObject")
209 
210 private val ReentrantLockAlias = KmClassifier.TypeAlias("kotlinx/atomicfu/locks/ReentrantLock")
<lambda>null211 private val ReentrantLockType = KmType(0).apply {
212     classifier = KmClassifier.Class("java/util/concurrent/locks/ReentrantLock")
213 }
214 
215 @Suppress("UNCHECKED_CAST")
AnnotationNodenull216 private fun AnnotationNode.asMap(): Map<String, Any?> {
217     val result = HashMap<String, Any?>()
218     for (i in 0 until values.size step 2) {
219         result.put(values[i] as String, values[i + 1])
220     }
221     return result
222 }
223 
AnnotationNodenull224 private fun AnnotationNode.setKey(key: String, value: Any?) {
225     for (i in 0 until values.size step 2) {
226         if (values[i] == key) {
227             values[i + 1] = value
228             return
229         }
230     }
231     error("Annotation key '$key' is not found")
232 }