-optimize
than they were before! Take this code:class OptEx { def sum(l: Array[Int]) = { var acc = 0 for (i <- 0 until l.length) acc += l(i) acc } }This is the java bytecode generated with Scala 2.8.1 for the method
sum
:
public int sum(int[]); Code: 0: new #7; //class scala/runtime/IntRef 3: dup 4: iconst_0 5: invokespecial #12; //Method scala/runtime/IntRef."And this is what Scala 2.9.0 does:":(I)V 8: astore_2 9: new #14; //class scala/runtime/RichInt 12: dup 13: iconst_0 14: invokespecial #15; //Method scala/runtime/RichInt." ":(I)V 17: aload_1 18: arraylength 19: invokevirtual #19; //Method scala/runtime/RichInt.until:(I)Lscala/collection/immutable/Range$ByOne; 22: new #21; //class OptEx$$anonfun$sum$1 25: dup 26: aload_0 27: aload_1 28: aload_2 29: invokespecial #24; //Method OptEx$$anonfun$sum$1." ":(LOptEx;[ILscala/runtime/IntRef;)V 32: invokeinterface #30, 2; //InterfaceMethod scala/collection/immutable/Range$ByOne.foreach$mVc$sp:(Lscala/Functio n1;)V 37: aload_2 38: getfield #34; //Field scala/runtime/IntRef.elem:I 41: ireturn
public int sum(int[]); Code: 0: new #7; //class scala/runtime/IntRef 3: dup 4: iconst_0 5: invokespecial #12; //Method scala/runtime/IntRef."":(I)V 8: astore 6 10: new #14; //class scala/runtime/RichInt 13: dup 14: iconst_0 15: invokespecial #15; //Method scala/runtime/RichInt." ":(I)V 18: aload_1 19: arraylength 20: istore_3 21: astore_2 22: getstatic #21; //Field scala/collection/immutable/Range$.MODULE$:Lscala/collection/immutable/Range$; 25: aload_2 26: invokevirtual #25; //Method scala/runtime/RichInt.self:()I 29: iload_3 30: invokevirtual #29; //Method scala/collection/immutable/Range$.apply:(II)Lscala/collection/immutable/Range; 33: dup 34: astore 8 36: invokevirtual #34; //Method scala/collection/immutable/Range.length:()I 39: iconst_0 40: if_icmple 83 43: aload 8 45: invokevirtual #37; //Method scala/collection/immutable/Range.last:()I 48: istore 4 50: aload 8 52: invokevirtual #40; //Method scala/collection/immutable/Range.start:()I 55: istore 9 57: iload 9 59: iload 4 61: if_icmpne 89 64: iload 9 66: istore 5 68: aload 6 70: aload 6 72: getfield #44; //Field scala/runtime/IntRef.elem:I 75: aload_1 76: iload 5 78: iaload 79: iadd 80: putfield #44; //Field scala/runtime/IntRef.elem:I 83: aload 6 85: getfield #44; //Field scala/runtime/IntRef.elem:I 88: ireturn 89: iload 9 91: istore 7 93: aload 6 95: aload 6 97: getfield #44; //Field scala/runtime/IntRef.elem:I 100: aload_1 101: iload 7 103: iaload 104: iadd 105: putfield #44; //Field scala/runtime/IntRef.elem:I 108: iload 9 110: aload 8 112: invokevirtual #47; //Method scala/collection/immutable/Range.step:()I 115: iadd 116: istore 9 118: goto 57
Time to take your old benchmarks out of the closet, people!
The method foreach and the lambda seem to be inlined. In this case, usage of IntRef does not IMHO make sense.
ReplyDeleteHowever, I don't believe there will be any notable performance benefit in long-running app if you use a modern JVM. Modern JVMs probably can inline these calls and dynamic allocation can be probably also inhibited.
Hmm ... probably versus definately .. I'll take the definite one thank you :-)
ReplyDelete@v6ak
ReplyDeleteActually, this is a particular situation where inlining doesn't work well: megamorphic call sites.
See http://www.azulsystems.com/blog/cliff/2011-04-04-fixing-the-inlining-problem for a recent discussion about this problem.