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

Add filter for instructions inlined by Kotlin compiler #764

Merged
merged 33 commits into from
Dec 10, 2018

Conversation

Godin
Copy link
Member

@Godin Godin commented Oct 9, 2018

Fixes #763

After this change for the same example as in #763 :

$ java -jar jacococli.jar classinfo --verbose CallsiteKt.class
  INST   BRAN   LINE   METH   CXTY   ELEMENT
     7      0      4      2      2   class 0xcc96f697bc87baa7 CallsiteKt
     6      0      3      1      1   +- method main([Ljava/lang/String;)V
     1      0                        |  +- line 2
     1      0                        |  +- line 3
     1      0                        |  +- line 4
     1      0      1      1      1   +- method nop()V
     1      0                           +- line 7

@Godin Godin added this to the 0.8.3 milestone Oct 9, 2018
@Godin Godin self-assigned this Oct 9, 2018
@Godin Godin added this to Implementation in Current work items via automation Oct 9, 2018
@Godin Godin added this to To Do in Filtering via automation Oct 9, 2018
@Godin
Copy link
Member Author

Godin commented Oct 9, 2018

@marchof could you please do first review pass?

@Godin Godin requested a review from marchof October 9, 2018 23:28
@Godin Godin moved this from Implementation to Review in Current work items Oct 9, 2018
@Godin Godin moved this from Review to Implementation in Current work items Oct 21, 2018
@Godin Godin force-pushed the filter_kotlin_inline branch 4 times, most recently from a593487 to 3710462 Compare October 23, 2018 10:15
@Godin
Copy link
Member Author

Godin commented Dec 6, 2018

@jwalter thanks a lot for testing and this valuable feedback just in time to keep our master free from bugs 👍 our small team really appreciates this ❤️

Don't know yet how to reproduce this, but apparently KotlinDebug section is not always present in SMAP. Will try to do a deeper look and fix later today.

@Godin Godin moved this from Review to Implementation in Current work items Dec 6, 2018
@jwalter
Copy link

jwalter commented Dec 6, 2018

Not sure it helps, but the class triggering looks like this (lines 8-20. 1-7 are package declaration and imports):

internal class GetFormTemplateBodyBuilder: BodyBuilder<GetFormTemplateType> {
  override fun buildElement(mediatorRequest: MediatorClientRequest): JAXBElement<GetFormTemplateType> {
    val getFormsRequest = ObjectFactory().createGetFormTemplateType().apply {
      subjectOfCare = mediatorRequest.subjectOfCare()
      assert(subjectOfCare != null) { "No patient id provided" }
      sessionID = mediatorRequest.correlationId
      assert(sessionID != null) { "No correlation id provided" }
      templateID = mediatorRequest.getParameter("id")
      assert(templateID != null) { "No template id provided" }
    }
    return ObjectFactory().createGetFormTemplate(getFormsRequest)
  }
}

@Godin
Copy link
Member Author

Godin commented Dec 6, 2018

@jwalter thank you for the code - it gave an idea about reproducer, which is actually quite simple:

compilation of

fun main(args: Array<String>) {
    assert(args.size < 0) {
        println("Ouch")
    }
} // line 5

results in

...
        17: getstatic     #21                 // Field kotlin/_Assertions.ENABLED:Z
        20: ifeq          53
...
      LineNumberTable:
        line 2: 6
        line 3: 27
        line 4: 37
        line 2: 40
        line 5: 53
...
SourceDebugExtension:
  SMAP
  Example.kt
  Kotlin
  *S Kotlin
  *F
  + 1 Example.kt
  ExampleKt
  *L
  1#1,6:1
  *E

Will work on a fix in context of this ticket.

However this is also quite interesting in context of a #654 (comment) (CC @goodwinnk @yole): content of assert function clearly becomes inlined (see above bytecode at offsets 17 and 20), however there doesn't seem to be a way to determine this from SMAP as it doesn't mention AssertionsJVM.kt.

@Godin
Copy link
Member Author

Godin commented Dec 6, 2018

And here is another example:

F1.kt

package example

inline fun call(crossinline init: () -> Unit) {
    return {
        init()
    }()
} // line 7

F2.kt

package example

fun test(): String {
    var res = "Fail"
    call {
        res = "OK"
    }
    return res
}

that produces F2Kt$test$$inlined$call$1.class without KotlinDebug strata, however with line numbers that go beyond line numbers in source file F1.kt

...
  public final void invoke();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=2, args_size=1
         0: nop
         1: aload_0
         2: getfield      #18                 // Field $res$inlined:Lkotlin/jvm/internal/Ref$ObjectRef;
         5: ldc           #34                 // String OK
         7: putfield      #40                 // Field kotlin/jvm/internal/Ref$ObjectRef.element:Ljava/lang/Object;
        10: nop
        11: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            1       9     1 $i$a$1$call   I
            0      12     0  this   Lorg/jacoco/core/test/validation/kotlin/targets/F2Kt$test$$inlined$call$1;
      LineNumberTable:
        line 5: 0
        line 9: 1
        line 10: 10
        line 6: 11
...
SourceFile: "F1.kt"
SourceDebugExtension:
  SMAP
  F1.kt
  Kotlin
  *S Kotlin
  *F
  + 1 F1.kt
  org/jacoco/core/test/validation/kotlin/targets/F1Kt$call$1
  + 2 F2.kt
  org/jacoco/core/test/validation/kotlin/targets/F2Kt
  *L
  1#1,8:1
  6#2,2:9
  *E

From which to me seems that we can change algorithm on following:
in LineSection of main Kotlin strata
find minimal OutputStartLine
excluding LineInfos whose LineFileID corresponds to SourceFile attribute.

Any feedback/thoughts about this new algorithm are welcome.

@Godin
Copy link
Member Author

Godin commented Dec 6, 2018

I was wrong about current validation test 😞

object KotlinInlineTarget { // line 19

    inline fun inlined() {
        nop()
    }

    @JvmStatic
    fun main(args: Array<String>) {

        inlined()

    }

} // line 32
SMAP
KotlinInlineTarget.kt
Kotlin
*S Kotlin
*F
+ 1 KotlinInlineTarget.kt
org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget
*L
1#1,33:1
22#1,2:34
*E
*S KotlinDebug
*F
+ 1 KotlinInlineTarget.kt
org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget
*L
28#1,2:34
*E

@Godin
Copy link
Member Author

Godin commented Dec 6, 2018

 excluding `LineInfo`s whose `LineFileID` corresponds to `SourceFile` attribute
+and `InputStartLine` equal to `OutputStartLine`

@Godin
Copy link
Member Author

Godin commented Dec 6, 2018

@jwalter could you please retest?

@jwalter
Copy link

jwalter commented Dec 7, 2018

@Godin Works great! (My coverage went from 40% to 90%)

@Godin
Copy link
Member Author

Godin commented Dec 7, 2018

@jwalter thanks a lot for testing! 👍 ❤️

Please excuse me for pedantism, but as a remark - when talking about metrics it is IMO very important to always specify metric, i.e. percentage of what? "instructions"? 😉

Nevertheless, while #763 initially is about mismatch between numbers of lines in XML report and source files, another aspect - is indeed a fix of metrics (instructions, lines, branches, complexity), which before this change were including inlined code that potentially comes from other libraries and therefore doesn't require tests on a side of consumers of library.

Thanks again for spotting bug and testing! ❤️ Hope there won't be other obstacles and we'll publish this soon.

@Godin Godin moved this from Implementation to Review in Current work items Dec 7, 2018
@Godin Godin requested a review from marchof December 7, 2018 21:12
@marchof marchof merged commit 490939e into master Dec 10, 2018
Filtering automation moved this from In Progress to Done Dec 10, 2018
Current work items automation moved this from Review to Done Dec 10, 2018
@marchof marchof deleted the filter_kotlin_inline branch December 10, 2018 11:31
@jacoco jacoco locked as resolved and limited conversation to collaborators May 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Filtering
  
Done
Development

Successfully merging this pull request may close these issues.

Add filter for instructions inlined by Kotlin compiler
3 participants