我正在试验 Java 17 Vector API Incubator,我决定看看我是否可以为它创建一个零成本的语法糖。这是我写的一小段内容:
import jdk.incubator.vector._
object VectorOps {
implicit final class FloatVectorOps @inline() (val _this: FloatVector) extends AnyVal {
@inline def +(that: FloatVector): FloatVector = _this.add(that)
@inline def apply(i: Int): Float = _this.lane(i)
}
}
class Test {
def test(x: Float, y: Float): Float = {
import VectorOps._
val SSE = FloatVector.SPECIES_128
val xv = FloatVector.broadcast(SSE, x)
val yv = FloatVector.broadcast(SSE, y)
(xv + yv)(0) // sugar for xv.add(yv).lane(0)
}
}
我正在使用 Scala 2.13.5 和 Java 17。
Scala编译器运行-optimize -opt:inline -opt-warnings:at-inline-failed -Yopt-inline-heuristics:at-inline-annotated -opt:nullness-tracking -opt:box-unbox -opt:copy-propagation -opt:unreachable-code -language:implicitConversions -opt:closure-invocations
JVM 使用--add-modules jdk.incubator.vector
.
但是,Scala 编译器将test
方法的最后一行编译为
GETSTATIC VectorOps$FloatVectorOps$.MODULE$ : LVectorOps$FloatVectorOps$;
POP
GETSTATIC VectorOps$.MODULE$ : LVectorOps$;
GETSTATIC VectorOps$FloatVectorOps$.MODULE$ : LVectorOps$FloatVectorOps$;
POP
GETSTATIC VectorOps$.MODULE$ : LVectorOps$;
ALOAD 4
INVOKEVIRTUAL VectorOps$.FloatVectorOps (Ljdk/incubator/vector/FloatVector;)Ljdk/incubator/vector/FloatVector;
ALOAD 5
INVOKEVIRTUAL jdk/incubator/vector/FloatVector.add (Ljdk/incubator/vector/Vector;)Ljdk/incubator/vector/FloatVector;
INVOKEVIRTUAL VectorOps$.FloatVectorOps (Ljdk/incubator/vector/FloatVector;)Ljdk/incubator/vector/FloatVector;
ICONST_0
INVOKEVIRTUAL jdk/incubator/vector/FloatVector.lane (I)F
FRETURN
这些对隐式类构造函数的调用完全关闭了 Hotspot,并且它无法拆箱矢量变量,从而降低了性能。请注意,隐式类构造函数在字节码方面是一个标识函数,这实际上意味着它是一个空操作。所有的东西MODULE$
也都是不必要的。但热点没有看到它。
(请注意,该方法调用+
并apply
已成功内联。)
添加-Yopt-inline-heuristics:everything
会删除构造函数调用和MODULE$
,并修复性能,但这就像使用大锤来破解坚果一样。就像大锤一样,感觉不安全。
当然,以 Java 风格编写整个代码也可以解决性能问题,但这不是重点。
所以我的问题:
-Yopt-inline-heuristics:everything
是否可以在不重写原始 Java 语法的所有内容的情况下消除调用?Scala 3 有一些新的内联特性。如果没有积极的优化选项,这可以在 Scala 3 中完成吗?