Skip to content

Commit

Permalink
fix(core): buffer attachment offset detection. Close #491
Browse files Browse the repository at this point in the history
  • Loading branch information
Spasi committed Aug 8, 2019
1 parent 2e1549d commit 0e13a49
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 22 deletions.
1 change: 1 addition & 0 deletions doc/notes/3.2.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ This build includes the following changes:

#### Fixes

- Core: Fixed buffer attachment offset detection on JDK 12+. (#491)
- EGL/GLES: Fixed bootstrapping code.
* Regression caused by `org.lwjgl.system.JNI` refactoring in `3.2.2`.
- lmdb: Reverted to the official release. (#482)
Expand Down
38 changes: 16 additions & 22 deletions modules/lwjgl/core/src/main/java/org/lwjgl/system/MemoryUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.nio.*;
import java.nio.charset.*;
import java.util.*;
import java.util.function.*;

import static java.lang.Character.*;
import static java.lang.Math.*;
Expand Down Expand Up @@ -83,6 +82,7 @@ public final class MemoryUtil {
private static final long POSITION;
private static final long LIMIT;
private static final long CAPACITY;

private static final long ADDRESS;

private static final long PARENT_BYTE;
Expand Down Expand Up @@ -110,32 +110,29 @@ public final class MemoryUtil {
UNSAFE = getUnsafeInstance();

try {
ADDRESS = getAddressOffset();
MARK = getMarkOffset();
POSITION = getPositionOffset();
LIMIT = getLimitOffset();
CAPACITY = getCapacityOffset();

ADDRESS = getAddressOffset();

int oopSize = UNSAFE.arrayIndexScale(Object[].class);

PARENT_BYTE = getParentOffset(oopSize, bb, it -> it.duplicate().order(it.order()));
PARENT_SHORT = getParentOffset(oopSize, bb.asShortBuffer(), ShortBuffer::duplicate);
PARENT_CHAR = getParentOffset(oopSize, bb.asCharBuffer(), CharBuffer::duplicate);
PARENT_INT = getParentOffset(oopSize, bb.asIntBuffer(), IntBuffer::duplicate);
PARENT_LONG = getParentOffset(oopSize, bb.asLongBuffer(), LongBuffer::duplicate);
PARENT_FLOAT = getParentOffset(oopSize, bb.asFloatBuffer(), FloatBuffer::duplicate);
PARENT_DOUBLE = getParentOffset(oopSize, bb.asDoubleBuffer(), DoubleBuffer::duplicate);
long offset = (max(max(max(MARK, POSITION), LIMIT), CAPACITY) + 4 + (oopSize - 1)) & ~Integer.toUnsignedLong(oopSize - 1);
long a = memAddress(bb);

PARENT_BYTE = getParentOffset(offset, oopSize, bb, bb.duplicate().order(bb.order()));
PARENT_SHORT = getParentOffset(offset, oopSize, memShortBuffer(a, 0), bb.asShortBuffer());
PARENT_CHAR = getParentOffset(offset, oopSize, memCharBuffer(a, 0), bb.asCharBuffer());
PARENT_INT = getParentOffset(offset, oopSize, memIntBuffer(a, 0), bb.asIntBuffer());
PARENT_LONG = getParentOffset(offset, oopSize, memLongBuffer(a, 0), bb.asLongBuffer());
PARENT_FLOAT = getParentOffset(offset, oopSize, memFloatBuffer(a, 0), bb.asFloatBuffer());
PARENT_DOUBLE = getParentOffset(offset, oopSize, memDoubleBuffer(a, 0), bb.asDoubleBuffer());
} catch (Throwable t) {
throw new UnsupportedOperationException(t);
}

// JDK-12 has a JIT compilation bug related to Unsafe. In LWJGL applications it is triggered when
// making concurrent calls to the custom slice/duplicate implementations, during JVM start-up. An
// effective workaround is to warm-up Unsafe.putObject in a single thread (this static-init block).
for (int i = 0; i < 10000; i++) {
UNSAFE.putObject(bb, PARENT_BYTE, UNSAFE.getObject(bb, PARENT_BYTE));
}

PAGE_SIZE = UNSAFE.pageSize();
CACHE_LINE_SIZE = 64; // TODO: Can we do better?
}
Expand Down Expand Up @@ -2845,21 +2842,18 @@ private static long getCapacityOffset() {
return getIntFieldOffset(bb, MAGIC_CAPACITY);
}

private static <T extends Buffer> long getParentOffset(int oopSize, T parent, Function<T, T> childFactory) {
T child = childFactory.apply(parent);

long offset = oopSize; // pointer aligned, cannot be at 0
private static <T extends Buffer> long getParentOffset(long offset, int oopSize, T buffer, T bufferWithAttachment) {
switch (oopSize) {
case Integer.BYTES: // 32-bit or 64-bit with compressed oops
while (true) {
if (UNSAFE.getInt(parent, offset) != UNSAFE.getInt(child, offset)) {
if (UNSAFE.getInt(buffer, offset) != UNSAFE.getInt(bufferWithAttachment, offset)) {
return offset;
}
offset += oopSize;
}
case Long.BYTES: // 64-bit with uncompressed oops
while (true) {
if (UNSAFE.getLong(parent, offset) != UNSAFE.getLong(child, offset)) {
if (UNSAFE.getLong(buffer, offset) != UNSAFE.getLong(bufferWithAttachment, offset)) {
return offset;
}
offset += oopSize;
Expand Down

0 comments on commit 0e13a49

Please sign in to comment.