Allow intrinsics to be partial
Also, add an overridable invoke() method that skips the Callable step.
This commit is contained in:
+7
-18
@@ -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?
|
||||
|
||||
+10
-19
@@ -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() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -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 {
|
||||
|
||||
+8
-19
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user