Fix fill-array-data on big-endian systems.
The array data comes out of the instruction stream, which is swapped as
if it were a stream of 16-bit code units. This is great for char/short
array data, but comes out wrong for everything else.
This was verified by an external developer with big-endian MIPS hardware.
Should be no change for ARM.
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index fbf0f09..20395cc 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -515,6 +515,62 @@
}
/*
+ * Copy data for a fill-array-data instruction. On a little-endian machine
+ * we can just do a memcpy(), on a big-endian system we have work to do.
+ *
+ * The trick here is that dexopt has byte-swapped each code unit, which is
+ * exactly what we want for short/char data. For byte data we need to undo
+ * the swap, and for 4- or 8-byte values we need to swap pieces within
+ * each word.
+ */
+static void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ memcpy(dest, src, size*width);
+#else
+ int i;
+
+ switch (width) {
+ case 1:
+ /* un-swap pairs of bytes as we go */
+ for (i = (size-1) & ~1; i >= 0; i -= 2) {
+ ((u1*)dest)[i] = ((u1*)src)[i+1];
+ ((u1*)dest)[i+1] = ((u1*)src)[i];
+ }
+ /*
+ * "src" is padded to end on a two-byte boundary, but we don't want to
+ * assume "dest" is, so we handle odd length specially.
+ */
+ if ((size & 1) != 0) {
+ ((u1*)dest)[size-1] = ((u1*)src)[size];
+ }
+ break;
+ case 2:
+ /* already swapped correctly */
+ memcpy(dest, src, size*width);
+ break;
+ case 4:
+ /* swap word halves */
+ for (i = 0; i < (int) size; i++) {
+ ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1];
+ }
+ break;
+ case 8:
+ /* swap word halves and words */
+ for (i = 0; i < (int) (size << 1); i += 2) {
+ ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2];
+ ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1];
+ }
+ break;
+ default:
+ LOGE("Unexpected width %d in copySwappedArrayData\n", width);
+ dvmAbort();
+ break;
+ }
+#endif
+}
+
+/*
* Fill the array with predefined constant values.
*
* Returns true if job is completed, otherwise false to indicate that
@@ -552,7 +608,7 @@
dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
return false;
}
- memcpy(arrayObj->contents, &arrayData[4], size*width);
+ copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
return true;
}