为啥 Intellij 的调试器会为此 Scala 代码两次命中断点
Posted
技术标签:
【中文标题】为啥 Intellij 的调试器会为此 Scala 代码两次命中断点【英文标题】:Why Intellij's debugger hits breakpoint twice for this Scala code为什么 Intellij 的调试器会为此 Scala 代码两次命中断点 【发布时间】:2022-01-14 16:42:06 【问题描述】:当我在 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 调试器中的错误,还是 Scala 编程语言的一个特性?
IntelliJ IDEA 2021.3 爪哇 - 11 斯卡拉 - 2.12.15
【问题讨论】:
【参考方案1】:这是 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
Scala 3 编译器没有添加这个并且断点按预期工作。
【讨论】:
感谢@niktrop,我正在调试一个 Scala 代码,其中包含理解/收益、期货等。我认为我的代码被调用了两次并试图找出根本原因。最终我怀疑,也许代码没有执行两次,但断点多次命中并以简单的方法进行测试。确实是这样。以上是关于为啥 Intellij 的调试器会为此 Scala 代码两次命中断点的主要内容,如果未能解决你的问题,请参考以下文章