scala-dev
scala-dev copied to clipboard
Result of inlining a method dealing with generic arrays is disappointing
trafficstars
Perhaps a heuristic to inline array_apply / array_update / array_length when we know the specific array type (reference vs primitive) could do better.
@inline final def hashArray[T](s: Array[T], hashF: T => Unit): Unit = {
extend(s.length)
var i = 0
while (i < s.length) {
hashF(s(i))
i += 1
}
}
def hashValueParameters(valueParameters: Array[ParameterList]) =
hashArray(valueParameters, hashValueParameterList)
public hashValueParameters([Lxsbti/api/ParameterList;)V
// parameter final valueParameters
GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
ALOAD 1
INVOKEVIRTUAL scala/runtime/ScalaRunTime$.array_length (Ljava/lang/Object;)I
ISTORE 3
ALOAD 0
GETSTATIC scala/util/hashing/MurmurHash3$.MODULE$ : Lscala/util/hashing/MurmurHash3$;
ALOAD 0
GETFIELD xsbt/api/HashAPI.xsbt$api$HashAPI$$hash : I
ILOAD 3
INVOKEVIRTUAL scala/util/hashing/MurmurHash3$.mix (II)I
PUTFIELD xsbt/api/HashAPI.xsbt$api$HashAPI$$hash : I
ICONST_0
ISTORE 2
L0
ILOAD 2
GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
ALOAD 1
INVOKEVIRTUAL scala/runtime/ScalaRunTime$.array_length (Ljava/lang/Object;)I
IF_ICMPGE L1
GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
ALOAD 1
ILOAD 2
INVOKEVIRTUAL scala/runtime/ScalaRunTime$.array_apply (Ljava/lang/Object;I)Ljava/lang/Object;
CHECKCAST xsbti/api/ParameterList
ASTORE 4
ALOAD 0
ALOAD 4
INVOKESTATIC xsbt/api/HashAPI.$anonfun$hashValueParameters$1 (Lxsbt/api/HashAPI;Lxsbti/api/ParameterList;)V
ILOAD 2
ICONST_1
IADD
ISTORE 2
GOTO L0
L1
RETURN
MAXSTACK = 4
MAXLOCALS = 5
A workaround is the declare the method as:
@inline final def hashArray[T <: AnyRef](s: Array[T], hashF: T => Unit): Unit = {
extend(s.length)
var i = 0
while (i < s.length) {
hashF(s(i))
i += 1
}
}
public hashValueParameters([Lxsbti/api/ParameterList;)V
// parameter final valueParameters
ALOAD 1
CHECKCAST [Ljava/lang/Object;
ASTORE 2
ALOAD 2
ARRAYLENGTH
ISTORE 4
ALOAD 0
GETSTATIC scala/util/hashing/MurmurHash3$.MODULE$ : Lscala/util/hashing/MurmurHash3$;
ALOAD 0
GETFIELD xsbt/api/HashAPI.xsbt$api$HashAPI$$hash : I
ILOAD 4
INVOKEVIRTUAL scala/util/hashing/MurmurHash3$.mix (II)I
PUTFIELD xsbt/api/HashAPI.xsbt$api$HashAPI$$hash : I
ICONST_0
ISTORE 3
L0
ILOAD 3
ALOAD 2
ARRAYLENGTH
IF_ICMPGE L1
ALOAD 2
ILOAD 3
AALOAD
CHECKCAST xsbti/api/ParameterList
ASTORE 5
ALOAD 0
ALOAD 5
INVOKESTATIC xsbt/api/HashAPI.$anonfun$hashValueParameters$1 (Lxsbt/api/HashAPI;Lxsbti/api/ParameterList;)V
ILOAD 3
ICONST_1
IADD
ISTORE 3
GOTO L0
FWIW, the Scala.js optimizer does intrinsify those three methods, and replaces them with the appropriate IR node (bytecode) if the array argument is known to have an array type (as opposed to Object).