Added throwing exception if receiver type is unexpected

This assert is not generated with -opt mode
This commit is contained in:
Igor Chevdar
2018-02-21 18:40:26 +03:00
parent 2812480af9
commit be251c98fb
@@ -894,6 +894,7 @@ internal object Devirtualization {
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) { devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
val nativePtrType = context.builtIns.nativePtr.defaultType val nativePtrType = context.builtIns.nativePtr.defaultType
val nativePtrEqualityOperatorSymbol = context.ir.symbols.areEqualByValue.single { it.descriptor.valueParameters[0].type == nativePtrType } val nativePtrEqualityOperatorSymbol = context.ir.symbols.areEqualByValue.single { it.descriptor.valueParameters[0].type == nativePtrType }
val optimize = context.config.configuration.get(KonanConfigKeys.OPTIMIZATION) ?: false
irModule.transformChildrenVoid(object: IrElementTransformerVoidWithContext() { irModule.transformChildrenVoid(object: IrElementTransformerVoidWithContext() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
@@ -934,7 +935,7 @@ internal object Devirtualization {
+nullConst(expression, type) +nullConst(expression, type)
} }
possibleCallees.size == 1 -> { // Monomorphic callsite. optimize && possibleCallees.size == 1 -> { // Monomorphic callsite.
val actualCallee = possibleCallees[0].callee as DataFlowIR.FunctionSymbol.Declared val actualCallee = possibleCallees[0].callee as DataFlowIR.FunctionSymbol.Declared
irDevirtualizedCall(expression, type, actualCallee).apply { irDevirtualizedCall(expression, type, actualCallee).apply {
this.dispatchReceiver = dispatchReceiver this.dispatchReceiver = dispatchReceiver
@@ -953,46 +954,63 @@ internal object Devirtualization {
putValueArgument(0, irGet(receiver.symbol)) putValueArgument(0, irGet(receiver.symbol))
}) })
val branches = possibleCallees.mapIndexed { index, devirtualizedCallee -> val branches = mutableListOf<IrBranchImpl>()
possibleCallees.mapIndexedTo(branches) { index, devirtualizedCallee ->
val actualCallee = devirtualizedCallee.callee as DataFlowIR.FunctionSymbol.Declared val actualCallee = devirtualizedCallee.callee as DataFlowIR.FunctionSymbol.Declared
val actualReceiverType = devirtualizedCallee.receiverType as DataFlowIR.Type.Declared val actualReceiverType = devirtualizedCallee.receiverType as DataFlowIR.Type.Declared
val expectedTypeInfo = IrPrivateClassReferenceImpl( val expectedTypeInfo = IrPrivateClassReferenceImpl(
startOffset, startOffset = startOffset,
endOffset, endOffset = endOffset,
nativePtrType, type = nativePtrType,
IrClassSymbolImpl(dispatchReceiver.type.getErasedTypeClass()), symbol = IrClassSymbolImpl(dispatchReceiver.type.getErasedTypeClass()),
receiver.type, classType = receiver.type,
actualReceiverType.module!!.descriptor, moduleDescriptor = actualReceiverType.module!!.descriptor,
actualReceiverType.module.numberOfClasses, totalClasses = actualReceiverType.module.numberOfClasses,
actualReceiverType.symbolTableIndex) classIndex = actualReceiverType.symbolTableIndex)
val condition = val condition =
if (index == possibleCallees.size - 1) if (optimize && index == possibleCallees.size - 1)
irTrue() irTrue() // Don't check last type in optimize mode.
else else
irCall(nativePtrEqualityOperatorSymbol).apply { irCall(nativePtrEqualityOperatorSymbol).apply {
putValueArgument(0, irGet(typeInfo.symbol)) putValueArgument(0, irGet(typeInfo.symbol))
putValueArgument(1, expectedTypeInfo) putValueArgument(1, expectedTypeInfo)
} }
IrBranchImpl( IrBranchImpl(
startOffset, startOffset = startOffset,
endOffset, endOffset = endOffset,
condition, condition = condition,
irDevirtualizedCall(expression, type, actualCallee).apply { result = irDevirtualizedCall(expression, type, actualCallee).apply {
this.dispatchReceiver = irGet(receiver.symbol) this.dispatchReceiver = irGet(receiver.symbol)
this.extensionReceiver = extensionReceiver?.let { irGet(it.symbol) } this.extensionReceiver = extensionReceiver?.let { irGet(it.symbol) }
expression.descriptor.valueParameters.forEach { expression.descriptor.valueParameters.forEach {
this.putValueArgument(it.index, irGet(parameters[it]!!.symbol)) putValueArgument(it.index, irGet(parameters[it]!!.symbol))
} }
} }
) )
} }
if (!optimize) { // Add else branch throwing exception for debug purposes.
branches.add(IrBranchImpl(
startOffset = startOffset,
endOffset = endOffset,
condition = irTrue(),
result = irCall(context.ir.symbols.throwInvalidReceiverTypeException).apply {
putValueArgument(0,
irCall(context.ir.symbols.kClassImplConstructor,
listOf(dispatchReceiver.type)
).apply {
putValueArgument(0, irGet(typeInfo.symbol))
}
)
})
)
}
+IrWhenImpl( +IrWhenImpl(
startOffset, startOffset = startOffset,
endOffset, endOffset = endOffset,
type, type = type,
expression.origin, origin = expression.origin,
branches branches = branches
) )
} }
} }
@@ -1002,15 +1020,15 @@ internal object Devirtualization {
fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: KotlinType, fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: KotlinType,
devirtualizedCallee: DataFlowIR.FunctionSymbol.Declared) = devirtualizedCallee: DataFlowIR.FunctionSymbol.Declared) =
IrPrivateFunctionCallImpl( IrPrivateFunctionCallImpl(
startOffset, startOffset = startOffset,
endOffset, endOffset = endOffset,
actualType, type = actualType,
callee.symbol, symbol = callee.symbol,
callee.descriptor, descriptor = callee.descriptor,
(callee as? IrCallImpl)?.typeArguments, typeArguments = (callee as? IrCallImpl)?.typeArguments,
devirtualizedCallee.module.descriptor, moduleDescriptor = devirtualizedCallee.module.descriptor,
devirtualizedCallee.module.numberOfFunctions, totalFunctions = devirtualizedCallee.module.numberOfFunctions,
devirtualizedCallee.symbolTableIndex functionIndex = devirtualizedCallee.symbolTableIndex
) )
}) })