diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
index 187e041e674..47605d1f359 100644
--- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
+++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
@@ -1990,7 +1990,9 @@ public AbstractStringBuilder repeat(CharSequence cs, int count) {
         } else {
             appendChars(cs, 0, length);
         }
-        String.repeatCopyRest(value, offset << coder, total << coder, length << coder);
+        offset <<= coder;
+        Arrays.tiler(value, offset, offset + (total << coder),
+                     value, offset, offset + (length << coder));
         this.count = limit;
         return this;
     }
diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java
index 2245792999a..82a86df17ed 100644
--- a/src/java.base/share/classes/java/lang/String.java
+++ b/src/java.base/share/classes/java/lang/String.java
@@ -4726,37 +4726,10 @@ public String repeat(int count) {
         }
         final int limit = len * count;
         final byte[] multiple = new byte[limit];
-        System.arraycopy(value, 0, multiple, 0, len);
-        repeatCopyRest(multiple, 0, limit, len);
+        Arrays.tile(multiple, value);
         return new String(multiple, coder);
     }

-    /**
-     * Used to perform copying after the initial insertion. Copying is optimized
-     * by using power of two duplication. First pass duplicates original copy,
-     * second pass then duplicates the original and the copy yielding four copies,
-     * third pass duplicates four copies yielding eight copies, and so on.
-     * Finally, the remainder is filled in with prior copies.
-     *
-     * @implNote The technique used here is significantly faster than hand-rolled
-     * loops or special casing small numbers due to the intensive optimization
-     * done by intrinsic {@code System.arraycopy}.
-     *
-     * @param buffer    destination buffer
-     * @param offset    offset in the destination buffer
-     * @param limit     total replicated including what is already in the buffer
-     * @param copied    number of bytes that have already in the buffer
-     */
-    static void repeatCopyRest(byte[] buffer, int offset, int limit, int copied) {
-        // Initial copy is in the buffer.
-        for (; copied < limit - copied; copied <<= 1) {
-            // Power of two duplicate.
-            System.arraycopy(buffer, offset, buffer, offset + copied, copied);
-        }
-        // Duplicate remainder.
-        System.arraycopy(buffer, offset, buffer, offset + copied, limit - copied);
-    }
-
     ////////////////////////////////////////////////////////////////

     /**
diff --git a/src/java.base/share/classes/java/util/Arrays.java b/src/java.base/share/classes/java/util/Arrays.java
index c5412776d20..37cb2cbec5a 100644
--- a/src/java.base/share/classes/java/util/Arrays.java
+++ b/src/java.base/share/classes/java/util/Arrays.java
@@ -3455,6 +3455,367 @@ public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
             a[i] = val;
     }

+    // Tiling
+
+    /**
+     * Tile the destination char array {@code dst} by progressively copying the source char
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination char array
+     * @param dstFrom  starting index in the destination char array where tiling begins
+     * @param dstTo    last index plus one in the destination char array where tiling ends
+     * @param src      source char array
+     * @param srcFrom  starting index in the source char array where tiling begins
+     * @param srcTo    last index plus one in the source char array where tiling ends
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo || srcFrom > srcTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length || srcFrom < 0 || srcTo > src.length}
+     * @throws ArrayStoreException if an element in the src array could not be stored into the
+     * dst array because of a type mismatch
+     */
+    public static void tiler(Object dst, int dstFrom, int dstTo,
+                             Object src, int srcFrom, int srcTo) {
+        Objects.requireNonNull(dst, "dst must not be null");
+        Objects.requireNonNull(src, "src must not be null");
+        rangeCheck(Array.getLength(dst), dstFrom, dstTo);
+        rangeCheck(Array.getLength(src), srcFrom, srcTo);
+        int srcLength = srcTo - srcFrom;
+        int dstLength = dstTo - dstFrom;
+        if (dstLength != 0) {
+            if (dstLength <= srcLength) {
+                System.arraycopy(src, srcFrom, dst, dstFrom, dstLength);
+            } else {
+                System.arraycopy(src, srcFrom, dst, dstFrom, srcLength);
+                int remaining = dstLength - srcLength;
+                int offset = dstFrom + srcLength;
+                while (srcLength < remaining) {
+                    System.arraycopy(dst, dstFrom, dst, offset, srcLength);
+                    offset += srcLength;
+                    remaining -= srcLength;
+                    srcLength <<= 1;
+                }
+                System.arraycopy(dst, dstFrom, dst, offset, remaining);
+            }
+        }
+    }
+
+    /**
+     * Tile the destination char array {@code dst} by progressively copying the source char
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination char array
+     * @param dstFrom  starting index in the destination char array where tiling begins
+     * @param dstTo    last index plus one in the destination char array where tiling ends
+     * @param src      source char array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     * @throws ArrayStoreException if an element in the src array could not be stored into the
+     * dst array because of a type mismatch
+     */
+    public static void tiler(Object dst, int dstFrom, int dstTo, Object src) {
+        tiler(dst, dstFrom, dstTo, src, 0, Array.getLength(src));
+    }
+
+    /**
+     * Tile the destination char array {@code dst} by progressively copying the source char
+     * array {@code src} contents until the destination char array is filled.
+     *
+     * @param dst  destination char array
+     * @param src  source char array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws ArrayStoreException if an element in the src array could not be stored into the
+     * dst array because of a type mismatch
+     */
+    public static void tiler(Object dst, Object src) {
+        tiler(dst, 0, Array.getLength(dst), src, 0, Array.getLength(src));
+    }
+
+    /**
+     * Tile the destination byte array {@code dst} by progressively copying the source byte
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination byte array
+     * @param dstFrom  starting index in the destination byte array where tiling begins
+     * @param dstTo    last index plus one in the destination bytearray where tiling ends
+     * @param src      source byte array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(byte[] dst, int dstFrom, int dstTo, byte[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination byte array {@code dst} by progressively copying the source byte
+     * array {@code src} contents until destination byte array {@code dst} is filled.
+     *
+     * @param dst  destination byte array
+     * @param src  source byte array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(byte[] dst, byte[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination short array {@code dst} by progressively copying the source short
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination short array
+     * @param dstFrom  starting index in the destination short array where tiling begins
+     * @param dstTo    last index plus one in the destination shortarray where tiling ends
+     * @param src      source short array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(short[] dst, int dstFrom, int dstTo, short[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination short array {@code dst} by progressively copying the source short
+     * array {@code src} contents until destination short array {@code dst} is filled.
+     *
+     * @param dst  destination short array
+     * @param src  source short array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(short[] dst, short[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination int array {@code dst} by progressively copying the source int
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination int array
+     * @param dstFrom  starting index in the destination int array where tiling begins
+     * @param dstTo    last index plus one in the destination intarray where tiling ends
+     * @param src      source int array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(int[] dst, int dstFrom, int dstTo, int[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination int array {@code dst} by progressively copying the source int
+     * array {@code src} contents until destination int array {@code dst} is filled.
+     *
+     * @param dst  destination int array
+     * @param src  source int array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(int[] dst, int[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination long array {@code dst} by progressively copying the source long
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination long array
+     * @param dstFrom  starting index in the destination long array where tiling begins
+     * @param dstTo    last index plus one in the destination longarray where tiling ends
+     * @param src      source long array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(long[] dst, int dstFrom, int dstTo, long[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination long array {@code dst} by progressively copying the source long
+     * array {@code src} contents until destination long array {@code dst} is filled.
+     *
+     * @param dst  destination long array
+     * @param src  source long array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(long[] dst, long[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination float array {@code dst} by progressively copying the source float
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination float array
+     * @param dstFrom  starting index in the destination float array where tiling begins
+     * @param dstTo    last index plus one in the destination floatarray where tiling ends
+     * @param src      source float array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(float[] dst, int dstFrom, int dstTo, float[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination float array {@code dst} by progressively copying the source float
+     * array {@code src} contents until destination float array {@code dst} is filled.
+     *
+     * @param dst  destination float array
+     * @param src  source float array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(float[] dst, float[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination double array {@code dst} by progressively copying the source double
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination double array
+     * @param dstFrom  starting index in the destination double array where tiling begins
+     * @param dstTo    last index plus one in the destination doublearray where tiling ends
+     * @param src      source double array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(double[] dst, int dstFrom, int dstTo, double[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination double array {@code dst} by progressively copying the source double
+     * array {@code src} contents until destination double array {@code dst} is filled.
+     *
+     * @param dst  destination double array
+     * @param src  source double array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(double[] dst, double[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination boolean array {@code dst} by progressively copying the source boolean
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination boolean array
+     * @param dstFrom  starting index in the destination boolean array where tiling begins
+     * @param dstTo    last index plus one in the destination booleanarray where tiling ends
+     * @param src      source boolean array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(boolean[] dst, int dstFrom, int dstTo, boolean[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination boolean array {@code dst} by progressively copying the source boolean
+     * array {@code src} contents until destination boolean array {@code dst} is filled.
+     *
+     * @param dst  destination boolean array
+     * @param src  source boolean array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(boolean[] dst, boolean[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination char array {@code dst} by progressively copying the source char
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination char array
+     * @param dstFrom  starting index in the destination char array where tiling begins
+     * @param dstTo    last index plus one in the destination chararray where tiling ends
+     * @param src      source char array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(char[] dst, int dstFrom, int dstTo, char[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination char array {@code dst} by progressively copying the source char
+     * array {@code src} contents until destination char array {@code dst} is filled.
+     *
+     * @param dst  destination char array
+     * @param src  source char array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(char[] dst, char[] src) {
+        tiler(dst, src);
+    }
+
+    /**
+     * Tile the destination Object array {@code dst} by progressively copying the source Object
+     * array {@code src} contents until the range, {@code dstFrom} to {@code dstTo}, is filled.
+     *
+     * @param dst      destination Object array
+     * @param dstFrom  starting index in the destination Object array where tiling begins
+     * @param dstTo    last index plus one in the destination Objectarray where tiling ends
+     * @param src      source Object array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code dstFrom > dstTo}
+     * @throws ArrayIndexOutOfBoundsException
+     * if {@code dstFrom < 0 || dstTo > dst.length}
+     */
+    public static void tile(Object[] dst, int dstFrom, int dstTo, Object[] src) {
+        tiler(dst, dstFrom, dstTo, src);
+    }
+
+    /**
+     * Tile the destination Object array {@code dst} by progressively copying the source Object
+     * array {@code src} contents until destination Object array {@code dst} is filled.
+     *
+     * @param dst  destination Object array
+     * @param src  source Object array
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     */
+    public static void tile(Object[] dst, Object[] src) {
+        tiler(dst, src);
+    }
+
+
     // Cloning

     /**
