diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py
index 334cc280392f..66f6f0a74deb 100644
--- a/compiler/mx.compiler/suite.py
+++ b/compiler/mx.compiler/suite.py
@@ -488,8 +488,7 @@
"GRAAL",
"GRAAL_MANAGEMENT",
"sdk:NATIVEIMAGE_LIBGRAAL",
- "sdk:JNIUTILS",
- "sdk:NATIVEBRIDGE"
+ "sdk:JNIUTILS"
],
"requiresConcealed" : {
"java.base" : [
diff --git a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryInput.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryInput.java
new file mode 100644
index 000000000000..4709daf692fb
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryInput.java
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2025, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.graal.compiler.libgraal.truffle;
+
+import org.graalvm.nativeimage.c.type.CCharPointer;
+import org.graalvm.nativeimage.c.type.CTypeConversion;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.ARRAY;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.BOOLEAN;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.BYTE;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.CHAR;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.DOUBLE;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.FLOAT;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.INT;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.LARGE_STRING_TAG;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.LONG;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.NULL;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.SHORT;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.STRING;
+import static jdk.graal.compiler.libgraal.truffle.BinaryOutput.bufferSize;
+
+/**
+ * This is a copy of {@code org.graalvm.nativebridge.BinaryInput} to avoid an external dependency.
+ */
+public abstract class BinaryInput {
+
+ private static final int EOF = -1;
+
+ private byte[] tempEncodingByteBuffer;
+ private char[] tempEncodingCharBuffer;
+ protected final int length;
+ protected int pos;
+
+ private BinaryInput(int length) {
+ this.length = length;
+ }
+
+ /**
+ * Reads a single byte and returns {@code true} if that byte is non-zero, {@code false} if that
+ * byte is zero.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final boolean readBoolean() throws IndexOutOfBoundsException {
+ int b = read();
+ if (b < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ return b != 0;
+ }
+
+ /**
+ * Reads and returns a single byte.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final byte readByte() throws IndexOutOfBoundsException {
+ int b = read();
+ if (b < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ return (byte) b;
+ }
+
+ /**
+ * Reads two bytes and returns a {@code short} value.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final short readShort() throws IndexOutOfBoundsException {
+ int b1 = read();
+ int b2 = read();
+ if ((b1 | b2) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ return packShort(b1, b2);
+ }
+
+ /**
+ * Creates a Java {@code short} from given unsigned bytes, where {@code b1} is the most
+ * significant byte {@code byte} and {@code b2} is the least significant {@code byte}.
+ */
+ private static short packShort(int b1, int b2) {
+ return (short) ((b1 << 8) + b2);
+ }
+
+ /**
+ * Reads two bytes and returns a {@code char} value.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final char readChar() throws IndexOutOfBoundsException {
+ int b1 = read();
+ int b2 = read();
+ if ((b1 | b2) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ return packChar(b1, b2);
+ }
+
+ /**
+ * Creates a Java {@code char} from given unsigned bytes, where {@code b1} is the most
+ * significant byte {@code byte} and {@code b2} is the least significant {@code byte}.
+ */
+ private static char packChar(int b1, int b2) {
+ return (char) ((b1 << 8) + b2);
+ }
+
+ /**
+ * Reads four bytes and returns an {@code int} value.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final int readInt() throws IndexOutOfBoundsException {
+ int b1 = read();
+ int b2 = read();
+ int b3 = read();
+ int b4 = read();
+ if ((b1 | b2 | b3 | b4) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ return packInt(b1, b2, b3, b4);
+ }
+
+ /**
+ * Creates a Java {@code int} from given unsigned bytes, where {@code b1} is the most
+ * significant byte {@code byte} and {@code b4} is the least significant {@code byte}.
+ */
+ private static int packInt(int b1, int b2, int b3, int b4) {
+ return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
+ }
+
+ /**
+ * Reads eight bytes and returns a {@code long} value.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final long readLong() throws IndexOutOfBoundsException {
+ int b1 = read();
+ int b2 = read();
+ int b3 = read();
+ int b4 = read();
+ int b5 = read();
+ int b6 = read();
+ int b7 = read();
+ int b8 = read();
+ if ((b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ return packLong(b1, b2, b3, b4, b5, b6, b7, b8);
+ }
+
+ /**
+ * Creates a Java {@code long} from given unsigned bytes, where {@code b1} is the most
+ * significant byte {@code byte} and {@code b8} is the least significant {@code byte}.
+ */
+ private static long packLong(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8) {
+ return ((long) b1 << 56) + ((long) b2 << 48) + ((long) b3 << 40) + ((long) b4 << 32) +
+ ((long) b5 << 24) + ((long) b6 << 16) + ((long) b7 << 8) + b8;
+ }
+
+ /**
+ * Reads four bytes and returns a {@code float} value. It does this by reading an {@code int}
+ * value and converting the {@code int} value to a {@code float} using
+ * {@link Float#intBitsToFloat(int)}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final float readFloat() throws IndexOutOfBoundsException {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * Reads eight bytes and returns a {@code double} value. It does this by reading a {@code long}
+ * value and converting the {@code long} value to a {@code double} using
+ * {@link Double#longBitsToDouble(long)}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ */
+ public final double readDouble() throws IndexOutOfBoundsException {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ /**
+ * Reads a single byte. The byte value is returned as an {@code int} in the range {@code 0} to
+ * {@code 255}. If no byte is available because the end of the stream has been reached, the
+ * value {@code -1} is returned.
+ */
+ public abstract int read();
+
+ /**
+ * Reads {@code len} bytes into a byte array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public abstract void read(byte[] b, int off, int len) throws IndexOutOfBoundsException;
+
+ /**
+ * Reads a string using a modified UTF-8 encoding in a machine-independent manner.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ * @throws IllegalArgumentException if the bytes do not represent a valid modified UTF-8
+ * encoding of a string.
+ */
+ public final String readUTF() throws IndexOutOfBoundsException, IllegalArgumentException {
+ int len;
+ int b1 = read();
+ int b2 = read();
+ if ((b1 | b2) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if ((b1 & LARGE_STRING_TAG) == LARGE_STRING_TAG) {
+ int b3 = read();
+ int b4 = read();
+ if ((b3 | b4) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ len = ((b1 & ~LARGE_STRING_TAG) << 24) + (b2 << 16) + (b3 << 8) + b4;
+ } else {
+ len = (b1 << 8) + b2;
+ }
+ ensureBufferSize(len);
+ if (tempEncodingCharBuffer == null || tempEncodingCharBuffer.length < len) {
+ tempEncodingCharBuffer = new char[Math.max(bufferSize(0, len), 80)];
+ }
+
+ int c1;
+ int c2;
+ int c3;
+ int byteCount = 0;
+ int charCount = 0;
+
+ read(tempEncodingByteBuffer, 0, len);
+
+ while (byteCount < len) {
+ c1 = tempEncodingByteBuffer[byteCount] & 0xff;
+ if (c1 > 127) {
+ break;
+ }
+ byteCount++;
+ tempEncodingCharBuffer[charCount++] = (char) c1;
+ }
+
+ while (byteCount < len) {
+ c1 = tempEncodingByteBuffer[byteCount] & 0xff;
+ switch (c1 >> 4) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ /* 0xxxxxxx */
+ byteCount++;
+ tempEncodingCharBuffer[charCount++] = (char) c1;
+ break;
+ case 12:
+ case 13:
+ /* 110x xxxx 10xx xxxx */
+ byteCount += 2;
+ if (byteCount > len) {
+ throw new IllegalArgumentException("Partial character at end");
+ }
+ c2 = tempEncodingByteBuffer[byteCount - 1];
+ if ((c2 & 0xC0) != 0x80) {
+ throw new IllegalArgumentException("malformed input around byte " + byteCount);
+ }
+ tempEncodingCharBuffer[charCount++] = (char) (((c1 & 0x1F) << 6) | (c2 & 0x3F));
+ break;
+ case 14:
+ /* 1110 xxxx 10xx xxxx 10xx xxxx */
+ byteCount += 3;
+ if (byteCount > len) {
+ throw new IllegalArgumentException("malformed input: partial character at end");
+ }
+ c2 = tempEncodingByteBuffer[byteCount - 2];
+ c3 = tempEncodingByteBuffer[byteCount - 1];
+ if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) {
+ throw new IllegalArgumentException("malformed input around byte " + (byteCount - 1));
+ }
+ tempEncodingCharBuffer[charCount++] = (char) (((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+ break;
+ default:
+ /* 10xx xxxx, 1111 xxxx */
+ throw new IllegalArgumentException("malformed input around byte " + byteCount);
+ }
+ }
+ // The number of chars produced may be less than len
+ return new String(tempEncodingCharBuffer, 0, charCount);
+ }
+
+ /**
+ * Reads a single value, using the data type encoded in the marshalled data.
+ *
+ * @return The read value, such as a boxed Java primitive, a {@link String}, a {@code null}, or
+ * an array of these types.
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read.
+ * @throws IllegalArgumentException when the marshaled type is not supported or if the bytes do
+ * not represent a valid modified UTF-8 encoding of a string.
+ */
+ public final Object readTypedValue() throws IndexOutOfBoundsException, IllegalArgumentException {
+ byte tag = readByte();
+ switch (tag) {
+ case ARRAY:
+ int len = readInt();
+ Object[] arr = new Object[len];
+ for (int i = 0; i < len; i++) {
+ arr[i] = readTypedValue();
+ }
+ return arr;
+ case NULL:
+ return null;
+ case BOOLEAN:
+ return readBoolean();
+ case BYTE:
+ return readByte();
+ case SHORT:
+ return readShort();
+ case CHAR:
+ return readChar();
+ case INT:
+ return readInt();
+ case LONG:
+ return readLong();
+ case FLOAT:
+ return readFloat();
+ case DOUBLE:
+ return readDouble();
+ case STRING:
+ return readUTF();
+ default:
+ throw new IllegalArgumentException(String.format("Unknown tag %d", tag));
+ }
+ }
+
+ /**
+ * Reads {@code len} bytes into a boolean array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public final void read(boolean[] b, int off, int len) {
+ ensureBufferSize(len);
+ read(tempEncodingByteBuffer, 0, len);
+ int limit = off + len;
+ for (int i = off, j = 0; i < limit; i++) {
+ b[i] = tempEncodingByteBuffer[j++] != 0;
+ }
+ }
+
+ /**
+ * Reads {@code len} shorts into a short array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public final void read(short[] b, int off, int len) {
+ int size = len * Short.BYTES;
+ ensureBufferSize(size);
+ read(tempEncodingByteBuffer, 0, size);
+ int limit = off + len;
+ for (int i = off, j = 0; i < limit; i++) {
+ int b1 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b2 = (tempEncodingByteBuffer[j++] & 0xff);
+ b[i] = packShort(b1, b2);
+ }
+ }
+
+ /**
+ * Reads {@code len} chars into a char array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public final void read(char[] b, int off, int len) {
+ int size = len * Character.BYTES;
+ ensureBufferSize(size);
+ read(tempEncodingByteBuffer, 0, size);
+ int limit = off + len;
+ for (int i = off, j = 0; i < limit; i++) {
+ int b1 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b2 = (tempEncodingByteBuffer[j++] & 0xff);
+ b[i] = packChar(b1, b2);
+ }
+ }
+
+ /**
+ * Reads {@code len} ints into an int array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public final void read(int[] b, int off, int len) {
+ int size = len * Integer.BYTES;
+ ensureBufferSize(size);
+ read(tempEncodingByteBuffer, 0, size);
+ int limit = off + len;
+ for (int i = off, j = 0; i < limit; i++) {
+ int b1 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b2 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b3 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b4 = (tempEncodingByteBuffer[j++] & 0xff);
+ b[i] = packInt(b1, b2, b3, b4);
+ }
+ }
+
+ /**
+ * Reads {@code len} longs into a long array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public final void read(long[] b, int off, int len) {
+ int size = len * Long.BYTES;
+ ensureBufferSize(size);
+ read(tempEncodingByteBuffer, 0, size);
+ int limit = off + len;
+ for (int i = off, j = 0; i < limit; i++) {
+ int b1 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b2 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b3 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b4 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b5 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b6 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b7 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b8 = (tempEncodingByteBuffer[j++] & 0xff);
+ b[i] = packLong(b1, b2, b3, b4, b5, b6, b7, b8);
+ }
+ }
+
+ /**
+ * Reads {@code len} floats into a float array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public final void read(float[] b, int off, int len) {
+ int size = len * Float.BYTES;
+ ensureBufferSize(size);
+ read(tempEncodingByteBuffer, 0, size);
+ int limit = off + len;
+ for (int i = off, j = 0; i < limit; i++) {
+ int b1 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b2 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b3 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b4 = (tempEncodingByteBuffer[j++] & 0xff);
+ b[i] = Float.intBitsToFloat(packInt(b1, b2, b3, b4));
+ }
+ }
+
+ /**
+ * Reads {@code len} doubles into a double array starting at offset {@code off}.
+ *
+ * @throws IndexOutOfBoundsException if there are not enough bytes to read
+ */
+ public final void read(double[] b, int off, int len) {
+ int size = len * Double.BYTES;
+ ensureBufferSize(size);
+ read(tempEncodingByteBuffer, 0, size);
+ int limit = off + len;
+ for (int i = off, j = 0; i < limit; i++) {
+ int b1 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b2 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b3 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b4 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b5 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b6 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b7 = (tempEncodingByteBuffer[j++] & 0xff);
+ int b8 = (tempEncodingByteBuffer[j++] & 0xff);
+ b[i] = Double.longBitsToDouble(packLong(b1, b2, b3, b4, b5, b6, b7, b8));
+ }
+ }
+
+ /**
+ * Returns a read only {@link ByteBuffer} backed by the {@link BinaryInput} internal buffer. The
+ * content of the buffer will start at the {@link BinaryInput}'s current position. The buffer's
+ * capacity and limit will be {@code len}, its position will be zero, its mark will be
+ * undefined, and its byte order will be {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN}. After a
+ * successful call, the {@link BinaryInput}'s current position is incremented by the
+ * {@code len}.
+ *
+ * @throws IndexOutOfBoundsException if the BinaryInput has not enough remaining bytes.
+ */
+ public abstract ByteBuffer asByteBuffer(int len);
+
+ /**
+ * Creates a new buffer backed by a byte array.
+ */
+ public static BinaryInput create(byte[] buffer) {
+ return new ByteArrayBinaryInput(buffer);
+ }
+
+ /**
+ * Creates a new buffer backed by a byte array only up to a given length.
+ */
+ public static BinaryInput create(byte[] buffer, int length) {
+ return new ByteArrayBinaryInput(buffer, length);
+ }
+
+ /**
+ * Creates a new buffer wrapping an off-heap memory segment starting at an {@code address}
+ * having {@code length} bytes.
+ */
+ public static BinaryInput create(CCharPointer address, int length) {
+ return new CCharPointerInput(address, length);
+ }
+
+ private void ensureBufferSize(int len) {
+ if (tempEncodingByteBuffer == null || tempEncodingByteBuffer.length < len) {
+ tempEncodingByteBuffer = new byte[Math.max(bufferSize(0, len), 80)];
+ }
+ }
+
+ private static final class ByteArrayBinaryInput extends BinaryInput {
+
+ private final byte[] buffer;
+
+ ByteArrayBinaryInput(byte[] buffer) {
+ super(buffer.length);
+ this.buffer = buffer;
+ }
+
+ ByteArrayBinaryInput(byte[] buffer, int length) {
+ super(length);
+ this.buffer = buffer;
+ }
+
+ @Override
+ public int read() {
+ if (pos >= length) {
+ return EOF;
+ }
+ return (buffer[pos++] & 0xff);
+ }
+
+ @Override
+ public void read(byte[] b, int off, int len) {
+ if (len < 0) {
+ throw new IllegalArgumentException(String.format("Len must be non negative but was %d", len));
+ }
+ if (pos + len > length) {
+ throw new IndexOutOfBoundsException();
+ }
+ System.arraycopy(buffer, pos, b, off, len);
+ pos += len;
+ }
+
+ @Override
+ public ByteBuffer asByteBuffer(int len) {
+ ByteBuffer result = ByteBuffer.wrap(buffer, pos, len).slice().asReadOnlyBuffer();
+ pos += len;
+ return result;
+ }
+ }
+
+ private static final class CCharPointerInput extends BinaryInput {
+
+ /**
+ * Represents the point at which the average cost of a JNI call exceeds the expense of an
+ * element by element copy. See {@code java.nio.Bits#JNI_COPY_TO_ARRAY_THRESHOLD}.
+ */
+ private static final int BYTEBUFFER_COPY_TO_ARRAY_THRESHOLD = 6;
+
+ private final CCharPointer address;
+ /**
+ * ByteBuffer view of this {@link CCharPointerInput} direct memory. The ByteBuffer is used
+ * for bulk data transfers, where the bulk ByteBuffer operations outperform element by
+ * element copying by an order of magnitude.
+ */
+ private ByteBuffer byteBufferView;
+
+ CCharPointerInput(CCharPointer address, int length) {
+ super(length);
+ this.address = address;
+ }
+
+ @Override
+ public int read() {
+ if (pos >= length) {
+ return EOF;
+ }
+ return (address.read(pos++) & 0xff);
+ }
+
+ @Override
+ public void read(byte[] b, int off, int len) {
+ if (len < 0) {
+ throw new IllegalArgumentException(String.format("Len must be non negative but was %d", len));
+ }
+ if (pos + len > length) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (len > BYTEBUFFER_COPY_TO_ARRAY_THRESHOLD) {
+ if (byteBufferView == null) {
+ byteBufferView = CTypeConversion.asByteBuffer(address, length);
+ }
+ byteBufferView.position(pos);
+ byteBufferView.get(b, off, len);
+ } else {
+ for (int i = 0, j = pos; i < len; i++, j++) {
+ b[off + i] = address.read(j);
+ }
+ }
+ pos += len;
+ }
+
+ @Override
+ public ByteBuffer asByteBuffer(int len) {
+ ByteBuffer result = CTypeConversion.asByteBuffer(address.addressOf(pos), len).order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer();
+ pos += len;
+ return result;
+ }
+ }
+}
diff --git a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryOutput.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryOutput.java
new file mode 100644
index 000000000000..a2190eec77d6
--- /dev/null
+++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/BinaryOutput.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2025, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.graal.compiler.libgraal.truffle;
+
+import org.graalvm.nativeimage.UnmanagedMemory;
+import org.graalvm.nativeimage.c.type.CCharPointer;
+import org.graalvm.nativeimage.c.type.CTypeConversion;
+import org.graalvm.word.WordFactory;
+
+import java.io.Closeable;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * This is a copy of {@code org.graalvm.nativebridge.BinaryInput} to avoid an external dependency.
+ */
+public abstract class BinaryOutput {
+
+ /**
+ * Maximum string length for string encoded by 4 bytes length followed be content.
+ */
+ private static final int MAX_LENGTH = Integer.MAX_VALUE - Integer.BYTES;
+ /**
+ * Maximum string length for string encoded by 2 bytes length followed be content.
+ */
+ private static final int MAX_SHORT_LENGTH = Short.MAX_VALUE;
+ /**
+ * Tag to distinguish between long and short string. The tag is set in the first string length
+ * byte.
+ */
+ static final int LARGE_STRING_TAG = 1 << 7;
+
+ // Type tags used by writeTypedValue
+ static final byte NULL = 0;
+ static final byte BOOLEAN = NULL + 1;
+ static final byte BYTE = BOOLEAN + 1;
+ static final byte SHORT = BYTE + 1;
+ static final byte CHAR = SHORT + 1;
+ static final byte INT = CHAR + 1;
+ static final byte LONG = INT + 1;
+ static final byte FLOAT = LONG + 1;
+ static final byte DOUBLE = FLOAT + 1;
+ static final byte STRING = DOUBLE + 1;
+ static final byte ARRAY = STRING + 1;
+
+ private byte[] tempDecodingBuffer;
+ protected int pos;
+
+ private BinaryOutput() {
+ }
+
+ /**
+ * Writes a {@code boolean} as a single byte value. The value {@code true} is written as the
+ * value {@code (byte)1}, the value {@code false} is written as the value {@code (byte)0}. The
+ * buffer position is incremented by {@code 1}.
+ */
+ public final void writeBoolean(boolean value) {
+ write(value ? 1 : 0);
+ }
+
+ /**
+ * Writes a {@code byte} as a single byte value. The buffer position is incremented by
+ * {@code 1}.
+ */
+ public final void writeByte(int value) {
+ write(value);
+ }
+
+ /**
+ * Writes a {@code short} as two bytes, high byte first. The buffer position is incremented by
+ * {@code 2}.
+ */
+ public final void writeShort(int value) {
+ write((value >>> 8) & 0xff);
+ write(value & 0xff);
+ }
+
+ /**
+ * Writes a {@code char} as two bytes, high byte first. The buffer position is incremented by
+ * {@code 2}.
+ */
+ public final void writeChar(int value) {
+ write((value >>> 8) & 0xff);
+ write(value & 0xff);
+ }
+
+ /**
+ * Writes an {@code int} as four bytes, high byte first. The buffer position is incremented by
+ * {@code 4}.
+ */
+ public final void writeInt(int value) {
+ write((value >>> 24) & 0xff);
+ write((value >>> 16) & 0xff);
+ write((value >>> 8) & 0xff);
+ write(value & 0xff);
+ }
+
+ /**
+ * Writes a {@code long} as eight bytes, high byte first. The buffer position is incremented by
+ * {@code 8}.
+ */
+ public final void writeLong(long value) {
+ write((int) ((value >>> 56) & 0xff));
+ write((int) ((value >>> 48) & 0xff));
+ write((int) ((value >>> 40) & 0xff));
+ write((int) ((value >>> 32) & 0xff));
+ write((int) ((value >>> 24) & 0xff));
+ write((int) ((value >>> 16) & 0xff));
+ write((int) ((value >>> 8) & 0xff));
+ write((int) (value & 0xff));
+ }
+
+ /**
+ * Converts a {@code float} value to an {@code int} using the
+ * {@link Float#floatToIntBits(float)}, and then writes that {@code int} as four bytes, high
+ * byte first. The buffer position is incremented by {@code 4}.
+ */
+ public final void writeFloat(float value) {
+ writeInt(Float.floatToIntBits(value));
+ }
+
+ /**
+ * Converts a {@code double} value to a {@code long} using the
+ * {@link Double#doubleToLongBits(double)}, and then writes that {@code long} as eight bytes,
+ * high byte first. The buffer position is incremented by {@code 8}.
+ */
+ public final void writeDouble(double value) {
+ writeLong(Double.doubleToLongBits(value));
+ }
+
+ /**
+ * Writes the lowest byte of the argument as a single byte value. The buffer position is
+ * incremented by {@code 1}.
+ */
+ public abstract void write(int b);
+
+ /**
+ * Writes {@code len} bytes from the byte {@code array} starting at offset {@code off}. The
+ * buffer position is incremented by {@code len}.
+ */
+ public abstract void write(byte[] array, int off, int len);
+
+ /**
+ * Reserves a buffer space. The reserved space can be used for out parameters.
+ *
+ * @param numberOfBytes number of bytes to reserve.
+ */
+ public abstract void skip(int numberOfBytes);
+
+ /**
+ * Writes a string using a modified UTF-8 encoding in a machine-independent manner.
+ *
+ * @throws IllegalArgumentException if the {@code string} cannot be encoded using modified UTF-8
+ * encoding.
+ */
+ public final void writeUTF(String string) throws IllegalArgumentException {
+ int len = string.length();
+ long utfLen = 0;
+ int c;
+ int count = 0;
+
+ for (int i = 0; i < len; i++) {
+ c = string.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ utfLen++;
+ } else if (c > 0x07FF) {
+ utfLen += 3;
+ } else {
+ utfLen += 2;
+ }
+ }
+
+ if (utfLen > MAX_LENGTH) {
+ throw new IllegalArgumentException("String too long to encode, " + utfLen + " bytes");
+ }
+ int headerSize;
+ if (utfLen > MAX_SHORT_LENGTH) {
+ headerSize = Integer.BYTES;
+ ensureBufferSize(headerSize, (int) utfLen);
+ tempDecodingBuffer[count++] = (byte) ((LARGE_STRING_TAG | (utfLen >>> 24)) & 0xff);
+ tempDecodingBuffer[count++] = (byte) ((utfLen >>> 16) & 0xFF);
+ } else {
+ headerSize = Short.BYTES;
+ ensureBufferSize(headerSize, (int) utfLen);
+ }
+ tempDecodingBuffer[count++] = (byte) ((utfLen >>> 8) & 0xFF);
+ tempDecodingBuffer[count++] = (byte) (utfLen & 0xFF);
+
+ int i = 0;
+ for (; i < len; i++) {
+ c = string.charAt(i);
+ if (!((c >= 0x0001) && (c <= 0x007F))) {
+ break;
+ }
+ tempDecodingBuffer[count++] = (byte) c;
+ }
+
+ for (; i < len; i++) {
+ c = string.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ tempDecodingBuffer[count++] = (byte) c;
+ } else if (c > 0x07FF) {
+ tempDecodingBuffer[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+ tempDecodingBuffer[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
+ tempDecodingBuffer[count++] = (byte) (0x80 | (c & 0x3F));
+ } else {
+ tempDecodingBuffer[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
+ tempDecodingBuffer[count++] = (byte) (0x80 | (c & 0x3F));
+ }
+ }
+ write(tempDecodingBuffer, 0, (int) (headerSize + utfLen));
+ }
+
+ /**
+ * Returns this buffer's position.
+ */
+ public int getPosition() {
+ return pos;
+ }
+
+ /**
+ * Returns true if a value is a typed value writable using
+ * {@link #writeTypedValue(Object)}, else false.
+ */
+ public static boolean isTypedValue(Object value) {
+ if (value == null) {
+ return true;
+ }
+ return value instanceof Object[] || value instanceof Boolean || value instanceof Byte ||
+ value instanceof Short || value instanceof Character || value instanceof Integer ||
+ value instanceof Long || value instanceof Float || value instanceof Double || value instanceof String;
+ }
+
+ /**
+ * Writes the value that is represented by the given object, together with information on the
+ * value's data type. Supported types are boxed Java primitive types, {@link String},
+ * {@code null}, and arrays of these types.
+ *
+ * @throws IllegalArgumentException when the {@code value} type is not supported or the
+ * {@code value} is a string which cannot be encoded using modified UTF-8 encoding.
+ * @see #isTypedValue(Object) to find out whether a value can be serialized.
+ */
+ public final void writeTypedValue(Object value) throws IllegalArgumentException {
+ if (value instanceof Object[] arr) {
+ writeByte(ARRAY);
+ writeInt(arr.length);
+ for (Object arrElement : arr) {
+ writeTypedValue(arrElement);
+ }
+ } else if (value == null) {
+ writeByte(NULL);
+ } else if (value instanceof Boolean) {
+ writeByte(BOOLEAN);
+ writeBoolean((boolean) value);
+ } else if (value instanceof Byte) {
+ writeByte(BYTE);
+ writeByte((byte) value);
+ } else if (value instanceof Short) {
+ writeByte(SHORT);
+ writeShort((short) value);
+ } else if (value instanceof Character) {
+ writeByte(CHAR);
+ writeChar((char) value);
+ } else if (value instanceof Integer) {
+ writeByte(INT);
+ writeInt((int) value);
+ } else if (value instanceof Long) {
+ writeByte(LONG);
+ writeLong((long) value);
+ } else if (value instanceof Float) {
+ writeByte(FLOAT);
+ writeFloat((float) value);
+ } else if (value instanceof Double) {
+ writeByte(DOUBLE);
+ writeDouble((double) value);
+ } else if (value instanceof String) {
+ writeByte(STRING);
+ writeUTF((String) value);
+ } else {
+ throw new IllegalArgumentException(String.format("Unsupported type %s", value.getClass()));
+ }
+ }
+
+ /**
+ * Writes {@code len} bytes from the boolean {@code array} starting at offset {@code off}. The
+ * value {@code true} is written as the value {@code (byte)1}, the value {@code false} is
+ * written as the value {@code (byte)0}. The buffer position is incremented by {@code len}.
+ */
+ public final void write(boolean[] array, int off, int len) {
+ ensureBufferSize(0, len);
+ for (int i = 0, j = 0; i < len; i++, j++) {
+ tempDecodingBuffer[j] = (byte) (array[off + i] ? 1 : 0);
+ }
+ write(tempDecodingBuffer, 0, len);
+ }
+
+ /**
+ * Writes {@code len} shorts from the {@code array} starting at offset {@code off}. The buffer
+ * position is incremented by {@code 2 * len}.
+ */
+ public final void write(short[] array, int off, int len) {
+ int size = len * Short.BYTES;
+ ensureBufferSize(0, size);
+ for (int i = 0, j = 0; i < len; i++) {
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 8) & 0xff);
+ tempDecodingBuffer[j++] = (byte) (array[off + i] & 0xff);
+ }
+ write(tempDecodingBuffer, 0, size);
+ }
+
+ /**
+ * Writes {@code len} chars from the {@code array} starting at offset {@code off}. The buffer
+ * position is incremented by {@code 2 * len}.
+ */
+ public final void write(char[] array, int off, int len) {
+ int size = len * Character.BYTES;
+ ensureBufferSize(0, size);
+ for (int i = 0, j = 0; i < len; i++) {
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 8) & 0xff);
+ tempDecodingBuffer[j++] = (byte) (array[off + i] & 0xff);
+ }
+ write(tempDecodingBuffer, 0, size);
+ }
+
+ /**
+ * Writes {@code len} ints from the {@code array} starting at offset {@code off}. The buffer
+ * position is incremented by {@code 4 * len}.
+ */
+ public final void write(int[] array, int off, int len) {
+ int size = len * Integer.BYTES;
+ ensureBufferSize(0, size);
+ for (int i = 0, j = 0; i < len; i++) {
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 24) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 16) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 8) & 0xff);
+ tempDecodingBuffer[j++] = (byte) (array[off + i] & 0xff);
+ }
+ write(tempDecodingBuffer, 0, size);
+ }
+
+ /**
+ * Writes {@code len} longs from the {@code array} starting at offset {@code off}. The buffer
+ * position is incremented by {@code 8 * len}.
+ */
+ public final void write(long[] array, int off, int len) {
+ int size = len * Long.BYTES;
+ ensureBufferSize(0, size);
+ for (int i = 0, j = 0; i < len; i++) {
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 56) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 48) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 40) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 32) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 24) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 16) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((array[off + i] >>> 8) & 0xff);
+ tempDecodingBuffer[j++] = (byte) (array[off + i] & 0xff);
+ }
+ write(tempDecodingBuffer, 0, size);
+ }
+
+ /**
+ * Writes {@code len} floats from the {@code array} starting at offset {@code off}. Each
+ * {@code float} value is converted to an {@code int} using the
+ * {@link Float#floatToIntBits(float)} and written as an int. The buffer position is incremented
+ * by {@code 4 * len}.
+ */
+ public final void write(float[] array, int off, int len) {
+ int size = len * Float.BYTES;
+ ensureBufferSize(0, size);
+ for (int i = 0, j = 0; i < len; i++) {
+ int bits = Float.floatToIntBits(array[off + i]);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 24) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 16) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 8) & 0xff);
+ tempDecodingBuffer[j++] = (byte) (bits & 0xff);
+ }
+ write(tempDecodingBuffer, 0, size);
+ }
+
+ /**
+ * Writes {@code len} doubles from the {@code array} starting at offset {@code off}. Each
+ * {@code double} value is converted to an {@code lang} using the
+ * {@link Double#doubleToLongBits(double)} and written as a long. The buffer position is
+ * incremented by {@code 8 * len}.
+ */
+ public final void write(double[] array, int off, int len) {
+ int size = len * Double.BYTES;
+ ensureBufferSize(Integer.BYTES, size);
+ for (int i = 0, j = 0; i < len; i++) {
+ long bits = Double.doubleToLongBits(array[off + i]);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 56) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 48) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 40) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 32) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 24) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 16) & 0xff);
+ tempDecodingBuffer[j++] = (byte) ((bits >>> 8) & 0xff);
+ tempDecodingBuffer[j++] = (byte) (bits & 0xff);
+ }
+ write(tempDecodingBuffer, 0, size);
+ }
+
+ private void ensureBufferSize(int headerSize, int dataSize) {
+ if (tempDecodingBuffer == null || tempDecodingBuffer.length < (headerSize + dataSize)) {
+ tempDecodingBuffer = new byte[bufferSize(headerSize, dataSize)];
+ }
+ }
+
+ /**
+ * Creates a new buffer backed by a byte array.
+ */
+ public static ByteArrayBinaryOutput create() {
+ return new ByteArrayBinaryOutput(ByteArrayBinaryOutput.INITIAL_SIZE);
+ }
+
+ /**
+ * Creates a new buffer wrapping the {@code initialBuffer}. If the {@code initialBuffer}
+ * capacity is not sufficient for writing the data, a new array is allocated. Always use
+ * {@link ByteArrayBinaryOutput#getArray()} to obtain the marshaled data.
+ */
+ public static ByteArrayBinaryOutput create(byte[] initialBuffer) {
+ Objects.requireNonNull(initialBuffer, "InitialBuffer must be non null.");
+ return new ByteArrayBinaryOutput(initialBuffer);
+ }
+
+ /**
+ * Creates a new buffer wrapping an off-heap memory segment starting at {@code address} having
+ * {@code length} bytes. If the capacity of an off-heap memory segment is not sufficient for
+ * writing the data, a new off-heap memory is allocated. Always use
+ * {@link CCharPointerBinaryOutput#getAddress()} to obtain the marshaled data.
+ *
+ * @param address the off-heap memory address
+ * @param length the off-heap memory size
+ * @param dynamicallyAllocated {@code true} if the memory was dynamically allocated and should
+ * be freed when the buffer is closed; {@code false} for the stack allocated memory.
+ */
+ public static CCharPointerBinaryOutput create(CCharPointer address, int length, boolean dynamicallyAllocated) {
+ return new CCharPointerBinaryOutput(address, length, dynamicallyAllocated);
+ }
+
+ static int bufferSize(int headerSize, int dataSize) {
+ return headerSize + (dataSize <= MAX_SHORT_LENGTH ? dataSize << 1 : dataSize);
+ }
+
+ /**
+ * A {@link BinaryOutput} backed by a byte array.
+ */
+ public static final class ByteArrayBinaryOutput extends BinaryOutput {
+
+ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+ static final int INITIAL_SIZE = 32;
+
+ private byte[] buffer;
+
+ private ByteArrayBinaryOutput(int size) {
+ buffer = new byte[size];
+ }
+
+ private ByteArrayBinaryOutput(byte[] initialBuffer) {
+ buffer = initialBuffer;
+ }
+
+ @Override
+ public void write(int b) {
+ ensureCapacity(pos + 1);
+ buffer[pos] = (byte) b;
+ pos += 1;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) {
+ ensureCapacity(pos + len);
+ System.arraycopy(b, off, buffer, pos, len);
+ pos += len;
+ }
+
+ @Override
+ public void skip(int numberOfBytes) {
+ ensureCapacity(pos + numberOfBytes);
+ pos += numberOfBytes;
+ }
+
+ /**
+ * Returns the byte array containing the marshalled data.
+ */
+ public byte[] getArray() {
+ return buffer;
+ }
+
+ private void ensureCapacity(int neededCapacity) {
+ if (neededCapacity - buffer.length > 0) {
+ int newCapacity = buffer.length << 1;
+ if (newCapacity - neededCapacity < 0) {
+ newCapacity = neededCapacity;
+ }
+ if (newCapacity - MAX_ARRAY_SIZE > 0) {
+ throw new OutOfMemoryError();
+ }
+ buffer = Arrays.copyOf(buffer, newCapacity);
+ }
+ }
+
+ /**
+ * Creates a new buffer backed by a byte array. The buffer initial size is
+ * {@code initialSize}.
+ */
+ public static ByteArrayBinaryOutput create(int initialSize) {
+ return new ByteArrayBinaryOutput(initialSize);
+ }
+ }
+
+ /**
+ * A {@link BinaryOutput} backed by an off-heap memory.
+ */
+ public static final class CCharPointerBinaryOutput extends BinaryOutput implements Closeable {
+
+ /**
+ * Represents the point at which the average cost of a JNI call exceeds the expense of an
+ * element by element copy. See {@code java.nio.Bits#JNI_COPY_FROM_ARRAY_THRESHOLD}.
+ */
+ private static final int BYTEBUFFER_COPY_FROM_ARRAY_THRESHOLD = 6;
+
+ private CCharPointer address;
+ private int length;
+ private boolean unmanaged;
+ /**
+ * ByteBuffer view of this {@link CCharPointerBinaryOutput} direct memory. The ByteBuffer is
+ * used for bulk data transfers, where the bulk ByteBuffer operations outperform element by
+ * element copying by an order of magnitude.
+ */
+ private ByteBuffer byteBufferView;
+
+ private CCharPointerBinaryOutput(CCharPointer address, int length, boolean unmanaged) {
+ this.address = address;
+ this.length = length;
+ this.unmanaged = unmanaged;
+ }
+
+ @Override
+ public int getPosition() {
+ checkClosed();
+ return super.getPosition();
+ }
+
+ /**
+ * Returns an address of an off-heap memory segment containing the marshalled data.
+ */
+ public CCharPointer getAddress() {
+ checkClosed();
+ return address;
+ }
+
+ @Override
+ public void write(int b) {
+ checkClosed();
+ ensureCapacity(pos + 1);
+ address.write(pos++, (byte) b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) {
+ checkClosed();
+ if ((off | len | b.length) < 0 || b.length - off < len) {
+ throw new IndexOutOfBoundsException("offset: " + off + ", length: " + len + ", array length: " + b.length);
+ }
+ ensureCapacity(pos + len);
+ if (len > BYTEBUFFER_COPY_FROM_ARRAY_THRESHOLD) {
+ if (byteBufferView == null) {
+ byteBufferView = CTypeConversion.asByteBuffer(address, length);
+ }
+ byteBufferView.position(pos);
+ byteBufferView.put(b, off, len);
+ } else {
+ for (int i = 0; i < len; i++) {
+ address.write(pos + i, b[off + i]);
+ }
+ }
+ pos += len;
+ }
+
+ @Override
+ public void skip(int numberOfBytes) {
+ ensureCapacity(pos + numberOfBytes);
+ pos += numberOfBytes;
+ }
+
+ /**
+ * Closes the buffer and frees off-heap allocated resources.
+ */
+ @Override
+ public void close() {
+ if (unmanaged) {
+ UnmanagedMemory.free(address);
+ byteBufferView = null;
+ address = WordFactory.nullPointer();
+ length = 0;
+ unmanaged = false;
+ pos = Integer.MIN_VALUE;
+ }
+ }
+
+ private void checkClosed() {
+ if (pos == Integer.MIN_VALUE) {
+ throw new IllegalStateException("Already closed");
+ }
+ }
+
+ private void ensureCapacity(int neededCapacity) {
+ if (neededCapacity - length > 0) {
+ byteBufferView = null;
+ int newCapacity = length << 1;
+ if (newCapacity - neededCapacity < 0) {
+ newCapacity = neededCapacity;
+ }
+ if (newCapacity - Integer.MAX_VALUE > 0) {
+ throw new OutOfMemoryError();
+ }
+ if (unmanaged) {
+ address = UnmanagedMemory.realloc(address, WordFactory.unsigned(newCapacity));
+ } else {
+ CCharPointer newAddress = UnmanagedMemory.malloc(newCapacity);
+ memcpy(newAddress, address, pos);
+ address = newAddress;
+ }
+ length = newCapacity;
+ unmanaged = true;
+ }
+ }
+
+ private static void memcpy(CCharPointer dst, CCharPointer src, int len) {
+ for (int i = 0; i < len; i++) {
+ dst.write(i, src.read(i));
+ }
+ }
+
+ /**
+ * Creates a new buffer backed by an off-heap memory segment. The buffer initial size is
+ * {@code initialSize}.
+ */
+ public static CCharPointerBinaryOutput create(int initialSize) {
+ return new CCharPointerBinaryOutput(UnmanagedMemory.malloc(initialSize), initialSize, true);
+ }
+ }
+}
diff --git a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilable.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilable.java
index 891e6a9d297c..c633bedbf9a6 100644
--- a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilable.java
+++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilable.java
@@ -40,7 +40,6 @@
import org.graalvm.jniutils.JNICalls.JNIMethod;
import org.graalvm.jniutils.JNIMethodScope;
import org.graalvm.jniutils.JNIUtil;
-import org.graalvm.nativebridge.BinaryInput;
import org.graalvm.nativeimage.StackValue;
import org.graalvm.word.WordFactory;
diff --git a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilationTask.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilationTask.java
index b9bc48926451..d5a3c0c10dd3 100644
--- a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilationTask.java
+++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilationTask.java
@@ -36,7 +36,6 @@
import org.graalvm.jniutils.JNI.JObject;
import org.graalvm.jniutils.JNIMethodScope;
import org.graalvm.jniutils.JNIUtil;
-import org.graalvm.nativebridge.BinaryInput;
import java.util.LinkedHashMap;
import java.util.Map;
diff --git a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilerRuntime.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilerRuntime.java
index d2cf241da28f..09a69ec990fc 100644
--- a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilerRuntime.java
+++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/HSTruffleCompilerRuntime.java
@@ -54,7 +54,6 @@
import org.graalvm.jniutils.JNI.JString;
import org.graalvm.jniutils.JNIMethodScope;
import org.graalvm.jniutils.JNIUtil;
-import org.graalvm.nativebridge.BinaryInput;
import org.graalvm.nativeimage.StackValue;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.word.WordFactory;
diff --git a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/LibGraalTruffleEntryPoints.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/LibGraalTruffleEntryPoints.java
index 50612c3fd3c8..b8ac6074159a 100644
--- a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/LibGraalTruffleEntryPoints.java
+++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/truffle/LibGraalTruffleEntryPoints.java
@@ -40,7 +40,6 @@
import org.graalvm.jniutils.JNIExceptionWrapper;
import org.graalvm.jniutils.JNIMethodScope;
import org.graalvm.jniutils.JNIUtil;
-import org.graalvm.nativebridge.BinaryOutput;
import org.graalvm.nativeimage.ObjectHandles;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.function.CEntryPoint.IsolateThreadContext;