为什么 Intellij 的调试器会在此 Scala 代码中两次命中断点

Eng*_*ler 5 java debugging scala breakpoints intellij-idea

对于以下 scala 代码,当我在 if 语句处设置调试点并启用“日志:断点命中消息”时

object App1 {
  def main(args: Array[String]): Unit = {
    iftest()
  }
  def iftest(): Unit = {
    val setA: Set[String] = Set("a", "b", "c");
    var setB: Set[String] = Set("d", "e", "f")
    if(setA.size > setB.size){ //here break point at line 8
      println("bigger")
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我在控制台中得到以下输出。问题是为什么这个断点会被击中两次?

Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Run Code Online (Sandbox Code Playgroud)

但对于以下类似的 Java 代码,断点仅被命中一次。

Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Run Code Online (Sandbox Code Playgroud)

我得到以下输出

Breakpoint reached at com.eguller.JApp.main(JApp.java:8)
Run Code Online (Sandbox Code Playgroud)

这是 Intellij 调试器中的错误,还是 Scala 编程语言的功能?

IntelliJ IDEA 2021.3 Java - 11 Scala - 2.12.15

小智 3

这是 scalac 字节码生成的一个特性。由于某种原因,它在返回指令之前为调试器生成一个附加位置并将其放在该行上。您可以在 IDE 中调用“显示字节码”操作,并看到有 2 个LINENUMBER 8条目:

// access flags 0x1
public iftest()V
 L0
  LINENUMBER 6 L0
  GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
  INVOKEVIRTUAL scala/Predef$.Set ()Lscala/collection/immutable/Set$;
  GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
  ICONST_3
  ANEWARRAY java/lang/String
  DUP
  ICONST_0
  LDC "a"
  AASTORE
  DUP
  ICONST_1
  LDC "b"
  AASTORE
  DUP
  ICONST_2
  LDC "c"
  AASTORE
  CHECKCAST [Ljava/lang/Object;
  INVOKEVIRTUAL scala/runtime/ScalaRunTime$.wrapRefArray ([Ljava/lang/Object;)Lscala/collection/immutable/ArraySeq;
  INVOKEVIRTUAL scala/collection/immutable/Set$.apply (Lscala/collection/immutable/Seq;)Ljava/lang/Object;
  CHECKCAST scala/collection/immutable/Set
  ASTORE 1
 L1
  LINENUMBER 7 L1
  GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
  INVOKEVIRTUAL scala/Predef$.Set ()Lscala/collection/immutable/Set$;
  GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
  ICONST_3
  ANEWARRAY java/lang/String
  DUP
  ICONST_0
  LDC "d"
  AASTORE
  DUP
  ICONST_1
  LDC "e"
  AASTORE
  DUP
  ICONST_2
  LDC "f"
  AASTORE
  CHECKCAST [Ljava/lang/Object;
  INVOKEVIRTUAL scala/runtime/ScalaRunTime$.wrapRefArray ([Ljava/lang/Object;)Lscala/collection/immutable/ArraySeq;
  INVOKEVIRTUAL scala/collection/immutable/Set$.apply (Lscala/collection/immutable/Seq;)Ljava/lang/Object;
  CHECKCAST scala/collection/immutable/Set
  ASTORE 2
 L2
  LINENUMBER 8 L2
  ALOAD 1
  INVOKEINTERFACE scala/collection/immutable/Set.size ()I (itf)
  ALOAD 2
  INVOKEINTERFACE scala/collection/immutable/Set.size ()I (itf)
  IF_ICMPLE L3
 L4
  LINENUMBER 9 L4
  GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
  LDC "bigger"
  INVOKEVIRTUAL scala/Predef$.println (Ljava/lang/Object;)V
  GOTO L3
 L3
  LINENUMBER 8 L3
 FRAME APPEND [scala/collection/immutable/Set scala/collection/immutable/Set]
  RETURN
 L5
  LOCALVARIABLE setA Lscala/collection/immutable/Set; L1 L3 1
  LOCALVARIABLE setB Lscala/collection/immutable/Set; L2 L3 2
  LOCALVARIABLE this LApp1$; L0 L5 0
  MAXSTACK = 6
  MAXLOCALS = 3
Run Code Online (Sandbox Code Playgroud)

Scala 3 编译器不会添加此功能,并且断点按预期工作。