From d87ce33458866117de947e85e9c90c67175aac6d Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Mon, 19 Oct 2015 19:16:23 +0300 Subject: [PATCH] Drop @inline from tests and incremental compilation --- .../org/jetbrains/kotlin/inline/inlineUtil.kt | 69 +++++++++++++++++++ .../kotlin/codegen/InlineTestUtil.kt | 20 +++--- .../jps/incremental/IncrementalCacheImpl.kt | 29 +++----- 3 files changed, 89 insertions(+), 29 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt new file mode 100644 index 00000000000..5f3e4d4b94a --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.inline + +import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader +import org.jetbrains.kotlin.serialization.Flags +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.deserialization.NameResolver +import org.jetbrains.kotlin.serialization.deserialization.TypeTable +import org.jetbrains.kotlin.serialization.jvm.BitEncoding +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil + +public fun inlineFunctionsJvmNames(bytes: ByteArray): Set { + val header = readKotlinHeader(bytes) + val annotationData = header.annotationData + val strings = header.strings + + if (annotationData == null || strings == null) return emptySet() + + return when (header.kind) { + KotlinClassHeader.Kind.CLASS -> { + val classData = JvmProtoBufUtil.readClassDataFrom(BitEncoding.decodeBytes(annotationData), strings) + inlineFunctionsJvmNames(classData.classProto.functionList, classData.nameResolver, classData.classProto.typeTable) + } + KotlinClassHeader.Kind.FILE_FACADE, + KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> { + val packageData = JvmProtoBufUtil.readPackageDataFrom(BitEncoding.decodeBytes(annotationData), strings) + inlineFunctionsJvmNames(packageData.packageProto.functionList, packageData.nameResolver, packageData.packageProto.typeTable) + } + else -> emptySet() + } +} + +private fun inlineFunctionsJvmNames(functions: List, nameResolver: NameResolver, protoTypeTable: ProtoBuf.TypeTable): Set { + val typeTable = TypeTable(protoTypeTable) + val inlineFunctions = functions.filter { Flags.IS_INLINE.get(it.flags) } + val jvmNames = inlineFunctions.map { + JvmProtoBufUtil.getJvmMethodSignature(it, nameResolver, typeTable) + } + return jvmNames.filterNotNull().toSet() +} + +private fun readKotlinHeader(bytes: ByteArray): KotlinClassHeader { + var header: KotlinClassHeader? = null + + FileBasedKotlinClass.create(bytes) { className, classHeader, innerClasses -> + header = classHeader + null + } + + if (header == null) throw AssertionError("Could not read kotlin header from byte array") + + return header!! +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt b/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt index 8dcb6ae02d0..56382eccf7b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt @@ -17,10 +17,10 @@ package org.jetbrains.kotlin.codegen; import org.jetbrains.kotlin.backend.common.output.OutputFile +import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass -import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.resolve.jvm.JvmClassName @@ -32,7 +32,6 @@ import kotlin.properties.Delegates public object InlineTestUtil { - public val INLINE_ANNOTATION_CLASS: String = "kotlin/inline" private val KOTLIN_PACKAGE_DESC = "L" + AsmUtil.internalNameByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_PACKAGE) + ";" private val KOTLIN_MULTIFILE_CLASS_DESC = "L" + AsmUtil.internalNameByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS) + ";" @@ -62,27 +61,28 @@ public object InlineTestUtil { val classHeaders = hashMapOf() for (file in files) { - val cr = ClassReader(file.asByteArray()) + val bytes = file.asByteArray() + val cr = ClassReader(bytes) + + val inlineFunctions = inlineFunctionsJvmNames(bytes) + if (inlineFunctions.isEmpty()) continue val classVisitor = object : ClassVisitorWithName() { - override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor { return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { - public override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor { - val type = Type.getType(desc) - val annotationClass = type.getInternalName() - if (INLINE_ANNOTATION_CLASS == annotationClass) { + override fun visitEnd() { + if (name + desc in inlineFunctions) { inlineMethods.add(MethodInfo(className, name, this.desc)) } - return super.visitAnnotation(desc, visible) } } } } - cr.accept(classVisitor, 0) + cr.accept(classVisitor, 0) classHeaders.put(classVisitor.className, getClassHeader(file)) } + return InlineInfo(inlineMethods, classHeaders) } diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt index d7aeaf112a9..3de1a1a4800 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -27,17 +27,15 @@ import org.jetbrains.jps.incremental.ModuleBuildTarget import org.jetbrains.jps.incremental.storage.BuildDataManager import org.jetbrains.jps.incremental.storage.PathStringDescriptor import org.jetbrains.jps.incremental.storage.StorageOwner +import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames import org.jetbrains.kotlin.jps.build.GeneratedJvmClass import org.jetbrains.kotlin.jps.build.KotlinBuilder import org.jetbrains.kotlin.jps.incremental.storage.BasicMap import org.jetbrains.kotlin.jps.incremental.storage.BasicStringMap -import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.ModuleMapping -import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.header.* import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName.byInternalName import org.jetbrains.kotlin.serialization.jvm.BitEncoding @@ -49,8 +47,6 @@ import java.io.File import java.security.MessageDigest import java.util.* -val INLINE_ANNOTATION_DESC = "Lkotlin/inline;" - internal val CACHE_DIRECTORY_NAME = "kotlin" @TestOnly @@ -451,26 +447,21 @@ public class IncrementalCacheImpl( private fun getInlineFunctionsMap(bytes: ByteArray): Map { val result = HashMap() + val inlineFunctions = inlineFunctionsJvmNames(bytes) + if (inlineFunctions.isEmpty()) return emptyMap() + ClassReader(bytes).accept(object : ClassVisitor(Opcodes.ASM5) { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { val dummyClassWriter = ClassWriter(Opcodes.ASM5) + return object : MethodVisitor(Opcodes.ASM5, dummyClassWriter.visitMethod(0, name, desc, null, exceptions)) { - var hasInlineAnnotation = false - - override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? { - if (desc == INLINE_ANNOTATION_DESC) { - hasInlineAnnotation = true - } - return null - } - override fun visitEnd() { - if (hasInlineAnnotation) { - val dummyBytes = dummyClassWriter.toByteArray()!! - val hash = dummyBytes.md5() + val jvmName = name + desc + if (jvmName !in inlineFunctions) return - result[name + desc] = hash - } + val dummyBytes = dummyClassWriter.toByteArray()!! + val hash = dummyBytes.md5() + result[jvmName] = hash } } }