--- old/src/java.base/share/classes/java/nio/Bits.java 2016-02-05 13:30:06.837438488 -0800 +++ new/src/java.base/share/classes/java/nio/Bits.java 2016-02-05 13:30:06.665435489 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -808,7 +808,7 @@ } /** - * Copy and byte swap 16 bit elements from a heap array to off-heap memory + * Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory * * @param src * the source array, must be a 16-bit primitive array type @@ -824,7 +824,7 @@ } /** - * Copy and byte swap 16 bit elements from off-heap memory to a heap array + * Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array * * @param srcAddr * source address @@ -840,7 +840,7 @@ } /** - * Copy and byte swap 16 bit elements from a heap array to off-heap memory + * Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory * * @param src * the source array, must be a 16-bit primitive array type @@ -856,7 +856,7 @@ } /** - * Copy and byte swap 16 bit elements from off-heap memory to a heap array + * Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array * * @param srcAddr * source address @@ -872,7 +872,7 @@ } /** - * Copy and byte swap 32 bit elements from a heap array to off-heap memory + * Copy and unconditionally byte swap 32 bit elements from a heap array to off-heap memory * * @param src * the source array, must be a 32-bit primitive array type @@ -888,7 +888,7 @@ } /** - * Copy and byte swap 32 bit elements from off-heap memory to a heap array + * Copy and unconditionally byte swap 32 bit elements from off-heap memory to a heap array * * @param srcAddr * source address @@ -904,7 +904,7 @@ } /** - * Copy and byte swap 64 bit elements from a heap array to off-heap memory + * Copy and unconditionally byte swap 64 bit elements from a heap array to off-heap memory * * @param src * the source array, must be a 64-bit primitive array type @@ -920,7 +920,7 @@ } /** - * Copy and byte swap 64 bit elements from off-heap memory to a heap array + * Copy and unconditionally byte swap 64 bit elements from off-heap memory to a heap array * * @param srcAddr * source address --- old/test/jdk/internal/misc/Unsafe/CopySwap.java 2016-02-05 13:30:06.873439115 -0800 +++ new/test/jdk/internal/misc/Unsafe/CopySwap.java 2016-02-05 13:30:06.681435769 -0800 @@ -147,7 +147,7 @@ byte data = (byte)getVerificationDataForOffset(offset, 1); if (ptr.isOnHeap()) { - UNSAFE.putByte(ptr.getObject(), UNSAFE.arrayBaseOffset(ptr.getObject().getClass()) + offset, data); + UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); } else { UNSAFE.putByte(ptr.getOffset() + offset, data); } @@ -273,7 +273,7 @@ byte actual; if (ptr.isOnHeap()) { - actual = UNSAFE.getByte(ptr.getObject(), UNSAFE.arrayBaseOffset(ptr.getObject().getClass()) + elemOffset); + actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + elemOffset); } else { actual = UNSAFE.getByte(ptr.getOffset() + elemOffset); } @@ -359,9 +359,9 @@ // Copy & swap data into the middle of the destination buffer UNSAFE.copySwapMemory(src.getObject(), - (src.isOnHeap() ? UNSAFE.arrayBaseOffset(src.getObject().getClass()) : src.getOffset()) + srcOffset, + src.getOffset() + srcOffset, dst.getObject(), - (dst.isOnHeap() ? UNSAFE.arrayBaseOffset(dst.getObject().getClass()) : dst.getOffset()) + dstOffset, + dst.getOffset() + dstOffset, copyBytes, elemSize); @@ -544,11 +544,12 @@ bufRaw = UNSAFE.allocateMemory(1024); long buf = alignUp(bufRaw, BASE_ALIGNMENT); + // Check various illegal element sizes for (int elemSize = 2; elemSize <= 8; elemSize <<= 1) { long[] illegalSizes = { -1, 1, elemSize - 1, elemSize + 1, elemSize * 2 - 1 }; for (long size : illegalSizes) { try { - // Check that elemSize 1 throws an IAE + // Check that illegal elemSize throws an IAE UNSAFE.copySwapMemory(null, buf, null, buf, size, elemSize); throw new RuntimeException("copySwapMemory failed to throw IAE for size=" + size + " elemSize=" + elemSize); } catch (IllegalArgumentException e) { @@ -557,6 +558,23 @@ } } + + try { + // Check that negative srcOffset throws an IAE + UNSAFE.copySwapMemory(null, -1, null, buf, 16, 2); + throw new RuntimeException("copySwapMemory failed to throw IAE for srcOffset=-1"); + } catch (IllegalArgumentException e) { + // good + } + + try { + // Check that negative destOffset throws an IAE + UNSAFE.copySwapMemory(null, buf, null, -1, 16, 2); + throw new RuntimeException("copySwapMemory failed to throw IAE for destOffset=-1"); + } catch (IllegalArgumentException e) { + // good + } + long illegalElemSizes[] = { 0, 1, 3, 5, 6, 7, 9, 10, -1 }; for (long elemSize : illegalElemSizes) { try { @@ -591,6 +609,29 @@ } catch (IllegalArgumentException e) { // good } + + // Check that invalid source & dest pointers throw IAEs (only relevant on 32-bit platforms) + if (UNSAFE.addressSize() == 4) { + long invalidPtr = (long)1 << 35; // Pick a random bit in upper 32 bits + + try { + // Check that an invalid (not 32-bit clean) source pointer throws IAE + UNSAFE.copySwapMemory(null, invalidPtr, null, buf, 16, 2); + throw new RuntimeException("copySwapMemory failed to throw IAE for srcOffset 0x" + + Long.toHexString(invalidPtr)); + } catch (IllegalArgumentException e) { + // good + } + + try { + // Check that an invalid (not 32-bit clean) source pointer throws IAE + UNSAFE.copySwapMemory(null, buf, null, invalidPtr, 16, 2); + throw new RuntimeException("copySwapMemory failed to throw IAE for destOffset 0x" + + Long.toHexString(invalidPtr)); + } catch (IllegalArgumentException e) { + // good + } + } } finally { if (bufRaw != 0) { UNSAFE.freeMemory(bufRaw); @@ -617,10 +658,13 @@ * Helper class to represent a "pointer" - either a heap array or * a pointer to a native buffer. * - * Note: this only represents the base object or pointer, not an - * offset into it. That is, only one of the "o" and "offset" - * fields is ever used, never both. - /*/ + * In the case of a native pointer, the Object is null and the offset is + * the absolute address of the native buffer. + * + * In the case of a heap object, the Object is a primitive array, and + * the offset will be set to the base offset to the first element, meaning + * the object and the offset together form a double-register pointer. + */ static class GenericPointer { private final Object o; private final long offset; @@ -645,7 +689,7 @@ } GenericPointer(Object o) { - this(o, 0); + this(o, UNSAFE.arrayBaseOffset(o.getClass())); } GenericPointer(long offset) { --- old/src/java.base/share/classes/jdk/internal/misc/Unsafe.java 2016-02-05 13:30:06.917439881 -0800 +++ new/src/java.base/share/classes/jdk/internal/misc/Unsafe.java 2016-02-05 13:30:06.701436118 -0800 @@ -458,9 +458,19 @@ copyMemory(null, srcAddress, null, destAddress, bytes); } + private boolean isPrimitiveArray(Class c) { + Class componentType = c.getComponentType(); + return componentType != null && componentType.isPrimitive(); + } + + private native void copySwapMemory0(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize); + + /** - * Copies all elements from one block of memory to another block, byte swapping the - * elements on the fly. + * Copies all elements from one block of memory to another block, + * *unconditionally* byte swapping the elements on the fly. * *

This method determines each block's base address by means of two parameters, * and so it provides (in effect) a double-register addressing mode, @@ -469,9 +479,42 @@ * * @since 9 */ - public native void copySwapMemory(Object srcBase, long srcOffset, - Object destBase, long destOffset, - long bytes, long elemSize); + public void copySwapMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize) { + if (bytes < 0 || srcOffset < 0 || destOffset < 0) { + throw new IllegalArgumentException(); + } + if (elemSize != 2 && elemSize != 4 && elemSize != 8) { + throw new IllegalArgumentException(); + } + if (bytes % elemSize != 0) { + throw new IllegalArgumentException(); + } + if ((srcBase == null && srcOffset == 0) || + (destBase == null && destOffset == 0)) { + throw new NullPointerException(); + } + + // Must be off-heap, or primitive heap arrays + if ((srcBase != null && !isPrimitiveArray(srcBase.getClass())) || + (destBase != null && !isPrimitiveArray(destBase.getClass()))) { + throw new IllegalArgumentException(); + } + + // Sanity check size and offsets on 32-bit platforms. Most + // significant 32 bits must be zero. + if (ADDRESS_SIZE == 4 && + (bytes >>> 32 != 0 || srcOffset >>> 32 != 0 || destOffset >>> 32 != 0)) { + throw new IllegalArgumentException(); + } + + if (bytes == 0) { + return; + } + + copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); + } /** * Copies all elements from one block of memory to another block, byte swapping the