数组构造器优化——Double的装箱
Array constructor optimization - boxing of Double
在分析我的应用程序时,我可以看到在 Array[Double]
构造函数中对 Double 值进行装箱,如下所示(从 JMC / JFR 复制):
Double Double.valueOf(double) 1472
Double BoxesRunTime.boxToDouble(double) 1472
Object WrappedArray$ofDouble.apply(int) 1468
Object IndexedSeqLike$Elements.next() 1365
void Iterator.foreach(Function1) 1365
void Iterator.foreach$(Iterator, Function1) 1365
void AbstractIterator.foreach(Function1) 1365
Object Array$.apply(Seq, ClassTag) 1365
当我检查 Array
构造函数代码时,有以下注释(参见 Array.scala#L182-L192):
// Subject to a compiler optimization in Cleanup.
// Array(e0, ..., en) is translated to { val a = new Array(3); a(i) = ei; a }
这样的翻译听起来很合理。为什么我仍然在我的调用堆栈中看到 Iterator
/ boxToDouble
?该评论是否已过时,或者我是否需要一些特定的编译器设置才能应用此优化?
调用数组构造函数的代码是class成员初始化:
var elements = Array[Double](
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
)
我已经用 Scala 2.12.12 和 2.13.3 测试过
注释已添加到提交 Optimize primitive Array(e1, ..., en)(在 Scala 2.11.0-M1 中)。
看来优化很脆弱。更改涉及的类型和文字会导致优化完成(或不完成)。
var el = Array[Double](1)
var el = Array[Double](1.0)
两者都产生丑陋的代码:
0: aload_0
1: invokespecial #27 // Method java/lang/Object."<init>":()V
4: aload_0
5: getstatic #33 // Field scala/Array$.MODULE$:Lscala/Array$;
8: getstatic #38 // Field scala/runtime/ScalaRunTime$.MODULE$:Lscala/runtime/ScalaRunTime$;
11: iconst_1
12: newarray double
14: dup
15: iconst_0
16: dconst_1
17: dastore
18: invokevirtual #42 // Method scala/runtime/ScalaRunTime$.wrapDoubleArray:([D)Lscala/collection/immutable/ArraySeq;
21: getstatic #47 // Field scala/reflect/ClassTag$.MODULE$:Lscala/reflect/ClassTag$;
24: invokevirtual #51 // Method scala/reflect/ClassTag$.Double:()Lscala/reflect/ManifestFactory$DoubleManifest;
27: invokevirtual #55 // Method scala/Array$.apply:(Lscala/collection/immutable/Seq;Lscala/reflect/ClassTag;)Ljava/lang/Object;
30: checkcast #56 // class "[D"
33: putfield #18 // Field el:[D
36: return
}
同时
var el = Array(1.0)
var el: Array[Double] = Array(1)
产生了漂亮的结果:
0: aload_0
1: invokespecial #22 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: newarray double
8: dup
9: iconst_0
10: dconst_1
11: dastore
12: putfield #13 // Field el:[D
15: return
我也试过 Dotty,它似乎对所有变体都应用了优化。
发布为 scala/bug#12201。
在分析我的应用程序时,我可以看到在 Array[Double]
构造函数中对 Double 值进行装箱,如下所示(从 JMC / JFR 复制):
Double Double.valueOf(double) 1472
Double BoxesRunTime.boxToDouble(double) 1472
Object WrappedArray$ofDouble.apply(int) 1468
Object IndexedSeqLike$Elements.next() 1365
void Iterator.foreach(Function1) 1365
void Iterator.foreach$(Iterator, Function1) 1365
void AbstractIterator.foreach(Function1) 1365
Object Array$.apply(Seq, ClassTag) 1365
当我检查 Array
构造函数代码时,有以下注释(参见 Array.scala#L182-L192):
// Subject to a compiler optimization in Cleanup.
// Array(e0, ..., en) is translated to { val a = new Array(3); a(i) = ei; a }
这样的翻译听起来很合理。为什么我仍然在我的调用堆栈中看到 Iterator
/ boxToDouble
?该评论是否已过时,或者我是否需要一些特定的编译器设置才能应用此优化?
调用数组构造函数的代码是class成员初始化:
var elements = Array[Double](
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
)
我已经用 Scala 2.12.12 和 2.13.3 测试过
注释已添加到提交 Optimize primitive Array(e1, ..., en)(在 Scala 2.11.0-M1 中)。
看来优化很脆弱。更改涉及的类型和文字会导致优化完成(或不完成)。
var el = Array[Double](1)
var el = Array[Double](1.0)
两者都产生丑陋的代码:
0: aload_0
1: invokespecial #27 // Method java/lang/Object."<init>":()V
4: aload_0
5: getstatic #33 // Field scala/Array$.MODULE$:Lscala/Array$;
8: getstatic #38 // Field scala/runtime/ScalaRunTime$.MODULE$:Lscala/runtime/ScalaRunTime$;
11: iconst_1
12: newarray double
14: dup
15: iconst_0
16: dconst_1
17: dastore
18: invokevirtual #42 // Method scala/runtime/ScalaRunTime$.wrapDoubleArray:([D)Lscala/collection/immutable/ArraySeq;
21: getstatic #47 // Field scala/reflect/ClassTag$.MODULE$:Lscala/reflect/ClassTag$;
24: invokevirtual #51 // Method scala/reflect/ClassTag$.Double:()Lscala/reflect/ManifestFactory$DoubleManifest;
27: invokevirtual #55 // Method scala/Array$.apply:(Lscala/collection/immutable/Seq;Lscala/reflect/ClassTag;)Ljava/lang/Object;
30: checkcast #56 // class "[D"
33: putfield #18 // Field el:[D
36: return
}
同时
var el = Array(1.0)
var el: Array[Double] = Array(1)
产生了漂亮的结果:
0: aload_0
1: invokespecial #22 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: newarray double
8: dup
9: iconst_0
10: dconst_1
11: dastore
12: putfield #13 // Field el:[D
15: return
我也试过 Dotty,它似乎对所有变体都应用了优化。
发布为 scala/bug#12201。