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