Allow intrinsics to be partial

Also, add an overridable invoke() method that skips the Callable step.
This commit is contained in:
pyos
2019-03-28 15:18:59 +01:00
committed by max-kammerer
parent 6e44b22340
commit a9bece9baa
6 changed files with 60 additions and 104 deletions
@@ -7,9 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.common.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicFunction
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
import org.jetbrains.kotlin.backend.jvm.lower.JvmBuiltinOptimizationLowering.Companion.isNegation
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.*
@@ -115,6 +113,8 @@ class ExpressionCodegen(
val typeMapper = classCodegen.typeMapper
val context = classCodegen.context
private val state = classCodegen.state
private val fileEntry = classCodegen.context.psiSourceManager.getFileEntry(irFunction.fileParent)
@@ -307,7 +307,7 @@ class ExpressionCodegen(
return visitStatementContainer(expression, data).coerce(expression.type)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression, data: BlockInfo): StackValue {
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: BlockInfo): StackValue {
expression.markLineNumber(startOffset = true)
return generateCall(expression, null, data)
}
@@ -346,14 +346,12 @@ class ExpressionCodegen(
return generateCall(expression, expression.superQualifier, data)
}
private fun generateCall(expression: IrMemberAccessExpression, superQualifier: ClassDescriptor?, data: BlockInfo): StackValue {
private fun generateCall(expression: IrFunctionAccessExpression, superQualifier: ClassDescriptor?, data: BlockInfo): StackValue {
classCodegen.context.irIntrinsics.getIntrinsic(expression.descriptor.original as CallableMemberDescriptor)
?.invoke(expression, this, data)?.let { return it }
val isSuperCall = superQualifier != null
val callable = resolveToCallable(expression, isSuperCall)
return if (callable is IrIntrinsicFunction) {
callable.invoke(mv, this, data)
} else {
generateCall(expression, callable, data, isSuperCall)
}
return generateCall(expression, callable, data, isSuperCall)
}
fun generateCall(expression: IrMemberAccessExpression, callable: Callable, data: BlockInfo, isSuperCall: Boolean = false): StackValue {
@@ -1085,15 +1083,6 @@ class ExpressionCodegen(
}
private fun resolveToCallable(irCall: IrMemberAccessExpression, isSuper: Boolean): Callable {
val intrinsic = classCodegen.context.irIntrinsics.getIntrinsic(irCall.descriptor.original as CallableMemberDescriptor)
if (intrinsic != null) {
return intrinsic.toCallable(
irCall,
typeMapper.mapSignatureSkipGeneric(irCall.descriptor as FunctionDescriptor),
classCodegen.context
)
}
var descriptor = irCall.descriptor
if (descriptor is TypeAliasConstructorDescriptor) {
//TODO where is best to unwrap?
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.AsmUtil.comparisonOperandType
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -66,24 +67,14 @@ class PrimitiveComparison(
private val primitiveNumberType: KotlinType,
private val operatorToken: KtSingleValueToken
) : IntrinsicMethod() {
override fun toCallable(
expression: IrMemberAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction {
val parameterType = context.state.typeMapper.mapType(primitiveNumberType)
return object : IrIntrinsicFunction(expression, signature, context, listOf(parameterType, parameterType)) {
override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue {
loadArguments(codegen, data)
return StackValue.cmp(
operatorToken,
parameterType,
StackValue.onStack(parameterType, primitiveNumberType),
StackValue.onStack(parameterType, primitiveNumberType)
)
}
}
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): StackValue? {
val parameterType = codegen.typeMapper.mapType(primitiveNumberType)
val (left, right) = expression.receiverAndArgs()
return StackValue.cmp(
operatorToken,
parameterType,
codegen.gen(left, parameterType, data),
codegen.gen(right, parameterType, data)
)
}
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.AsmUtil.*
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.types.toKotlinType
@@ -27,40 +28,27 @@ import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class Equals(val operator: IElementType) : IntrinsicMethod() {
override fun toCallable(
expression: IrMemberAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction {
val receiverAndArgs = expression.receiverAndArgs().apply {
assert(size == 2) { "Equals expects 2 arguments, but ${joinToString()}" }
}
val (leftArg, rightArg) = receiverAndArgs
var leftType = context.state.typeMapper.mapType(leftArg.type.toKotlinType())
var rightType = context.state.typeMapper.mapType(rightArg.type.toKotlinType())
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): StackValue? {
val (leftArg, rightArg) = expression.receiverAndArgs()
var leftType = codegen.typeMapper.mapType(leftArg.type.toKotlinType())
var rightType = codegen.typeMapper.mapType(rightArg.type.toKotlinType())
if (isPrimitive(leftType) != isPrimitive(rightType)) {
leftType = boxType(leftType)
rightType = boxType(rightType)
}
return object : IrIntrinsicFunction(expression, signature, context, listOf(leftType, rightType)) {
override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue {
val opToken = expression.origin
return if (leftArg.isNullConst() || rightArg.isNullConst()) {
val other = if (leftArg.isNullConst()) rightArg else leftArg
StackValue.compareWithNull(other.accept(codegen, data), Opcodes.IFNONNULL)
} else if (leftType.isFloatingPoint && rightType.isFloatingPoint) {
genEqualsBoxedOnStack(operator)
} else if (opToken === IrStatementOrigin.EQEQEQ || opToken === IrStatementOrigin.EXCLEQEQ) {
// TODO: always casting to the type of the left operand in case of primitives looks wrong
val operandType = if (isPrimitive(leftType)) leftType else OBJECT_TYPE
StackValue.cmp(operator, operandType, codegen.gen(leftArg, operandType, data), codegen.gen(rightArg, operandType, data))
} else {
genEqualsForExpressionsOnStack(operator, codegen.gen(leftArg, leftType, data), codegen.gen(rightArg, rightType, data))
}
}
val opToken = expression.origin
return if (leftArg.isNullConst() || rightArg.isNullConst()) {
val other = if (leftArg.isNullConst()) rightArg else leftArg
return StackValue.compareWithNull(other.accept(codegen, data), Opcodes.IFNONNULL)
} else if (leftType.isFloatingPoint && rightType.isFloatingPoint) {
genEqualsBoxedOnStack(operator)
} else if (opToken === IrStatementOrigin.EQEQEQ || opToken === IrStatementOrigin.EXCLEQEQ) {
// TODO: always casting to the type of the left operand in case of primitives looks wrong
val operandType = if (isPrimitive(leftType)) leftType else OBJECT_TYPE
StackValue.cmp(operator, operandType, codegen.gen(leftArg, operandType, data), codegen.gen(rightArg, operandType, data))
} else {
genEqualsForExpressionsOnStack(operator, codegen.gen(leftArg, leftType, data), codegen.gen(rightArg, rightType, data))
}
}
@@ -122,3 +110,4 @@ class Ieee754Equals(val operandType: Type) : IntrinsicMethod() {
}
}
}
@@ -6,7 +6,12 @@
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -14,11 +19,18 @@ import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method
abstract class IntrinsicMethod {
abstract fun toCallable(
open fun toCallable(
expression: IrMemberAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction
): IrIntrinsicFunction = TODO("implement toCallable() or invoke() of $this")
open fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): StackValue? =
toCallable(
expression,
codegen.typeMapper.mapSignatureSkipGeneric(expression.descriptor),
codegen.context
).invoke(codegen.mv, codegen, data)
companion object {
fun calcReceiverType(call: IrMemberAccessExpression, context: JvmBackendContext): Type {
@@ -16,31 +16,20 @@
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrGetClass
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class KClassJavaProperty : IntrinsicMethod() {
override fun toCallable(expression: IrMemberAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction {
return object: IrIntrinsicFunction(expression, signature, context) {
override fun invoke(v: InstructionAdapter, codegen: org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen, data: BlockInfo): StackValue {
val extensionReceiver = expression.extensionReceiver
if (extensionReceiver is IrClassReference || extensionReceiver is IrGetClass) {
codegen.generateClassLiteralReference(extensionReceiver, false, data)
}
else {
codegen.gen(extensionReceiver!!, data)
val mapToCallableMethod = context.state.typeMapper.mapToCallableMethod(expression.descriptor as FunctionDescriptor, false)
mapToCallableMethod.genInvokeInstruction(codegen.mv)
}
return StackValue.onStack(signature.returnType)
}
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): StackValue? {
val extensionReceiver = expression.extensionReceiver
if (extensionReceiver !is IrClassReference && extensionReceiver !is IrGetClass) {
return null
}
codegen.generateClassLiteralReference(extensionReceiver, false, data)
return with(codegen) { expression.onStack }
}
}
@@ -16,26 +16,12 @@
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
class Not : IntrinsicMethod() {
override fun toCallable(
expression: IrMemberAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction {
return object : IrIntrinsicFunction(expression, signature, context, expression.argTypes(context)) {
override fun invoke(
v: InstructionAdapter,
codegen: ExpressionCodegen,
data: BlockInfo
) = StackValue.not(expression.dispatchReceiver!!.accept(codegen, data))
}
}
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo) =
StackValue.not(expression.dispatchReceiver!!.accept(codegen, data))
}