https://kotlinlang.org logo
r

raulraja

03/23/2020, 1:53 PM
Hi!, When generating code with IR which seems ok in 1.3.61 it produces binaries that when loaded at runtime result in this kinds of exceptions related to
kotlin.internal.ir.Intrinsic
. I suppose this is an issue in code generation and not that I actually need an IR runtime to run that code and it’s missing as dependency. Is that the case? Or does anyone else know where this may be coming from? Any help is appreciated, thanks!
Copy code
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/internal/ir/Intrinsic
	at consumer.MainKt.<clinit>(main.kt:5)
Caused by: java.lang.ClassNotFoundException: kotlin.internal.ir.Intrinsic
	at <http://java.net|java.net>.URLClassLoader.findClass(URLClassLoader.java:382)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 1 more
s

shikasd

03/23/2020, 3:02 PM
I remember seeing something like that when I tried to generate a function directly in an
IrFile
some time ago. Maybe it is related.
r

raulraja

03/25/2020, 5:04 PM
I checked and we are not generating functions just inserting calls which are resolved in IR correctly
s

shikasd

03/25/2020, 5:49 PM
@raulraja Do you know which calls got replaced with intrinsic? From bytecode for example
r

raulraja

03/25/2020, 6:18 PM
In the case where it works it generates :
Copy code
2: invokestatic  #48                 // Method twitterHandle:(Ljava/lang/String;)Ltest/TwitterHandle;
And in the case it doesn’t it generates:
Copy code
2: invokestatic  #50                 // Method kotlin/internal/ir/Intrinsic.twitterHandle:(Ljava/lang/String;)Ltest/TwitterHandle;
so it thinks the
twitterHandle
functions is inside a class called
kotlin/internal/ir/Intrinsic
But the IR tree is the same in both cases
Copy code
PROPERTY name:x visibility:public modality:FINAL [val]
    FIELD PROPERTY_BACKING_FIELD name:x type:test.TwitterHandle? visibility:private [final,static]
      EXPRESSION_BODY
        CALL 'public final fun twitterHandle (): test.TwitterHandle? declared in test' type=test.TwitterHandle? origin=null
          $receiver: CONST String type=kotlin.String value="@admin"
I think I’m missing some button I need to push but I’m weirded out that given the same IR tree it generates different bytecode
s

shikasd

03/25/2020, 6:41 PM
I did a quick research on that yesterday, so what I found is:
Copy code
companion object {
    val FAKE_OWNER_TYPE = Type.getObjectType("kotlin/internal/ir/Intrinsic")
}
No other mentions of that guy anywhere else
Essentially it cannot find a class which is a method owner, maybe you are referencing the function before it gets wrapped into class?
Also run a debugger on your example and it gets into this branch. Apparently the method you are referencing still has PackageFragment as a parent 🤔
Copy code
fun mapToCallableMethod(expression: IrFunctionAccessExpression): IrCallableMethod {
        val callee = expression.symbol.owner.getOrCreateSuspendFunctionViewIfNeeded(context)
        val calleeParent = callee.parent
        if (calleeParent !is IrClass) {
            // Non-class parent is only possible for intrinsics created in IrBuiltIns, such as dataClassArrayMemberHashCode. In that case,
            // we still need to return some IrCallableMethod with some owner instance, but that owner will be ignored at the call site.
            // Here we return a fake type, but this needs to be refactored so that we never call mapToCallableMethod on intrinsics.
            // TODO: get rid of fake owner here
            return IrCallableMethod(FAKE_OWNER_TYPE, Opcodes.INVOKESTATIC, mapSignatureSkipGeneric(callee), false)
        }
r

raulraja

03/25/2020, 7:52 PM
the method is a global extension function
so it’s parent is the PackageFragment
Perhaps I’m missing something in the way I replace the call
s

shikasd

03/25/2020, 8:02 PM
Try this, it fails with
function is not declared
. Apparently, it is not in the symbol table?
Copy code
fun FunctionDescriptor.irCall(): IrCall {
        val irFunctionSymbol = backendContext.ir.symbols.externalSymbolTable.referenceDeclaredFunction(this)
        return IrCallImpl(
            startOffset = UNDEFINED_OFFSET,
            endOffset = UNDEFINED_OFFSET,
            type = irFunctionSymbol.owner.returnType,
            symbol = irFunctionSymbol,
            descriptor = irFunctionSymbol.descriptor,
            typeArgumentsCount = irFunctionSymbol.owner.descriptor.typeParameters.size,
            valueArgumentsCount = irFunctionSymbol.owner.descriptor.valueParameters.size
        )
    }
So its parent should be the fragment on your stage, but then in
jvmPhases
, lowering replaces function parent for generation
FileClassLowering
or something like that`
@raulraja Ok, apparently descriptor is there, but the instance is different from you have.
I removed
synthetic()
in
Copy code
fun List<Proof>.synthetic(): List<Proof> =
  mapNotNull { proof ->
    Proof(proof.from, <http://proof.to|proof.to>, (proof.through as SimpleFunctionDescriptor).synthetic(), proof.proofType)
  }
and it works 🙂
r

raulraja

03/25/2020, 9:43 PM
Awesome!
Thanks so much!
I owe you a 🍺 when travelling is back allowed !
I wonder if those unbounded symbols I was getting in 1.3.7 are related, I'll take a look at it tomorrow. Thanks again!
s

shikasd

03/26/2020, 2:46 AM
My pleasure 🍻
5 Views