JVM IR: Remove vararg handling from ExpressionCodegen

This commit is contained in:
Steven Schäfer
2019-08-06 11:38:46 +02:00
committed by max-kammerer
parent 4d8d65abec
commit 1543accf40
4 changed files with 28 additions and 163 deletions
@@ -352,27 +352,27 @@ class ExpressionCodegen(
} }
expression.descriptor is ConstructorDescriptor -> expression.descriptor is ConstructorDescriptor ->
throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}") throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}")
callee.isSuspend && !irFunction.isInvokeSuspendInContinuation() -> addInlineMarker(mv, isStartNotEnd = true) callee.isSuspend && !irFunction.isInvokeSuspendInContinuation() ->
addInlineMarker(mv, isStartNotEnd = true)
} }
val receiver = expression.dispatchReceiver expression.dispatchReceiver?.let { receiver ->
receiver?.apply {
callGenerator.genValueAndPut( callGenerator.genValueAndPut(
callee.dispatchReceiverParameter!!, callee.dispatchReceiverParameter!!,
this, receiver,
if (isSuperCall) receiver.asmType else callable.dispatchReceiverType if (isSuperCall) receiver.asmType else callable.dispatchReceiverType
?: throw AssertionError("No dispatch receiver type: ${expression.render()}"), ?: throw AssertionError("No dispatch receiver type: ${expression.render()}"),
this@ExpressionCodegen, this,
data data
) )
} }
expression.extensionReceiver?.apply { expression.extensionReceiver?.let { receiver ->
callGenerator.genValueAndPut( callGenerator.genValueAndPut(
callee.extensionReceiverParameter!!, callee.extensionReceiverParameter!!,
this, receiver,
callable.extensionReceiverType!!, callable.extensionReceiverType!!,
this@ExpressionCodegen, this,
data data
) )
} }
@@ -381,25 +381,8 @@ class ExpressionCodegen(
expression.symbol.owner.valueParameters.forEachIndexed { i, irParameter -> expression.symbol.owner.valueParameters.forEachIndexed { i, irParameter ->
val arg = expression.getValueArgument(i) val arg = expression.getValueArgument(i)
val parameterType = callable.valueParameterTypes[i] val parameterType = callable.valueParameterTypes[i]
when { require(arg != null) { "Null argument in ExpressionCodegen for parameter ${irParameter.render()}" }
arg != null -> { callGenerator.genValueAndPut(irParameter, arg, parameterType, this, data)
callGenerator.genValueAndPut(irParameter, arg, parameterType, this@ExpressionCodegen, data)
}
else -> {
assert(irParameter.varargElementType != null)
val type = typeMapper.mapType(
irParameter.type.substitute(typeSubstitutionMap)
)
callGenerator.putValueIfNeeded(
parameterType,
StackValue.operation(type) {
it.aconst(0)
it.newarray(correctElementType(type))
},
ValueKind.GENERAL_VARARG, i, this@ExpressionCodegen
)
}
}
} }
expression.markLineNumber(true) expression.markLineNumber(true)
@@ -409,19 +392,14 @@ class ExpressionCodegen(
addSuspendMarker(mv, isStartNotEnd = true) addSuspendMarker(mv, isStartNotEnd = true)
} }
callGenerator.genCall( callGenerator.genCall(callable, this, expression)
callable,
this,
expression
)
val returnType = callee.returnType
if (callee.isSuspend && !irFunction.isInvokeSuspendInContinuation()) { if (callee.isSuspend && !irFunction.isInvokeSuspendInContinuation()) {
addSuspendMarker(mv, isStartNotEnd = false) addSuspendMarker(mv, isStartNotEnd = false)
addInlineMarker(mv, isStartNotEnd = false) addInlineMarker(mv, isStartNotEnd = false)
} }
val returnType = callee.returnType
return when { return when {
returnType.substitute(expression.typeSubstitutionMap).isNothing() -> { returnType.substitute(expression.typeSubstitutionMap).isNothing() -> {
mv.aconst(null) mv.aconst(null)
@@ -581,101 +559,6 @@ class ExpressionCodegen(
return immaterialUnitValue return immaterialUnitValue
} }
override fun visitVararg(expression: IrVararg, data: BlockInfo): PromisedValue {
expression.markLineNumber(startOffset = true)
val outType = expression.type
val type = expression.asmType
assert(type.sort == Type.ARRAY)
val elementType = correctElementType(type)
val arguments = expression.elements
val size = arguments.size
val hasSpread = arguments.firstIsInstanceOrNull<IrSpreadElement>() != null
if (hasSpread) {
val arrayOfReferences = outType.makeNotNull().isArray()
if (size == 1) {
// Arrays.copyOf(receiverValue, newLength)
val argument = (arguments[0] as IrSpreadElement).expression
val arrayType = if (arrayOfReferences)
Type.getType("[Ljava/lang/Object;")
else
Type.getType("[" + elementType.descriptor)
argument.accept(this, data).coerce(type, argument.type).materialize()
mv.dup()
mv.arraylength()
mv.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false)
if (arrayOfReferences) {
mv.checkcast(type)
}
} else {
val owner: String
val addDescriptor: String
val toArrayDescriptor: String
if (arrayOfReferences) {
owner = "kotlin/jvm/internal/SpreadBuilder"
addDescriptor = "(Ljava/lang/Object;)V"
toArrayDescriptor = "([Ljava/lang/Object;)[Ljava/lang/Object;"
} else {
val spreadBuilderClassName =
asmPrimitiveTypeToLangPrimitiveType(elementType)!!.typeName.identifier + "SpreadBuilder"
owner = "kotlin/jvm/internal/$spreadBuilderClassName"
addDescriptor = "(" + elementType.descriptor + ")V"
toArrayDescriptor = "()" + type.descriptor
}
mv.anew(Type.getObjectType(owner))
mv.dup()
mv.iconst(size)
mv.invokespecial(owner, "<init>", "(I)V", false)
for (i in 0 until size) {
mv.dup()
val argument = arguments[i]
if (argument is IrSpreadElement) {
argument.expression.accept(this, data).coerce(OBJECT_TYPE, argument.expression.type).materialize()
mv.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false)
} else {
argument.accept(this, data).coerce(elementType, expression.varargElementType).materialize()
mv.invokevirtual(owner, "add", addDescriptor, false)
}
}
if (arrayOfReferences) {
mv.dup()
mv.invokevirtual(owner, "size", "()I", false)
newArrayInstruction(outType)
mv.invokevirtual(owner, "toArray", toArrayDescriptor, false)
mv.checkcast(type)
} else {
mv.invokevirtual(owner, "toArray", toArrayDescriptor, false)
}
}
} else {
mv.iconst(size)
newArrayInstruction(expression.type)
for ((i, element) in expression.elements.withIndex()) {
mv.dup()
mv.iconst(i)
element.accept(this, data).coerce(elementType, expression.varargElementType).materialize()
mv.astore(elementType)
}
}
return expression.onStack
}
fun newArrayInstruction(arrayType: IrType) {
if (arrayType.isArray()) {
val elementIrType = arrayType.safeAs<IrSimpleType>()!!.arguments[0].safeAs<IrTypeProjection>()!!.type
putReifiedOperationMarkerIfTypeIsReifiedParameter(
elementIrType,
ReifiedTypeInliner.OperationKind.NEW_ARRAY,
mv,
this
)
mv.newarray(typeMapper.boxType(elementIrType))
} else {
mv.newarray(correctElementType(arrayType.asmType))
}
}
override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue { override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue {
val returnTarget = expression.returnTargetSymbol.owner val returnTarget = expression.returnTargetSymbol.owner
val owner = val owner =
@@ -1224,7 +1107,7 @@ class ExpressionCodegen(
} }
/* From ExpressionCodegen.java */ /* From ExpressionCodegen.java */
private fun putReifiedOperationMarkerIfTypeIsReifiedParameter( fun putReifiedOperationMarkerIfTypeIsReifiedParameter(
type: IrType, operationKind: ReifiedTypeInliner.OperationKind, v: InstructionAdapter, type: IrType, operationKind: ReifiedTypeInliner.OperationKind, v: InstructionAdapter,
codegen: ExpressionCodegen? codegen: ExpressionCodegen?
) { ) {
@@ -1,29 +0,0 @@
/*
* Copyright 2010-2016 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.
*/
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
object ArrayOf : IntrinsicMethod() {
override fun toCallable(expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction {
return IrIntrinsicFunction.create(expression, signature, context, signature.returnType) {
//do nothing all generated as vararg
}
}
}
@@ -70,7 +70,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
"isArrayOf", "isArrayOf",
emptyList() emptyList()
) to IsArrayOf, ) to IsArrayOf,
symbols.arrayOf.toKey() to ArrayOf,
Key( Key(
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
KotlinBuiltIns.FQ_NAMES.any.toSafe(), KotlinBuiltIns.FQ_NAMES.any.toSafe(),
@@ -113,7 +112,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
unaryFunForPrimitives("hashCode", HashCode) + unaryFunForPrimitives("hashCode", HashCode) +
unaryFunForPrimitives("toString", ToString) + unaryFunForPrimitives("toString", ToString) +
binaryFunForPrimitives("equals", EQUALS, irBuiltIns.anyClass) + binaryFunForPrimitives("equals", EQUALS, irBuiltIns.anyClass) +
symbols.primitiveArrayOfByType.values.map { it.toKey() to ArrayOf } +
binaryFunForPrimitivesAcrossPrimitives("rangeTo", RangeTo) + binaryFunForPrimitivesAcrossPrimitives("rangeTo", RangeTo) +
binaryOp("plus", IADD) + binaryOp("plus", IADD) +
binaryOp("minus", ISUB) + binaryOp("minus", ISUB) +
@@ -8,13 +8,26 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue
import org.jetbrains.kotlin.backend.jvm.ir.getArrayElementType
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
object NewArray : IntrinsicMethod() { object NewArray : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
codegen.gen(expression.getValueArgument(0)!!, Type.INT_TYPE, codegen.context.irBuiltIns.intType, data) codegen.gen(expression.getValueArgument(0)!!, Type.INT_TYPE, codegen.context.irBuiltIns.intType, data)
codegen.newArrayInstruction(expression.type) return with(codegen) {
return with(codegen) { expression.onStack } val elementIrType = expression.type.getArrayElementType(context.irBuiltIns)
if (expression.type.isArray()) {
putReifiedOperationMarkerIfTypeIsReifiedParameter(
elementIrType, ReifiedTypeInliner.OperationKind.NEW_ARRAY, mv, this
)
mv.newarray(typeMapper.boxType(elementIrType))
} else {
mv.newarray(typeMapper.mapType(elementIrType))
}
expression.onStack
}
} }
} }