Introduce support for plugin-defined intrinsics in old JVM backend:
(Old is created first because all intrinsics emit bytecode anyway) Provide intrinsic for serializer<T>() function so it won't invoke typeOf() construction and KType->KSerializer conversion making it fast and truly reflectionless Add support for recalculating stack size in plugin-defined intrinsics since it is needed for correct work: Unify method for recalculating stack size with existing typeOf intrinsic Add testdata for IR for future intrinsic in IR
This commit is contained in:
+25
-13
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.extensions
|
||||
@@ -19,10 +8,17 @@ package org.jetbrains.kotlin.codegen.extensions
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
|
||||
interface ExpressionCodegenExtension {
|
||||
companion object : ProjectExtensionDescriptor<ExpressionCodegenExtension>(
|
||||
@@ -46,6 +42,22 @@ interface ExpressionCodegenExtension {
|
||||
*/
|
||||
fun applyFunction(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: Context): StackValue? = null
|
||||
|
||||
/**
|
||||
* Called when inliner encounters [ReifiedTypeInliner.OperationKind.PLUGIN_DEFINED] marker
|
||||
* to perform extension-specific operation with reified type parameter.
|
||||
*
|
||||
* @return Required stack size for method after inlining is performed, 0 if the size is unknown, or -1 if extension ignores this marker
|
||||
*/
|
||||
fun applyPluginDefinedReifiedOperationMarker(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
type: KotlinType,
|
||||
asmType: Type,
|
||||
typeMapper: KotlinTypeMapper,
|
||||
typeSystem: TypeSystemCommonBackendContext,
|
||||
module: ModuleDescriptor
|
||||
): Int = -1
|
||||
|
||||
fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {}
|
||||
|
||||
val shouldGenerateClassSyntheticPartsInLightClassesMode: Boolean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,7 @@ class PsiInlineCodegen(
|
||||
) : InlineCodegen<ExpressionCodegen>(
|
||||
codegen, state, signature, typeParameterMappings, sourceCompiler,
|
||||
ReifiedTypeInliner(
|
||||
typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn), codegen.typeSystem,
|
||||
typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn, codegen.typeSystem), codegen.typeSystem,
|
||||
state.languageVersionSettings, state.unifiedNullChecks
|
||||
),
|
||||
), CallGenerator {
|
||||
|
||||
+16
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
@@ -19,15 +20,19 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.kotlin.types.model.TypeParameterMarker
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.Type.INT_TYPE
|
||||
import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
|
||||
class PsiInlineIntrinsicsSupport(
|
||||
override val state: GenerationState,
|
||||
private val reportErrorsOn: KtElement,
|
||||
private val typeSystem: TypeSystemCommonBackendContext
|
||||
) : ReifiedTypeInliner.IntrinsicsSupport<KotlinType> {
|
||||
override fun putClassInstance(v: InstructionAdapter, type: KotlinType) {
|
||||
DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper)
|
||||
@@ -79,4 +84,15 @@ class PsiInlineIntrinsicsSupport(
|
||||
override fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name) {
|
||||
state.diagnostics.report(TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND.on(reportErrorsOn, typeParameterName.asString()))
|
||||
}
|
||||
|
||||
override fun applyPluginDefinedReifiedOperationMarker(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
type: KotlinType,
|
||||
asmType: Type
|
||||
): Int {
|
||||
return ExpressionCodegenExtension.getInstances(state.project)
|
||||
.map { it.applyPluginDefinedReifiedOperationMarker(insn, instructions, type, asmType, state.typeMapper, typeSystem, state.module) }
|
||||
.maxOrNull() ?: -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
@@ -57,11 +46,12 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
private val unifiedNullChecks: Boolean,
|
||||
) {
|
||||
enum class OperationKind {
|
||||
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF;
|
||||
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF, PLUGIN_DEFINED;
|
||||
|
||||
val id: Int get() = ordinal
|
||||
}
|
||||
|
||||
|
||||
interface IntrinsicsSupport<KT : KotlinTypeMarker> {
|
||||
val state: GenerationState
|
||||
|
||||
@@ -75,6 +65,16 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
|
||||
fun reportSuspendTypeUnsupported()
|
||||
fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name)
|
||||
|
||||
/**
|
||||
* @return Required stack size for method after inlining is performed, 0 if the size is unknown, or -1 if plugin was not applied
|
||||
*/
|
||||
fun applyPluginDefinedReifiedOperationMarker(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
type: KotlinType,
|
||||
asmType: Type
|
||||
): Int = -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -181,6 +181,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
|
||||
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType)
|
||||
OperationKind.TYPE_OF -> processTypeOf(insn, instructions, type)
|
||||
OperationKind.PLUGIN_DEFINED -> processPluginDefined(insn, instructions, type, asmType)
|
||||
}
|
||||
) {
|
||||
instructions.remove(insn.previous.previous!!) // PUSH operation ID
|
||||
@@ -196,6 +197,23 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun processPluginDefined(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
type: KT,
|
||||
asmType: Type
|
||||
): Boolean {
|
||||
val applyResult = intrinsicsSupport.applyPluginDefinedReifiedOperationMarker(
|
||||
insn,
|
||||
instructions,
|
||||
intrinsicsSupport.toKotlinType(type),
|
||||
asmType
|
||||
)
|
||||
if (applyResult == -1) return false
|
||||
maxStackSize = max(maxStackSize, applyResult)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun reify(argument: ReificationArgument, replacementAsmType: Type, type: KT): Pair<Type, KT> =
|
||||
with(typeSystem) {
|
||||
val arrayType = type.arrayOf(argument.arrayDepth)
|
||||
@@ -269,15 +287,11 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
|
||||
instructions: InsnList,
|
||||
type: KT
|
||||
) = rewriteNextTypeInsn(insn, Opcodes.ACONST_NULL) { stubConstNull: AbstractInsnNode ->
|
||||
val newMethodNode = MethodNode(Opcodes.API_VERSION, "fake", "()V", null, null)
|
||||
val mv = wrapWithMaxLocalCalc(newMethodNode)
|
||||
typeSystem.generateTypeOf(InstructionAdapter(mv), type, intrinsicsSupport)
|
||||
val newMethodNode = newMethodNodeWithCorrectStackSize {
|
||||
typeSystem.generateTypeOf(it, type, intrinsicsSupport)
|
||||
}
|
||||
|
||||
// Adding a fake return (and removing it below) to trigger maxStack calculation
|
||||
mv.visitInsn(Opcodes.RETURN)
|
||||
mv.visitMaxs(-1, -1)
|
||||
|
||||
instructions.insert(insn, newMethodNode.instructions.apply { remove(last) })
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
instructions.remove(stubConstNull)
|
||||
|
||||
maxStackSize = max(maxStackSize, newMethodNode.maxStack)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -229,6 +229,19 @@ internal fun isAnonymousClass(internalName: String) =
|
||||
fun wrapWithMaxLocalCalc(methodNode: MethodNode) =
|
||||
MaxStackFrameSizeAndLocalsCalculator(Opcodes.API_VERSION, methodNode.access, methodNode.desc, methodNode)
|
||||
|
||||
fun newMethodNodeWithCorrectStackSize(block: (InstructionAdapter) -> Unit): MethodNode {
|
||||
val newMethodNode = MethodNode(Opcodes.API_VERSION, "fake", "()V", null, null)
|
||||
val mv = wrapWithMaxLocalCalc(newMethodNode)
|
||||
block(InstructionAdapter(mv))
|
||||
|
||||
// Adding a fake return (and removing it below) to trigger maxStack calculation
|
||||
mv.visitInsn(Opcodes.RETURN)
|
||||
mv.visitMaxs(-1, -1)
|
||||
|
||||
newMethodNode.instructions.apply { remove(last) }
|
||||
return newMethodNode
|
||||
}
|
||||
|
||||
private fun String.isInteger(radix: Int = 10) = toIntOrNull(radix) != null
|
||||
|
||||
internal fun isCapturedFieldName(fieldName: String): Boolean {
|
||||
|
||||
Reference in New Issue
Block a user