Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JVM Codegen: Step into a function from default arguments #5274

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

scaventz
Copy link
Contributor

@scaventz scaventz commented Mar 7, 2024

This is a proposal to fix KT-64731

The main idea is we step into a function, from default arguments assigning(except for default lambda arguments), instead of from header(annotation/modifier/name) of the function. More specifically,for below sample code, the stepping would be:

// TARGET_BACKEND: JVM_IR
// WITH_STDLIB

// FILE: test.kt
inline fun g() = ""                           // line 5

@JvmName("jvmName")
inline fun f(
    p0: Int,
    p1: String = "O",                         // line 10
    p2: String = "",                          // line 11
    p3: () -> String = { "K" },               // line 12
    p4: String = g(),                         // line 13
): String = p1 + p2 + p3() + p4               // line 14

fun box(): String = f(0)                      // line 16

// EXPECTATIONS JVM_IR
// test.kt:16 box
// test.kt:10 box
// test.kt:11 box
// test.kt:13 box
// test.kt:5 box
// test.kt:13 box
// test.kt:14 box
// test.kt:12 box
// test.kt:14 box
// test.kt:16 box

This PR done this by below code changes:

  1. Creates IrSetValue with proper offsets in defaultArgumentStubGeneratorPhase phase.

  2. For BytecodeInliner

    1. before inline phase, in codegen, we mark line number for the IrSetValue.
      For sample code below, it means linenumber 2 is marked for simpleArg: String = "" and lineumber 3 is marked for stringMaker: () -> String = { "OK" } when we call function foo$default with default arguments.
      inline fun foo(
          simpleArg: String = "",
          stringMaker: () -> String = { "OK" }
      ): String {
          return stringMaker()+simpleArg
      }
    2. In bytecode inline phase, since the default lambda is inlined at call site, there is no astore instruction for the lambda instance any more, we slightly change the logic of extractDefaultLambdasInfo to adapt current design. But what need to be noticed is that we don't mark linenumber for stringMaker: () -> String = { "OK" } in caller, not before or after this pull request, not in BytecodeInliner or IrInliner.
  3. For IrInliner

    1. Do same thing as 2.1 described.
    2. In inline phase, we don't mark linenumber for callee in codegen, so the below code is removed from visitInlinedFunctionBlock
      if (inlineCall.usesDefaultArguments()) {
          // $default function has first LN pointing to original callee
          callee?.markLineNumber(startOffset = true)
          mv.nop()
      }

Exception default lambdas, since they are inlined at call site, there
are no `ASTORE` instruction for lambda instances in caller.

Fixes: KT-64731
@scaventz scaventz changed the title JVM IR: Step into a function from default arguments JVM Codegen: Step into a function from default arguments Mar 7, 2024
@ivakub ivakub added the Backend label Mar 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants