JVM_IR: Fix default argument bit mask for methods made static.
When called by reflection the bit mask will be generated discounting dispatch/extension receivers. Make sure that the interpretation of the bit mask is consistent for direct and reflective calls. In addition, this also fixes the modifiers on java 8 parameter metadata for the dispatch and extension receivers for these inline class methods.
This commit is contained in:
@@ -582,13 +582,13 @@ fun createStaticFunctionWithReceivers(
|
||||
name = Name.identifier("this"),
|
||||
index = offset++,
|
||||
type = dispatchReceiverType!!,
|
||||
origin = IrDeclarationOrigin.MOVED_RECEIVER_PARAMETER
|
||||
origin = IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
|
||||
)
|
||||
val extensionReceiver = oldFunction.extensionReceiverParameter?.copyTo(
|
||||
this,
|
||||
name = Name.identifier("receiver"),
|
||||
index = offset++,
|
||||
origin = IrDeclarationOrigin.MOVED_RECEIVER_PARAMETER
|
||||
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
|
||||
)
|
||||
valueParameters.addAll(listOfNotNull(dispatchReceiver, extensionReceiver) +
|
||||
oldFunction.valueParameters.map { it.copyTo(this, index = it.index + offset) }
|
||||
|
||||
+13
-2
@@ -85,11 +85,15 @@ open class DefaultArgumentStubGenerator(
|
||||
newIrFunction.valueParameters[it.index]
|
||||
}
|
||||
|
||||
var sourceParameterIndex = -1
|
||||
for (valueParameter in irFunction.valueParameters) {
|
||||
if (!valueParameter.isMovedReceiver()) {
|
||||
++sourceParameterIndex
|
||||
}
|
||||
val parameter = newIrFunction.valueParameters[valueParameter.index]
|
||||
val remapped = if (valueParameter.defaultValue != null) {
|
||||
val mask = irGet(newIrFunction.valueParameters[irFunction.valueParameters.size + valueParameter.index / 32])
|
||||
val bit = irInt(1 shl (valueParameter.index % 32))
|
||||
val bit = irInt(1 shl (sourceParameterIndex % 32))
|
||||
val defaultFlag = irCallOp(this@DefaultArgumentStubGenerator.context.ir.symbols.intAnd, context.irBuiltIns.intType, mask, bit)
|
||||
|
||||
val expressionBody = valueParameter.defaultValue!!
|
||||
@@ -289,14 +293,18 @@ open class DefaultParameterInjector(
|
||||
"argument count mismatch: expected $realArgumentsNumber arguments + ${maskValues.size} masks + optional handler/marker, " +
|
||||
"got ${stubFunction.valueParameters.size} total in ${stubFunction.render()}"
|
||||
}
|
||||
var sourceParameterIndex = -1
|
||||
return stubFunction.symbol to stubFunction.valueParameters.mapIndexed { i, parameter ->
|
||||
if (!parameter.isMovedReceiver()) {
|
||||
++sourceParameterIndex
|
||||
}
|
||||
when {
|
||||
i >= realArgumentsNumber + maskValues.size -> IrConstImpl.constNull(startOffset, endOffset, parameter.type)
|
||||
i >= realArgumentsNumber -> IrConstImpl.int(startOffset, endOffset, parameter.type, maskValues[i - realArgumentsNumber])
|
||||
else -> {
|
||||
val valueArgument = expression.getValueArgument(i)
|
||||
if (valueArgument == null) {
|
||||
maskValues[i / 32] = maskValues[i / 32] or (1 shl (i % 32))
|
||||
maskValues[i / 32] = maskValues[i / 32] or (1 shl (sourceParameterIndex % 32))
|
||||
}
|
||||
valueArgument ?: nullConst(startOffset, endOffset, parameter)?.let {
|
||||
IrCompositeImpl(
|
||||
@@ -440,3 +448,6 @@ private fun IrFunction.generateDefaultsFunctionImpl(
|
||||
annotations.mapTo(newFunction.annotations) { it.deepCopyWithSymbols() }
|
||||
return newFunction
|
||||
}
|
||||
|
||||
private fun IrValueParameter.isMovedReceiver() =
|
||||
origin == IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER || origin == IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
|
||||
|
||||
+2
-1
@@ -307,7 +307,8 @@ private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jv
|
||||
irParameter.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> Opcodes.ACC_MANDATED
|
||||
// TODO mark these backend-common origins as synthetic? (note: ExpressionCodegen is still expected
|
||||
// to generate LVT entries for them)
|
||||
irParameter.origin == IrDeclarationOrigin.MOVED_RECEIVER_PARAMETER -> Opcodes.ACC_SYNTHETIC
|
||||
irParameter.origin == IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER -> Opcodes.ACC_MANDATED
|
||||
irParameter.origin == IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER -> Opcodes.ACC_SYNTHETIC
|
||||
irParameter.origin == BOUND_VALUE_PARAMETER -> Opcodes.ACC_SYNTHETIC
|
||||
irParameter.origin == BOUND_RECEIVER_PARAMETER -> Opcodes.ACC_SYNTHETIC
|
||||
irParameter.origin.isSynthetic -> Opcodes.ACC_SYNTHETIC
|
||||
|
||||
+6
-2
@@ -182,8 +182,12 @@ class MemoizedInlineClassReplacements {
|
||||
function.extensionReceiverParameter -> Name.identifier("\$receiver")
|
||||
else -> parameter.name
|
||||
}
|
||||
|
||||
val newParameter = parameter.copyTo(this, index = index, name = name, defaultValue = null)
|
||||
val parameterOrigin = when (parameter) {
|
||||
function.dispatchReceiverParameter -> IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER
|
||||
function.extensionReceiverParameter -> IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
|
||||
else -> parameter.origin
|
||||
}
|
||||
val newParameter = parameter.copyTo(this, index = index, name = name, defaultValue = null, origin = parameterOrigin)
|
||||
valueParameters.add(newParameter)
|
||||
// See comment next to a similar line above.
|
||||
newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
|
||||
|
||||
@@ -32,7 +32,8 @@ interface IrDeclarationOrigin {
|
||||
object MASK_FOR_DEFAULT_FUNCTION : IrDeclarationOriginImpl("MASK_FOR_DEFAULT_FUNCTION", isSynthetic = true)
|
||||
object DEFAULT_CONSTRUCTOR_MARKER : IrDeclarationOriginImpl("DEFAULT_CONSTRUCTOR_MARKER", isSynthetic = true)
|
||||
object METHOD_HANDLER_IN_DEFAULT_FUNCTION : IrDeclarationOriginImpl("METHOD_HANDLER_IN_DEFAULT_FUNCTION", isSynthetic = true)
|
||||
object MOVED_RECEIVER_PARAMETER : IrDeclarationOriginImpl("MOVED_RECEIVER_PARAMETER")
|
||||
object MOVED_DISPATCH_RECEIVER : IrDeclarationOriginImpl("MOVED_DISPATCH_RECEIVER")
|
||||
object MOVED_EXTENSION_RECEIVER : IrDeclarationOriginImpl("MOVED_EXTENSION_RECEIVER")
|
||||
|
||||
object FILE_CLASS : IrDeclarationOriginImpl("FILE_CLASS")
|
||||
object GENERATED_DATA_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_DATA_CLASS_MEMBER")
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// SKIP_JDK6
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.PARAMETERS_METADATA
|
||||
|
||||
// FILE: A.kt
|
||||
|
||||
inline class A(val i: Int) {
|
||||
fun f() = i
|
||||
}
|
||||
|
||||
fun A.extension() = this.i
|
||||
|
||||
fun box(): String {
|
||||
val method = Class.forName("A").declaredMethods.single { it.name == "f-impl" }
|
||||
val parameters = method.getParameters()
|
||||
if (!parameters[0].isSynthetic()) return "wrong modifier on receiver parameter: ${parameters[0].modifiers}"
|
||||
|
||||
val extensionMethod = Class.forName("AKt").declaredMethods.single { it.name.contains("extension") }
|
||||
val extensionMethodParameters = extensionMethod.getParameters()
|
||||
if (extensionMethodParameters[0].isSynthetic())
|
||||
return "wrong modifier (synthetic) on extension receiver parameter: ${extensionMethodParameters[0].modifiers}"
|
||||
if (!extensionMethodParameters[0].isImplicit())
|
||||
return "wrong modifier (not implicit) on extension receiver parameter: ${extensionMethodParameters[0].modifiers}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// SKIP_JDK6
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.PARAMETERS_METADATA
|
||||
|
||||
// FILE: A.kt
|
||||
|
||||
inline class A(val i: Int) {
|
||||
fun f() = i
|
||||
}
|
||||
|
||||
fun A.extension() = this.i
|
||||
|
||||
fun box(): String {
|
||||
val method = Class.forName("A").declaredMethods.single { it.name == "f-impl" }
|
||||
val parameters = method.getParameters()
|
||||
if (parameters[0].name != "arg0") return "wrong name on receiver parameter: ${parameters[0].name}"
|
||||
|
||||
val extensionMethod = Class.forName("AKt").declaredMethods.single { it.name.contains("extension") }
|
||||
val extensionMethodParameters = extensionMethod.getParameters()
|
||||
if (extensionMethodParameters[0].name != "\$this\$extension")
|
||||
return "wrong name on extension receiver parameter: ${extensionMethodParameters[0].name}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
@@ -23,17 +23,19 @@ class D(e: S, f: S = S("f")) {
|
||||
fun S.extension(h: S = S("h")): S = this + h
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(S("ab"), C().member(S("a")))
|
||||
assertEquals(S("ab"), C::member.callBy(C::member.parameters.filter { it.name != "b" }.associate {
|
||||
it to (if (it.name == "a") S("a") else C())
|
||||
}))
|
||||
|
||||
assertEquals(S("cd"), topLevel(S("c")))
|
||||
assertEquals(S("cd"), ::topLevel.callBy(::topLevel.parameters.filter { it.name != "d" }.associate { it to S("c") }))
|
||||
|
||||
// assertEquals(S("ef"), ::D.callBy(::D.parameters.filter { it.name != "f" }.associate { it to S("e") }).result)
|
||||
|
||||
assertEquals(S("gh"), S("g").extension())
|
||||
assertEquals(S("gh"), S::extension.callBy(S::extension.parameters.filter { it.name != "h" }.associate { it to S("g") }))
|
||||
|
||||
|
||||
val boundMember = C()::member
|
||||
assertEquals(S("ab"), boundMember.callBy(boundMember.parameters.associate { it to S(it.name!!) }))
|
||||
|
||||
|
||||
+10
@@ -18571,6 +18571,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/function.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterModifiers.kt")
|
||||
public void testInlineClassMethodParameterModifiers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterNames.kt")
|
||||
public void testInlineClassMethodParameterNames() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerClass.kt")
|
||||
public void testInnerClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt");
|
||||
|
||||
+10
@@ -18571,6 +18571,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/function.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterModifiers.kt")
|
||||
public void testInlineClassMethodParameterModifiers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterNames.kt")
|
||||
public void testInlineClassMethodParameterNames() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerClass.kt")
|
||||
public void testInnerClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt");
|
||||
|
||||
+10
@@ -17055,6 +17055,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/function.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterModifiers.kt")
|
||||
public void testInlineClassMethodParameterModifiers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterNames.kt")
|
||||
public void testInlineClassMethodParameterNames() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerClass.kt")
|
||||
public void testInnerClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt");
|
||||
|
||||
+10
@@ -17055,6 +17055,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/function.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterModifiers.kt")
|
||||
public void testInlineClassMethodParameterModifiers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterModifiers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMethodParameterNames.kt")
|
||||
public void testInlineClassMethodParameterNames() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/inlineClassMethodParameterNames.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("innerClass.kt")
|
||||
public void testInnerClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/parametersMetadata/innerClass.kt");
|
||||
|
||||
Reference in New Issue
Block a user