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 }