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