Dump declaration mapping during codegen process.
This commit is contained in:
@@ -53,7 +53,7 @@ class GenerationState @JvmOverloads constructor(
|
|||||||
val files: List<KtFile>,
|
val files: List<KtFile>,
|
||||||
disableCallAssertions: Boolean = true,
|
disableCallAssertions: Boolean = true,
|
||||||
disableParamAssertions: Boolean = true,
|
disableParamAssertions: Boolean = true,
|
||||||
val generateDeclaredClassFilter: GenerationState.GenerateClassFilter = GenerationState.GenerateClassFilter.GENERATE_ALL,
|
val generateDeclaredClassFilter: GenerateClassFilter = GenerationState.GenerateClassFilter.GENERATE_ALL,
|
||||||
disableInline: Boolean = false,
|
disableInline: Boolean = false,
|
||||||
disableOptimization: Boolean = false,
|
disableOptimization: Boolean = false,
|
||||||
val useTypeTableInSerializer: Boolean = false,
|
val useTypeTableInSerializer: Boolean = false,
|
||||||
@@ -68,7 +68,8 @@ class GenerationState @JvmOverloads constructor(
|
|||||||
val outDirectory: File? = null,
|
val outDirectory: File? = null,
|
||||||
val incrementalCompilationComponents: IncrementalCompilationComponents? = null,
|
val incrementalCompilationComponents: IncrementalCompilationComponents? = null,
|
||||||
val progress: Progress = Progress.DEAF,
|
val progress: Progress = Progress.DEAF,
|
||||||
private val onIndependentPartCompilationEnd: GenerationStateEventCallback = GenerationStateEventCallback.DO_NOTHING
|
private val onIndependentPartCompilationEnd: GenerationStateEventCallback = GenerationStateEventCallback.DO_NOTHING,
|
||||||
|
dumpBinarySignatureMappingTo: File? = null
|
||||||
) {
|
) {
|
||||||
abstract class GenerateClassFilter {
|
abstract class GenerateClassFilter {
|
||||||
abstract fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean
|
abstract fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean
|
||||||
@@ -122,7 +123,7 @@ class GenerationState @JvmOverloads constructor(
|
|||||||
val reflectionTypes: ReflectionTypes = ReflectionTypes(module)
|
val reflectionTypes: ReflectionTypes = ReflectionTypes(module)
|
||||||
val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes()
|
val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes()
|
||||||
val factory: ClassFileFactory
|
val factory: ClassFileFactory
|
||||||
private val duplicateSignatureFactory: BuilderFactoryForDuplicateSignatureDiagnostics
|
private lateinit var duplicateSignatureFactory: BuilderFactoryForDuplicateSignatureDiagnostics
|
||||||
|
|
||||||
val replSpecific = ForRepl()
|
val replSpecific = ForRepl()
|
||||||
|
|
||||||
@@ -147,22 +148,20 @@ class GenerationState @JvmOverloads constructor(
|
|||||||
val rootContext: CodegenContext<*> = RootContext(this)
|
val rootContext: CodegenContext<*> = RootContext(this)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val optimizationClassBuilderFactory = OptimizationClassBuilderFactory(builderFactory, disableOptimization)
|
this.interceptedBuilderFactory = builderFactory
|
||||||
duplicateSignatureFactory = BuilderFactoryForDuplicateSignatureDiagnostics(
|
.wrapWith(
|
||||||
optimizationClassBuilderFactory, this.bindingContext, diagnostics, fileClassesProvider,
|
{ OptimizationClassBuilderFactory(it, disableOptimization) },
|
||||||
getIncrementalCacheForThisTarget(),
|
{ BuilderFactoryForDuplicateSignatureDiagnostics(
|
||||||
this.moduleName)
|
it, this.bindingContext, diagnostics, fileClassesProvider,
|
||||||
|
getIncrementalCacheForThisTarget(),
|
||||||
|
this.moduleName).apply { duplicateSignatureFactory = this } },
|
||||||
|
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, diagnostics) },
|
||||||
|
{ dumpBinarySignatureMappingTo?.let { destination -> SignatureDumpingBuilderFactory(it, destination) } ?: it }
|
||||||
|
)
|
||||||
|
.wrapWith(ClassBuilderInterceptorExtension.getInstances(project)) { builderFactory, extension ->
|
||||||
|
extension.interceptClassBuilderFactory(builderFactory, bindingContext, diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
var interceptedBuilderFactory: ClassBuilderFactory
|
|
||||||
= BuilderFactoryForDuplicateClassNameDiagnostics(duplicateSignatureFactory, diagnostics)
|
|
||||||
|
|
||||||
val interceptExtensions = ClassBuilderInterceptorExtension.getInstances(project)
|
|
||||||
|
|
||||||
for (extension in interceptExtensions) {
|
|
||||||
interceptedBuilderFactory = extension.interceptClassBuilderFactory(interceptedBuilderFactory, bindingContext, diagnostics)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.interceptedBuilderFactory = interceptedBuilderFactory
|
|
||||||
this.factory = ClassFileFactory(this, interceptedBuilderFactory)
|
this.factory = ClassFileFactory(this, interceptedBuilderFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,3 +213,9 @@ fun GenerationStateEventCallback(block: (GenerationState) -> Unit): GenerationSt
|
|||||||
object : GenerationStateEventCallback {
|
object : GenerationStateEventCallback {
|
||||||
override fun invoke(s: GenerationState) = block(s)
|
override fun invoke(s: GenerationState) = block(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ClassBuilderFactory.wrapWith(vararg wrappers: (ClassBuilderFactory) -> ClassBuilderFactory): ClassBuilderFactory =
|
||||||
|
wrappers.fold(this) { builderFactory, wrapper -> wrapper(builderFactory) }
|
||||||
|
|
||||||
|
private inline fun <T> ClassBuilderFactory.wrapWith(elements: Iterable<T>, wrapper: (ClassBuilderFactory, T) -> ClassBuilderFactory): ClassBuilderFactory =
|
||||||
|
elements.fold(this, wrapper)
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.codegen.state
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||||
|
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||||
|
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||||
|
import org.jetbrains.kotlin.codegen.DelegatingClassBuilderFactory
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MemberKind
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.RawSignature
|
||||||
|
import org.jetbrains.org.objectweb.asm.FieldVisitor
|
||||||
|
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||||
|
import java.io.BufferedWriter
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
class SignatureDumpingBuilderFactory(
|
||||||
|
builderFactory: ClassBuilderFactory,
|
||||||
|
val destination: File
|
||||||
|
) : DelegatingClassBuilderFactory(builderFactory) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val MEMBER_RENDERER = DescriptorRenderer.withOptions {
|
||||||
|
withDefinedIn = false
|
||||||
|
modifiers -= DescriptorRendererModifier.VISIBILITY
|
||||||
|
}
|
||||||
|
val TYPE_RENDERER = DescriptorRenderer.withOptions {
|
||||||
|
modifiers -= DescriptorRendererModifier.VISIBILITY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val outputStream: BufferedWriter by lazy {
|
||||||
|
// TODO: Replace with LOG.info and make log output go to MessageCollector
|
||||||
|
println("[INFO] Dumping signatures to $destination")
|
||||||
|
destination.parentFile?.mkdirs()
|
||||||
|
destination.bufferedWriter().apply { append("[\n") }
|
||||||
|
}
|
||||||
|
private var firstClassWritten: Boolean = false
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
outputStream.append("\n]")
|
||||||
|
outputStream.close()
|
||||||
|
super.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newClassBuilder(origin: JvmDeclarationOrigin): DelegatingClassBuilder {
|
||||||
|
return SignatureDumpingClassBuilder(origin, delegate.newClassBuilder(origin))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private inner class SignatureDumpingClassBuilder(val origin: JvmDeclarationOrigin, val _delegate: ClassBuilder) : DelegatingClassBuilder() {
|
||||||
|
override fun getDelegate() = _delegate
|
||||||
|
|
||||||
|
private val signatures = mutableListOf<Pair<RawSignature, DeclarationDescriptor?>>()
|
||||||
|
private lateinit var javaClassName: String
|
||||||
|
|
||||||
|
override fun defineClass(origin: PsiElement?, version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<out String>) {
|
||||||
|
javaClassName = name
|
||||||
|
|
||||||
|
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor {
|
||||||
|
signatures += RawSignature(name, desc, MemberKind.METHOD) to origin.descriptor
|
||||||
|
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newField(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor {
|
||||||
|
signatures += RawSignature(name, desc, MemberKind.FIELD) to origin.descriptor
|
||||||
|
return super.newField(origin, access, name, desc, signature, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun done() {
|
||||||
|
if (firstClassWritten) outputStream.append(",\n") else firstClassWritten = true
|
||||||
|
outputStream.append("\t{\n")
|
||||||
|
origin.descriptor?.let {
|
||||||
|
outputStream.append("\t\t").appendNameValue("declaration", TYPE_RENDERER.render(it)).append(",\n")
|
||||||
|
(it as? DeclarationDescriptorWithVisibility)?.visibility?.let {
|
||||||
|
outputStream.append("\t\t").appendNameValue("visibility", it.displayName).append(",\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputStream.append("\t\t").appendNameValue("class", javaClassName).append(", \n")
|
||||||
|
|
||||||
|
outputStream.append("\t\t").appendQuoted("members").append(": [\n")
|
||||||
|
signatures.joinTo(outputStream, ",\n") { buildString {
|
||||||
|
val (signature, descriptor) = it
|
||||||
|
append("\t\t\t{")
|
||||||
|
descriptor?.let {
|
||||||
|
(it as? DeclarationDescriptorWithVisibility)?.visibility?.let {
|
||||||
|
appendNameValue("visibility", it.displayName).append(",\t")
|
||||||
|
}
|
||||||
|
appendNameValue("declaration", MEMBER_RENDERER.render(it)).append(", ")
|
||||||
|
|
||||||
|
}
|
||||||
|
appendNameValue("name", signature.name).append(", ")
|
||||||
|
appendNameValue("desc", signature.desc).append("}")
|
||||||
|
}}
|
||||||
|
outputStream.append("\n\t\t]\n\t}")
|
||||||
|
|
||||||
|
super.done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Appendable.appendQuoted(value: String?): Appendable = value?.let { append('"').append(jsonEscape(it)).append('"') } ?: append("null")
|
||||||
|
private fun Appendable.appendNameValue(name: String, value: String?): Appendable = appendQuoted(name).append(": ").appendQuoted(value)
|
||||||
|
|
||||||
|
private fun jsonEscape(value: String): String = buildString {
|
||||||
|
for (index in 0..value.length - 1) {
|
||||||
|
val ch = value[index]
|
||||||
|
when (ch) {
|
||||||
|
'\b' -> append("\\b")
|
||||||
|
'\t' -> append("\\t")
|
||||||
|
'\n' -> append("\\n")
|
||||||
|
'\r' -> append("\\r")
|
||||||
|
'\"' -> append("\\\"")
|
||||||
|
'\\' -> append("\\\\")
|
||||||
|
else -> if (ch.toInt() < 32) {
|
||||||
|
append("\\u" + Integer.toHexString(ch.toInt()).padStart(4, '0'))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
append(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -398,7 +398,8 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
moduleName,
|
moduleName,
|
||||||
outputDirectory,
|
outputDirectory,
|
||||||
incrementalCompilationComponents,
|
incrementalCompilationComponents,
|
||||||
onIndependentPartCompilationEnd = onIndependentPartCompilationEnd)
|
onIndependentPartCompilationEnd = onIndependentPartCompilationEnd,
|
||||||
|
dumpBinarySignatureMappingTo = outputDirectory?.resolve("binary-signatures.json") ?: createTempFile("binary-signatures", ".json"))
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
val generationStart = PerformanceCounter.currentTime()
|
val generationStart = PerformanceCounter.currentTime()
|
||||||
|
|||||||
Reference in New Issue
Block a user