Generate type checker barriers in bridges
This commit is contained in:
@@ -52,7 +52,7 @@ class JvmLower(val context: JvmBackendContext) {
|
|||||||
InitializersLowering(context).runOnFilePostfix(irFile)
|
InitializersLowering(context).runOnFilePostfix(irFile)
|
||||||
SingletonReferencesLowering(context).runOnFilePostfix(irFile)
|
SingletonReferencesLowering(context).runOnFilePostfix(irFile)
|
||||||
SyntheticAccessorLowering(context).lower(irFile)
|
SyntheticAccessorLowering(context).lower(irFile)
|
||||||
BridgeLowering(context.state).runOnFilePostfix(irFile)
|
BridgeLowering(context).runOnFilePostfix(irFile)
|
||||||
|
|
||||||
TailrecLowering(context).runOnFilePostfix(irFile)
|
TailrecLowering(context).runOnFilePostfix(irFile)
|
||||||
}
|
}
|
||||||
|
|||||||
+101
-39
@@ -21,6 +21,11 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
|||||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.findInterfaceImplementation
|
import org.jetbrains.kotlin.backend.common.bridges.findInterfaceImplementation
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
|
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptor
|
import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptor
|
||||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmFunctionDescriptorImpl
|
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmFunctionDescriptorImpl
|
||||||
@@ -33,31 +38,38 @@ import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
|||||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil.getDirectMember
|
import org.jetbrains.kotlin.codegen.JvmCodegenUtil.getDirectMember
|
||||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||||
import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor
|
import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||||
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.*
|
||||||
import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor
|
import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||||
|
|
||||||
class BridgeLowering(val state: GenerationState) : ClassLoweringPass {
|
class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||||
|
|
||||||
|
private val state = context.state
|
||||||
|
|
||||||
private val typeMapper = state.typeMapper
|
private val typeMapper = state.typeMapper
|
||||||
|
|
||||||
@@ -149,13 +161,17 @@ class BridgeLowering(val state: GenerationState) : ClassLoweringPass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!descriptor.kind.isReal && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION, state)) {
|
if (!descriptor.kind.isReal && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION, state)) {
|
||||||
val overridden = descriptor.getOverriddenBuiltinReflectingJvmDescriptor<CallableMemberDescriptor>()!!
|
descriptor.getOverriddenBuiltinReflectingJvmDescriptor<CallableMemberDescriptor>() ?:
|
||||||
|
error("Expect to find overridden descriptors for $descriptor")
|
||||||
|
|
||||||
if (!isThereOverriddenInKotlinClass(descriptor)) {
|
if (!isThereOverriddenInKotlinClass(descriptor)) {
|
||||||
val method = typeMapper.mapAsmMethod(descriptor)
|
|
||||||
val flags = Opcodes.ACC_ABSTRACT or getVisibilityAccessFlag(descriptor)
|
val flags = Opcodes.ACC_ABSTRACT or getVisibilityAccessFlag(descriptor)
|
||||||
//TODO
|
val bridgeDescriptor = JvmFunctionDescriptorImpl(
|
||||||
//v.newMethod(OtherOrigin(overridden!!), flags, method.name, method.descriptor, null, null)
|
descriptor.containingDeclaration as ClassDescriptor, null, Annotations.EMPTY,
|
||||||
|
descriptor.name, CallableMemberDescriptor.Kind.SYNTHESIZED, descriptor.source, flags
|
||||||
|
)
|
||||||
|
val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, bridgeDescriptor)
|
||||||
|
irClass.declarations.add(irFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,44 +189,92 @@ class BridgeLowering(val state: GenerationState) : ClassLoweringPass {
|
|||||||
val flags = ACC_PUBLIC or ACC_BRIDGE or (if (!isSpecialOrDelegationToSuper) ACC_SYNTHETIC else 0) or if (isSpecialBridge) ACC_FINAL else 0 // TODO.
|
val flags = ACC_PUBLIC or ACC_BRIDGE or (if (!isSpecialOrDelegationToSuper) ACC_SYNTHETIC else 0) or if (isSpecialBridge) ACC_FINAL else 0 // TODO.
|
||||||
val containingClass = descriptor.containingDeclaration as ClassDescriptor
|
val containingClass = descriptor.containingDeclaration as ClassDescriptor
|
||||||
//here some 'isSpecialBridge' magic
|
//here some 'isSpecialBridge' magic
|
||||||
val newName = Name.identifier(bridge.method.name)
|
val bridgeDescriptor = JvmFunctionDescriptorImpl(
|
||||||
val newDescriptor = JvmFunctionDescriptorImpl(containingClass, null, Annotations.EMPTY, newName, CallableMemberDescriptor.Kind.SYNTHESIZED, descriptor.source, flags)
|
containingClass, null, Annotations.EMPTY, Name.identifier(bridge.method.name),
|
||||||
|
CallableMemberDescriptor.Kind.SYNTHESIZED, descriptor.source, flags
|
||||||
val descriptorForBridge = bridge.descriptor
|
|
||||||
newDescriptor.initialize(
|
|
||||||
null, containingClass.thisAsReceiverParameter, emptyList(),
|
|
||||||
descriptorForBridge.valueParameters.map { it.copy(newDescriptor, it.name, it.index) },
|
|
||||||
descriptorForBridge.returnType, Modality.OPEN, descriptor.visibility
|
|
||||||
)
|
)
|
||||||
val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
|
||||||
val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, newDescriptor, irBody)
|
|
||||||
|
|
||||||
//TODO
|
bridgeDescriptor.initialize(
|
||||||
//MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv)
|
null, containingClass.thisAsReceiverParameter, emptyList(),
|
||||||
// if (delegateTo.method.argumentTypes.isNotEmpty() && isSpecialBridge) {
|
bridge.descriptor.valueParameters.map { it.copy(bridgeDescriptor, it.name, it.index) },
|
||||||
// generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes())
|
bridge.descriptor.returnType, Modality.OPEN, descriptor.visibility
|
||||||
// }
|
)
|
||||||
|
|
||||||
//TODO: rewrite
|
val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, bridgeDescriptor)
|
||||||
//here some 'isSpecialBridge' magic (see type special descriptor processing in KotlinTypeMapper)
|
|
||||||
val implementation = if (isSpecialBridge) delegateTo.descriptor.copyAsDeclaration() else delegateTo.descriptor
|
context.createIrBuilder(irFunction.symbol).irBlockBody(irFunction) {
|
||||||
val call = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
//TODO
|
||||||
implementation,
|
//MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv)
|
||||||
null, JvmLoweredStatementOrigin.BRIDGE_DELEGATION, null)
|
if (delegateTo.method.argumentTypes.isNotEmpty() && isSpecialBridge) {
|
||||||
call.dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, containingClass.thisAsReceiverParameter, JvmLoweredStatementOrigin.BRIDGE_DELEGATION)
|
generateTypeCheckBarrierIfNeeded(descriptor, bridgeDescriptor, delegateTo.method.argumentTypes)
|
||||||
newDescriptor.valueParameters.mapIndexed { i, valueParameterDescriptor ->
|
}
|
||||||
call.putValueArgument(i, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valueParameterDescriptor, JvmLoweredStatementOrigin.BRIDGE_DELEGATION))
|
|
||||||
|
val implementation = if (isSpecialBridge) delegateTo.descriptor.copyAsDeclaration() else delegateTo.descriptor
|
||||||
|
val call = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||||
|
implementation,
|
||||||
|
null, JvmLoweredStatementOrigin.BRIDGE_DELEGATION, null)
|
||||||
|
call.dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, containingClass.thisAsReceiverParameter, JvmLoweredStatementOrigin.BRIDGE_DELEGATION)
|
||||||
|
bridgeDescriptor.valueParameters.mapIndexed { i, valueParameterDescriptor ->
|
||||||
|
call.putValueArgument(i, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valueParameterDescriptor, JvmLoweredStatementOrigin.BRIDGE_DELEGATION))
|
||||||
|
}
|
||||||
|
+IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridgeDescriptor, call)
|
||||||
|
}.apply {
|
||||||
|
irFunction.body = this
|
||||||
}
|
}
|
||||||
irBody.statements.add(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, newDescriptor, call))
|
|
||||||
|
|
||||||
return irFunction
|
return irFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrBlockBodyBuilder.generateTypeCheckBarrierIfNeeded(
|
||||||
|
overrideDescriptor: FunctionDescriptor,
|
||||||
|
bridgeDescriptor: FunctionDescriptor,
|
||||||
|
delegateParameterTypes: Array<Type>?
|
||||||
|
) {
|
||||||
|
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(overrideDescriptor) ?: return
|
||||||
|
|
||||||
|
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(overrideDescriptor) ?:
|
||||||
|
error("Overridden built-in method should not be null for " + overrideDescriptor)
|
||||||
|
|
||||||
|
val conditions = bridgeDescriptor.valueParameters.withIndex().filter { (i, parameterDescriptor) ->
|
||||||
|
typeSafeBarrierDescription.checkParameter(i) ||
|
||||||
|
!(delegateParameterTypes == null || OBJECT_TYPE == delegateParameterTypes[i]) ||
|
||||||
|
!TypeUtils.isNullableType(parameterDescriptor.type)
|
||||||
|
}.map { (i, parameterDescriptor) ->
|
||||||
|
val checkValue = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameterDescriptor, JvmLoweredStatementOrigin.BRIDGE_DELEGATION)
|
||||||
|
if (delegateParameterTypes == null || OBJECT_TYPE == delegateParameterTypes[i]) {
|
||||||
|
irNotEquals(checkValue, irNull())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
irIs(checkValue, overrideDescriptor.valueParameters[i].type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conditions.isNotEmpty()) {
|
||||||
|
val condition = conditions.fold<IrExpression, IrExpression>(irTrue()) { arg, result ->
|
||||||
|
context.andand(arg, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
+irIfThen(irNot(condition), irBlock {
|
||||||
|
+irReturn(
|
||||||
|
when (typeSafeBarrierDescription) {
|
||||||
|
MAP_GET_OR_DEFAULT -> irGet(IrVariableSymbolImpl(bridgeDescriptor.valueParameters[1]))
|
||||||
|
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.NULL -> irNull()
|
||||||
|
INDEX -> IrConstImpl.int(
|
||||||
|
UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.builtIns.intType, typeSafeBarrierDescription.defaultValue as Int)
|
||||||
|
FALSE -> irFalse()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getSignatureMapper(typeMapper: KotlinTypeMapper): Function1<FunctionDescriptor, SignatureAndDescriptor> {
|
fun getSignatureMapper(typeMapper: KotlinTypeMapper): Function1<FunctionDescriptor, SignatureAndDescriptor> {
|
||||||
return fun(descriptor: FunctionDescriptor): SignatureAndDescriptor {
|
return fun(descriptor: FunctionDescriptor) =
|
||||||
return SignatureAndDescriptor(typeMapper.mapAsmMethod(descriptor), descriptor)
|
SignatureAndDescriptor(typeMapper.mapAsmMethod(descriptor), descriptor)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FunctionDescriptor.copyAsDeclaration(): FunctionDescriptor {
|
fun FunctionDescriptor.copyAsDeclaration(): FunctionDescriptor {
|
||||||
@@ -233,9 +297,7 @@ class BridgeLowering(val state: GenerationState) : ClassLoweringPass {
|
|||||||
return method == sig2.method
|
return method == sig2.method
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int = method.hashCode()
|
||||||
return method.hashCode()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user