为什么 Intellij 的调试器会为此 Scala 代码命两次断点
Why Intellij's debugger hits breakpoint twice for this Scala code
当我在 if 语句中设置调试点并启用“日志:断点命中消息”时,对于以下 scala 代码
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")
}
}
}
我在控制台中得到以下输出。问题是为什么这个断点被打了两次?
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
但是对于下面类似的 Java 代码,断点只命中一次。
Set<String> set1 = new HashSet<>();
set1.add("1");
set1.add("2");
Set<String> set2 = new HashSet<>();
set2.add("a");
set2.add("b");
if(set1.size() > set2.size()){ //here break point at line 8
System.out.println("size different");
}
我得到了以下输出
Breakpoint reached at com.eguller.JApp.main(JApp.java:8)
是 Intellij 调试器的 bug,还是 Scala 编程语言的特性?
IntelliJ IDEA 2021.3
Java - 11
斯卡拉 - 2.12.15
这是 scalac 字节码生成的一个特点。由于某种原因,它会在 return 指令之前为调试器生成一个额外的位置,并将其放在该行上。您可以在 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
Scala 3 编译器不添加这个并且断点按预期工作。
当我在 if 语句中设置调试点并启用“日志:断点命中消息”时,对于以下 scala 代码
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")
}
}
}
我在控制台中得到以下输出。问题是为什么这个断点被打了两次?
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
但是对于下面类似的 Java 代码,断点只命中一次。
Set<String> set1 = new HashSet<>();
set1.add("1");
set1.add("2");
Set<String> set2 = new HashSet<>();
set2.add("a");
set2.add("b");
if(set1.size() > set2.size()){ //here break point at line 8
System.out.println("size different");
}
我得到了以下输出
Breakpoint reached at com.eguller.JApp.main(JApp.java:8)
是 Intellij 调试器的 bug,还是 Scala 编程语言的特性?
IntelliJ IDEA 2021.3 Java - 11 斯卡拉 - 2.12.15
这是 scalac 字节码生成的一个特点。由于某种原因,它会在 return 指令之前为调试器生成一个额外的位置,并将其放在该行上。您可以在 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
Scala 3 编译器不添加这个并且断点按预期工作。