@tailrec 优化和@Advice.OnMethodEnter 行为
@tailrec optimisation and @Advice.OnMethodEnter behaviour
我想检测一个用 @tailrec
注释的 Scala 方法。这导致编译器将递归方法优化为循环,只要是尾递归就可以了。
例如:
@tailrec
private def tailRecFunction(i: Int): Unit = {
if (i > 0) {
println(s"$i on Thread ${Thread.currentThread().getId}")
Thread.sleep(20)
tailRecFunction(i - 1)
} else {
println(s"0 on Thread ${Thread.currentThread().getId}")
Thread.sleep(20)
()
}
}
我有如下建议的方法:
@Override
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
return named("tailRecFunction");
}
@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
public static void onEnter() {
logger.info("onMethodEnter");
}
@Advice.OnMethodExit(suppress = Throwable.class, inline = false)
public static void onExit() {
logger.info("onMethodExit");
}
这会导致 tailRecFunction(10)
的以下日志输出:
2021-08-01 22:28:03,364 [main] INFO onMethodEnter
10 on Thread 1
9 on Thread 1
8 on Thread 1
7 on Thread 1
6 on Thread 1
5 on Thread 1
4 on Thread 1
3 on Thread 1
2 on Thread 1
1 on Thread 1
0 on Thread 1
2021-08-01 22:28:03,633 [main] INFO onMethodExit
是否有任何方法可以让我检测此方法并在每次方法调用时实际获得 onMethodEnter
和 onMethodExit
调用,而不是一次进入和退出?
因为尾调用消除意味着,在字节码层面,方法只有一次入口和出口(在执行方面),对于像Byte Buddy这样工作在字节码层面的工具,只能见过一个 entry/exit.
请注意,Byte Buddy 是为 Java 设计的:它只真正理解类似于 Java 编译器发出的字节码。如果 Byte Buddy 可以检测循环的进入和退出,它可能能够在 Scala 中使用尾递归方法。
据我所知,在 Scala 中没有注释或编译器选项可以禁用尾调用消除,因此使用 Byte Buddy 无法实现这一点。假设您正在尝试扩充您拥有的代码,则可以通过宏检测每次迭代。
我想检测一个用 @tailrec
注释的 Scala 方法。这导致编译器将递归方法优化为循环,只要是尾递归就可以了。
例如:
@tailrec
private def tailRecFunction(i: Int): Unit = {
if (i > 0) {
println(s"$i on Thread ${Thread.currentThread().getId}")
Thread.sleep(20)
tailRecFunction(i - 1)
} else {
println(s"0 on Thread ${Thread.currentThread().getId}")
Thread.sleep(20)
()
}
}
我有如下建议的方法:
@Override
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
return named("tailRecFunction");
}
@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
public static void onEnter() {
logger.info("onMethodEnter");
}
@Advice.OnMethodExit(suppress = Throwable.class, inline = false)
public static void onExit() {
logger.info("onMethodExit");
}
这会导致 tailRecFunction(10)
的以下日志输出:
2021-08-01 22:28:03,364 [main] INFO onMethodEnter
10 on Thread 1
9 on Thread 1
8 on Thread 1
7 on Thread 1
6 on Thread 1
5 on Thread 1
4 on Thread 1
3 on Thread 1
2 on Thread 1
1 on Thread 1
0 on Thread 1
2021-08-01 22:28:03,633 [main] INFO onMethodExit
是否有任何方法可以让我检测此方法并在每次方法调用时实际获得 onMethodEnter
和 onMethodExit
调用,而不是一次进入和退出?
因为尾调用消除意味着,在字节码层面,方法只有一次入口和出口(在执行方面),对于像Byte Buddy这样工作在字节码层面的工具,只能见过一个 entry/exit.
请注意,Byte Buddy 是为 Java 设计的:它只真正理解类似于 Java 编译器发出的字节码。如果 Byte Buddy 可以检测循环的进入和退出,它可能能够在 Scala 中使用尾递归方法。
据我所知,在 Scala 中没有注释或编译器选项可以禁用尾调用消除,因此使用 Byte Buddy 无法实现这一点。假设您正在尝试扩充您拥有的代码,则可以通过宏检测每次迭代。