diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java index 312d392d7..f8b19f4da 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java @@ -35,13 +35,32 @@ public final class TSystem extends TObject { if (src == null || dest == null) { throw new TNullPointerException(TString.wrap("Either src or dest is null")); } - if (src.getClass() != dest.getClass()) { - throw new TArrayStoreException(); - } if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > TArray.getLength(src) || destPos + length > TArray.getLength(dest)) { throw new TIndexOutOfBoundsException(); } + if (src != dest) { + Class srcType = src.getClass().getComponentType(); + Class targetType = dest.getClass().getComponentType(); + if (srcType == null || targetType == null) { + throw new TArrayStoreException(); + } + if (srcType != targetType) { + if (!srcType.isPrimitive() && !targetType.isPrimitive()) { + Object[] srcArray = (Object[])(Object)src; + Object[] dstArray = (Object[])(Object)dest; + for (int i = 0; i < length; ++i) { + Object elem = srcArray[srcPos++]; + if (!targetType.isInstance(elem)) { + throw new TArrayStoreException(); + } + dstArray[destPos++] = elem; + } + } else if (!srcType.isPrimitive() || !targetType.isPrimitive()) { + throw new TArrayStoreException(); + } + } + } doArrayCopy(src, srcPos, dest, destPos, length); } diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/SystemTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/SystemTest.java index e399a9844..1e295aa1e 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/SystemTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/SystemTest.java @@ -35,6 +35,57 @@ public class SystemTest { assertSame(a, dest[2]); } + @Test + public void copiesPrimitiveArray() { + int[] src = { 23, 24, 25 }; + int[] dest = new int[3]; + System.arraycopy(src, 0, dest, 0, 3); + assertEquals(23, dest[0]); + assertEquals(24, dest[1]); + assertEquals(25, dest[2]); + } + + @Test + public void copiesToSubclassArray() { + String[] src = { "foo", "bar", "baz" }; + Object[] dest = new Object[3]; + System.arraycopy(src, 0, dest, 0, 3); + assertEquals("foo", dest[0]); + assertEquals("bar", dest[1]); + assertEquals("baz", dest[2]); + } + + @Test + public void copiesToSuperclassArrayWhenItemsMatch() { + Object[] src = { "foo", "bar", "baz" }; + String[] dest = new String[3]; + System.arraycopy(src, 0, dest, 0, 3); + assertEquals("foo", dest[0]); + assertEquals("bar", dest[1]); + assertEquals("baz", dest[2]); + } + + @Test + public void failsToConverItemsCopyingArray() { + Object[] src = { "foo", 23, "baz" }; + String[] dest = new String[3]; + try { + System.arraycopy(src, 0, dest, 0, 3); + fail("Exception expected"); + } catch (ArrayStoreException e) { + assertEquals("foo", dest[0]); + assertNull(dest[1]); + assertNull(dest[2]); + } + } + + @Test(expected = ArrayStoreException.class) + public void failsToCopyToUnrelatedReferenceArray() { + String[] src = { "foo", "bar", "baz" }; + Integer[] dest = new Integer[3]; + System.arraycopy(src, 0, dest, 0, 3); + } + @Test(expected = IndexOutOfBoundsException.class) public void failsToCopyArraysWithInvalidIndexes() { System.arraycopy(new Object[0], 0, new Object[0], 0, 1);