diff --git a/actor/src/main/scala-2.12/org/apache/pekko/util/ByteIterator.scala b/actor/src/main/scala-2.12/org/apache/pekko/util/ByteIterator.scala index e172cb8298e..46d50e2e6cd 100644 --- a/actor/src/main/scala-2.12/org/apache/pekko/util/ByteIterator.scala +++ b/actor/src/main/scala-2.12/org/apache/pekko/util/ByteIterator.scala @@ -123,7 +123,7 @@ object ByteIterator { def getBytes(xs: Array[Byte], offset: Int, n: Int): this.type = { if (n <= this.len) { - Array.copy(this.array, this.from, xs, offset, n) + System.arraycopy(this.array, this.from, xs, offset, n) this.drop(n) } else EmptyImmutableSeq.iterator.next() } diff --git a/actor/src/main/scala-2.12/org/apache/pekko/util/ByteString.scala b/actor/src/main/scala-2.12/org/apache/pekko/util/ByteString.scala index 356a24868b7..0b06483b383 100644 --- a/actor/src/main/scala-2.12/org/apache/pekko/util/ByteString.scala +++ b/actor/src/main/scala-2.12/org/apache/pekko/util/ByteString.scala @@ -1005,7 +1005,7 @@ object CompactByteString { if (copyLength == 0) empty else { val copyArray = new Array[Byte](copyLength) - Array.copy(array, copyOffset, copyArray, 0, copyLength) + System.arraycopy(array, copyOffset, copyArray, 0, copyLength) ByteString.ByteString1C(copyArray) } } @@ -1065,7 +1065,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { private def clearTemp(): Unit = { if (_tempLength > 0) { val arr = new Array[Byte](_tempLength) - Array.copy(_temp, 0, arr, 0, _tempLength) + System.arraycopy(_temp, 0, arr, 0, _tempLength) _builder += ByteString1(arr) _tempLength = 0 } @@ -1073,7 +1073,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { private def resizeTemp(size: Int): Unit = { val newtemp = new Array[Byte](size) - if (_tempLength > 0) Array.copy(_temp, 0, newtemp, 0, _tempLength) + if (_tempLength > 0) System.arraycopy(_temp, 0, newtemp, 0, _tempLength) _temp = newtemp _tempCapacity = _temp.length } @@ -1257,7 +1257,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { * Add a number of Bytes from an array to this builder. */ def putBytes(array: Array[Byte], start: Int, len: Int): this.type = - fillArray(len) { case (target, targetOffset) => Array.copy(array, start, target, targetOffset, len) } + fillArray(len) { case (target, targetOffset) => System.arraycopy(array, start, target, targetOffset, len) } /** * Add a number of Shorts from an array to this builder. diff --git a/actor/src/main/scala-2.13/org/apache/pekko/util/ByteIterator.scala b/actor/src/main/scala-2.13/org/apache/pekko/util/ByteIterator.scala index fccd69fa0c4..af64128e65a 100644 --- a/actor/src/main/scala-2.13/org/apache/pekko/util/ByteIterator.scala +++ b/actor/src/main/scala-2.13/org/apache/pekko/util/ByteIterator.scala @@ -135,7 +135,7 @@ object ByteIterator { @throws[NoSuchElementException] def getBytes(xs: Array[Byte], offset: Int, n: Int): this.type = { if (n <= this.len) { - Array.copy(this.array, this.from, xs, offset, n) + System.arraycopy(this.array, this.from, xs, offset, n) this.drop(n) } else throw new NoSuchElementException("next on empty iterator") } diff --git a/actor/src/main/scala-2.13/org/apache/pekko/util/ByteString.scala b/actor/src/main/scala-2.13/org/apache/pekko/util/ByteString.scala index 6c3078851c0..bf5be5a69a2 100644 --- a/actor/src/main/scala-2.13/org/apache/pekko/util/ByteString.scala +++ b/actor/src/main/scala-2.13/org/apache/pekko/util/ByteString.scala @@ -1055,7 +1055,7 @@ object CompactByteString { if (copyLength == 0) empty else { val copyArray = new Array[Byte](copyLength) - Array.copy(array, copyOffset, copyArray, 0, copyLength) + System.arraycopy(array, copyOffset, copyArray, 0, copyLength) ByteString.ByteString1C(copyArray) } } @@ -1115,7 +1115,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { private def clearTemp(): Unit = { if (_tempLength > 0) { val arr = new Array[Byte](_tempLength) - Array.copy(_temp, 0, arr, 0, _tempLength) + System.arraycopy(_temp, 0, arr, 0, _tempLength) _builder += ByteString1(arr) _tempLength = 0 } @@ -1123,7 +1123,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { private def resizeTemp(size: Int): Unit = { val newtemp = new Array[Byte](size) - if (_tempLength > 0) Array.copy(_temp, 0, newtemp, 0, _tempLength) + if (_tempLength > 0) System.arraycopy(_temp, 0, newtemp, 0, _tempLength) _temp = newtemp _tempCapacity = _temp.length } @@ -1313,7 +1313,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { * Add a number of Bytes from an array to this builder. */ def putBytes(array: Array[Byte], start: Int, len: Int): this.type = - fillArray(len) { case (target, targetOffset) => Array.copy(array, start, target, targetOffset, len) } + fillArray(len) { case (target, targetOffset) => System.arraycopy(array, start, target, targetOffset, len) } /** * Add a number of Shorts from an array to this builder. diff --git a/actor/src/main/scala-3/org/apache/pekko/util/ByteIterator.scala b/actor/src/main/scala-3/org/apache/pekko/util/ByteIterator.scala index 92f57e10f9f..85699fcca71 100644 --- a/actor/src/main/scala-3/org/apache/pekko/util/ByteIterator.scala +++ b/actor/src/main/scala-3/org/apache/pekko/util/ByteIterator.scala @@ -132,7 +132,7 @@ object ByteIterator { @throws[NoSuchElementException] def getBytes(xs: Array[Byte], offset: Int, n: Int): this.type = { if (n <= this.len) { - Array.copy(this.array, this.from, xs, offset, n) + System.arraycopy(this.array, this.from, xs, offset, n) this.drop(n) } else throw new NoSuchElementException("next on empty iterator") } diff --git a/actor/src/main/scala-3/org/apache/pekko/util/ByteString.scala b/actor/src/main/scala-3/org/apache/pekko/util/ByteString.scala index d2e0823e65a..bcd4c3284c5 100644 --- a/actor/src/main/scala-3/org/apache/pekko/util/ByteString.scala +++ b/actor/src/main/scala-3/org/apache/pekko/util/ByteString.scala @@ -1055,7 +1055,7 @@ object CompactByteString { if (copyLength == 0) empty else { val copyArray = new Array[Byte](copyLength) - Array.copy(array, copyOffset, copyArray, 0, copyLength) + System.arraycopy(array, copyOffset, copyArray, 0, copyLength) ByteString.ByteString1C(copyArray) } } @@ -1115,7 +1115,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { private def clearTemp(): Unit = { if (_tempLength > 0) { val arr = new Array[Byte](_tempLength) - Array.copy(_temp, 0, arr, 0, _tempLength) + System.arraycopy(_temp, 0, arr, 0, _tempLength) _builder += ByteString1(arr) _tempLength = 0 } @@ -1123,7 +1123,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { private def resizeTemp(size: Int): Unit = { val newtemp = new Array[Byte](size) - if (_tempLength > 0) Array.copy(_temp, 0, newtemp, 0, _tempLength) + if (_tempLength > 0) System.arraycopy(_temp, 0, newtemp, 0, _tempLength) _temp = newtemp _tempCapacity = _temp.length } @@ -1313,7 +1313,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { * Add a number of Bytes from an array to this builder. */ def putBytes(array: Array[Byte], start: Int, len: Int): this.type = - fillArray(len) { case (target, targetOffset) => Array.copy(array, start, target, targetOffset, len) } + fillArray(len) { case (target, targetOffset) => System.arraycopy(array, start, target, targetOffset, len) } /** * Add a number of Shorts from an array to this builder. diff --git a/bench-jmh/src/main/scala/org/apache/pekko/util/ArrayCopyOf_Benchmark.scala b/bench-jmh/src/main/scala/org/apache/pekko/util/ArrayCopyOf_Benchmark.scala new file mode 100644 index 00000000000..af2467a588c --- /dev/null +++ b/bench-jmh/src/main/scala/org/apache/pekko/util/ArrayCopyOf_Benchmark.scala @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.pekko.util + +import org.openjdk.jmh.annotations._ + +import java.util.concurrent.TimeUnit + +@State(Scope.Benchmark) +@Measurement(timeUnit = TimeUnit.MILLISECONDS) +class ArrayCopyOf_Benchmark { + + var bs: Array[Byte] = _ + + @Param(Array("100", "1000")) + var kb = 0 + + /* + bench-jmh/jmh:run -f 1 -wi 10 -i 10 .*ArrayCopyOf_Benchmark.* + */ + + @Setup + def setup(): Unit = { + bs = Array.fill[Byte](1024 * kb)(1) + } + + @Benchmark + def systemArrayCopy(): Unit = { + val len = bs.length + val buffer2 = new Array[Byte](bs.length) + System.arraycopy(bs, 0, buffer2, 0, len) + } + + @Benchmark + def arrayCopyOf(): Unit = { + val len = bs.length + val buffer2 = new Array[Byte](bs.length) + Array.copy(bs, 0, buffer2, 0, len) + } + +}