From 7b99bfa21fa6e603ea2762f5615358055e0bfb80 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 15 Mar 2022 18:19:25 +0100 Subject: [PATCH] Copy primitive arrays via `Unsafe.copyMemory()` --- .../swa/trufflesqueak/nodes/plugins/B2D.java | 3 +- .../nodes/primitives/impl/IOPrimitives.java | 55 ++++++++++--------- .../impl/MiscellaneousPrimitives.java | 9 +-- .../swa/trufflesqueak/util/UnsafeUtils.java | 36 ++++++++++++ 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java index 280fc4422..79cd71878 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java @@ -24,6 +24,7 @@ import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.ERROR_TABLE; import de.hpi.swa.trufflesqueak.nodes.SqueakGuards; import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; +import de.hpi.swa.trufflesqueak.util.UnsafeUtils; /* Automatically generated by VMPluginCodeGenerator * VMMaker.oscog-eem.2480 uuid: bb3ffda7-8241-4dea-b886-d656e474b6c1 @@ -591,7 +592,7 @@ private long allocateGradientFillrampWidthisRadial(final int[] ramp, final long workBuffer[rampPtr + i] = transformColor(ramp[i]); } } else { - System.arraycopy(ramp, 0, workBuffer, rampPtr, (int) rampWidth); + UnsafeUtils.copyInts(ramp, 0L, workBuffer, rampPtr, rampWidth); } gradientRampLengthOfput(fill, rampWidth); return fill; diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java index 3ecd009eb..8d20f6b15 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java @@ -65,6 +65,7 @@ import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveFallbacks.TernaryPrimitiveFallback; import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveFallbacks.UnaryPrimitiveFallback; import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; +import de.hpi.swa.trufflesqueak.util.UnsafeUtils; public final class IOPrimitives extends AbstractPrimitiveFactoryHolder { @@ -413,9 +414,9 @@ protected final void doEmptyArrays(final ArrayObject rcvr, final long start, fin @Specialization(guards = {"rcvr.isBooleanType()", "repl.isBooleanType()"}) protected static final void doArraysOfBooleans(final ArrayObject rcvr, final long start, final long stop, final ArrayObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getBooleanStorage(), (int) replStart - 1, rcvr.getBooleanStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getBooleanLength(), start, stop, repl.getBooleanLength(), replStart)) { + UnsafeUtils.copyBytes(repl.getBooleanStorage(), replStart - 1, rcvr.getBooleanStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -424,9 +425,9 @@ protected static final void doArraysOfBooleans(final ArrayObject rcvr, final lon @Specialization(guards = {"rcvr.isCharType()", "repl.isCharType()"}) protected static final void doArraysOfChars(final ArrayObject rcvr, final long start, final long stop, final ArrayObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getCharStorage(), (int) replStart - 1, rcvr.getCharStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getCharLength(), start, stop, repl.getCharLength(), replStart)) { + UnsafeUtils.copyChars(repl.getCharStorage(), replStart - 1, rcvr.getCharStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -435,9 +436,9 @@ protected static final void doArraysOfChars(final ArrayObject rcvr, final long s @Specialization(guards = {"rcvr.isLongType()", "repl.isLongType()"}) protected static final void doArraysOfLongs(final ArrayObject rcvr, final long start, final long stop, final ArrayObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getLongStorage(), (int) replStart - 1, rcvr.getLongStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getLongLength(), start, stop, repl.getLongLength(), replStart)) { + UnsafeUtils.copyLongs(repl.getLongStorage(), replStart - 1, rcvr.getLongStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -446,9 +447,9 @@ protected static final void doArraysOfLongs(final ArrayObject rcvr, final long s @Specialization(guards = {"rcvr.isDoubleType()", "repl.isDoubleType()"}) protected static final void doArraysOfDoubles(final ArrayObject rcvr, final long start, final long stop, final ArrayObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getDoubleStorage(), (int) replStart - 1, rcvr.getDoubleStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getDoubleLength(), start, stop, repl.getDoubleLength(), replStart)) { + UnsafeUtils.copyDoubles(repl.getDoubleStorage(), replStart - 1, rcvr.getDoubleStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -594,9 +595,9 @@ protected abstract static class NativeObjectReplaceNode extends AbstractNode { @Specialization(guards = {"rcvr.isByteType()", "repl.isByteType()"}) protected static final void doNativeBytes(final NativeObject rcvr, final long start, final long stop, final NativeObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getByteStorage(), (int) replStart - 1, rcvr.getByteStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getByteLength(), start, stop, repl.getByteLength(), replStart)) { + UnsafeUtils.copyBytes(repl.getByteStorage(), replStart - 1, rcvr.getByteStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -605,9 +606,9 @@ protected static final void doNativeBytes(final NativeObject rcvr, final long st @Specialization(guards = {"rcvr.isShortType()", "repl.isShortType()"}) protected static final void doNativeShorts(final NativeObject rcvr, final long start, final long stop, final NativeObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getShortStorage(), (int) replStart - 1, rcvr.getShortStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getShortLength(), start, stop, repl.getShortLength(), replStart)) { + UnsafeUtils.copyShorts(repl.getShortStorage(), replStart - 1, rcvr.getShortStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -616,9 +617,9 @@ protected static final void doNativeShorts(final NativeObject rcvr, final long s @Specialization(guards = {"rcvr.isIntType()", "repl.isIntType()"}) protected static final void doNativeInts(final NativeObject rcvr, final long start, final long stop, final NativeObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getIntStorage(), (int) replStart - 1, rcvr.getIntStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getIntLength(), start, stop, repl.getIntLength(), replStart)) { + UnsafeUtils.copyInts(repl.getIntStorage(), replStart - 1, rcvr.getIntStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -627,9 +628,9 @@ protected static final void doNativeInts(final NativeObject rcvr, final long sta @Specialization(guards = {"rcvr.isLongType()", "repl.isLongType()"}) protected static final void doNativeLongs(final NativeObject rcvr, final long start, final long stop, final NativeObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getLongStorage(), (int) replStart - 1, rcvr.getLongStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getLongLength(), start, stop, repl.getLongLength(), replStart)) { + UnsafeUtils.copyLongs(repl.getLongStorage(), replStart - 1, rcvr.getLongStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } @@ -638,9 +639,9 @@ protected static final void doNativeLongs(final NativeObject rcvr, final long st @Specialization(guards = {"rcvr.isByteType()"}) protected static final void doNativeLargeInteger(final NativeObject rcvr, final long start, final long stop, final LargeIntegerObject repl, final long replStart, @Shared("errorProfile") @Cached final BranchProfile errorProfile) { - try { - System.arraycopy(repl.getBytes(), (int) replStart - 1, rcvr.getByteStorage(), (int) start - 1, (int) (1 + stop - start)); - } catch (final IndexOutOfBoundsException e) { + if (inBounds(rcvr.getByteLength(), start, stop, repl.getBytes().length, replStart)) { + UnsafeUtils.copyBytes(repl.getBytes(), replStart - 1, rcvr.getByteStorage(), start - 1, 1 + stop - start); + } else { errorProfile.enter(); throw PrimitiveFailed.BAD_INDEX; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java index e8555b6a6..9c6ca98b2 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java @@ -71,6 +71,7 @@ import de.hpi.swa.trufflesqueak.util.ArrayUtils; import de.hpi.swa.trufflesqueak.util.MiscUtils; import de.hpi.swa.trufflesqueak.util.ObjectGraphUtils; +import de.hpi.swa.trufflesqueak.util.UnsafeUtils; public final class MiscellaneousPrimitives extends AbstractPrimitiveFactoryHolder { @@ -683,7 +684,7 @@ protected static final AbstractPointersObject doCopyWeakPointers(final WeakVaria "receiver.isByteType()", "anotherObject.isByteType()", "receiver.getByteLength() == anotherObject.getByteLength()"}) protected static final NativeObject doCopyNativeByte(final NativeObject receiver, final NativeObject anotherObject) { final byte[] destStorage = receiver.getByteStorage(); - System.arraycopy(anotherObject.getByteStorage(), 0, destStorage, 0, destStorage.length); + UnsafeUtils.copyBytes(anotherObject.getByteStorage(), 0L, destStorage, 0L, destStorage.length); return receiver; } @@ -691,7 +692,7 @@ protected static final NativeObject doCopyNativeByte(final NativeObject receiver "receiver.isShortType()", "anotherObject.isShortType()", "receiver.getShortLength() == anotherObject.getShortLength()"}) protected static final NativeObject doCopyNativeShort(final NativeObject receiver, final NativeObject anotherObject) { final short[] destStorage = receiver.getShortStorage(); - System.arraycopy(anotherObject.getShortStorage(), 0, destStorage, 0, destStorage.length); + UnsafeUtils.copyShorts(anotherObject.getShortStorage(), 0L, destStorage, 0L, destStorage.length); return receiver; } @@ -699,7 +700,7 @@ protected static final NativeObject doCopyNativeShort(final NativeObject receive "receiver.isIntType()", "anotherObject.isIntType()", "receiver.getIntLength() == anotherObject.getIntLength()"}) protected static final NativeObject doCopyNativeInt(final NativeObject receiver, final NativeObject anotherObject) { final int[] destStorage = receiver.getIntStorage(); - System.arraycopy(anotherObject.getIntStorage(), 0, destStorage, 0, destStorage.length); + UnsafeUtils.copyInts(anotherObject.getIntStorage(), 0L, destStorage, 0L, destStorage.length); return receiver; } @@ -707,7 +708,7 @@ protected static final NativeObject doCopyNativeInt(final NativeObject receiver, "receiver.isLongType()", "anotherObject.isLongType()", "receiver.getLongLength() == anotherObject.getLongLength()"}) protected static final NativeObject doCopyNativeLong(final NativeObject receiver, final NativeObject anotherObject) { final long[] destStorage = receiver.getLongStorage(); - System.arraycopy(anotherObject.getLongStorage(), 0, destStorage, 0, destStorage.length); + UnsafeUtils.copyLongs(anotherObject.getLongStorage(), 0L, destStorage, 0L, destStorage.length); return receiver; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/UnsafeUtils.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/UnsafeUtils.java index 61b612351..a8d5f41e7 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/UnsafeUtils.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/UnsafeUtils.java @@ -20,6 +20,42 @@ public final class UnsafeUtils { private UnsafeUtils() { } + public static void copyBytes(final byte[] src, final long srcPos, final byte[] dest, final long destPos, final long length) { + assert 0 <= srcPos && srcPos + length <= src.length && 0 <= destPos && destPos + length <= dest.length; + UNSAFE.copyMemory(src, Unsafe.ARRAY_BYTE_BASE_OFFSET + srcPos * Unsafe.ARRAY_BYTE_INDEX_SCALE, + dest, Unsafe.ARRAY_BYTE_BASE_OFFSET + destPos * Unsafe.ARRAY_BYTE_INDEX_SCALE, Byte.BYTES * length); + } + + public static void copyChars(final char[] src, final long srcPos, final char[] dest, final long destPos, final long length) { + assert 0 <= srcPos && srcPos + length <= src.length && 0 <= destPos && destPos + length <= dest.length; + UNSAFE.copyMemory(src, Unsafe.ARRAY_CHAR_BASE_OFFSET + srcPos * Unsafe.ARRAY_CHAR_INDEX_SCALE, + dest, Unsafe.ARRAY_CHAR_BASE_OFFSET + destPos * Unsafe.ARRAY_CHAR_INDEX_SCALE, Character.BYTES * length); + } + + public static void copyDoubles(final double[] src, final long srcPos, final double[] dest, final long destPos, final long length) { + assert 0 <= srcPos && srcPos + length <= src.length && 0 <= destPos && destPos + length <= dest.length; + UNSAFE.copyMemory(src, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + srcPos * Unsafe.ARRAY_DOUBLE_INDEX_SCALE, + dest, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + destPos * Unsafe.ARRAY_DOUBLE_INDEX_SCALE, Double.BYTES * length); + } + + public static void copyInts(final int[] src, final long srcPos, final int[] dest, final long destPos, final long length) { + assert 0 <= srcPos && srcPos + length <= src.length && 0 <= destPos && destPos + length <= dest.length; + UNSAFE.copyMemory(src, Unsafe.ARRAY_INT_BASE_OFFSET + srcPos * Unsafe.ARRAY_INT_INDEX_SCALE, + dest, Unsafe.ARRAY_INT_BASE_OFFSET + destPos * Unsafe.ARRAY_INT_INDEX_SCALE, Integer.BYTES * length); + } + + public static void copyLongs(final long[] src, final long srcPos, final long[] dest, final long destPos, final long length) { + assert 0 <= srcPos && srcPos + length <= src.length && 0 <= destPos && destPos + length <= dest.length; + UNSAFE.copyMemory(src, Unsafe.ARRAY_LONG_BASE_OFFSET + srcPos * Unsafe.ARRAY_LONG_INDEX_SCALE, + dest, Unsafe.ARRAY_LONG_BASE_OFFSET + destPos * Unsafe.ARRAY_LONG_INDEX_SCALE, Long.BYTES * length); + } + + public static void copyShorts(final short[] src, final long srcPos, final short[] dest, final long destPos, final long length) { + assert 0 <= srcPos && srcPos + length <= src.length && 0 <= destPos && destPos + length <= dest.length; + UNSAFE.copyMemory(src, Unsafe.ARRAY_SHORT_BASE_OFFSET + srcPos * Unsafe.ARRAY_SHORT_INDEX_SCALE, + dest, Unsafe.ARRAY_SHORT_BASE_OFFSET + destPos * Unsafe.ARRAY_SHORT_INDEX_SCALE, Short.BYTES * length); + } + public static long getAddress(final Class javaClass, final String fieldName) { try { return UNSAFE.objectFieldOffset(javaClass.getField(fieldName));