diff --git a/java/benchmark/src/main/java/org/apache/fory/benchmark/MemorySuite.java b/java/benchmark/src/main/java/org/apache/fory/benchmark/MemorySuite.java index 4cca997826..096a28e8b9 100644 --- a/java/benchmark/src/main/java/org/apache/fory/benchmark/MemorySuite.java +++ b/java/benchmark/src/main/java/org/apache/fory/benchmark/MemorySuite.java @@ -170,7 +170,7 @@ private static byte[] getByteArray(int arrLen) { } private static final byte[] array1 = getByteArray(256); - private static final MemoryBuffer buffer1 = MemoryUtils.wrap(getByteArray(256)); + private static final MemoryBuffer buffer1 = MemoryBuffer.wrap(getByteArray(256)); // @org.openjdk.jmh.annotations.Benchmark public Object bufferUnsafeReadByte(MemoryState state) { diff --git a/java/benchmark/src/main/java/org/apache/fory/benchmark/ZeroCopySuite.java b/java/benchmark/src/main/java/org/apache/fory/benchmark/ZeroCopySuite.java index 45d166723e..a1bd071762 100644 --- a/java/benchmark/src/main/java/org/apache/fory/benchmark/ZeroCopySuite.java +++ b/java/benchmark/src/main/java/org/apache/fory/benchmark/ZeroCopySuite.java @@ -163,10 +163,10 @@ public void setup() { .build(); switch (bufferType) { case array: - buffer = MemoryUtils.buffer(1024 * 512); + buffer = MemoryBuffer.buffer(1024 * 512); break; case directBuffer: - buffer = MemoryUtils.wrap(ByteBuffer.allocateDirect(1024 * 512)); + buffer = MemoryBuffer.wrap(ByteBuffer.allocateDirect(1024 * 512)); break; } fory.register(ArraysData.class); diff --git a/java/benchmark/src/main/java/org/apache/fory/benchmark/state/ForyState.java b/java/benchmark/src/main/java/org/apache/fory/benchmark/state/ForyState.java index bc630482d1..4d71b6557a 100644 --- a/java/benchmark/src/main/java/org/apache/fory/benchmark/state/ForyState.java +++ b/java/benchmark/src/main/java/org/apache/fory/benchmark/state/ForyState.java @@ -82,10 +82,10 @@ public void setup() { public void setupBuffer() { switch (bufferType) { case array: - buffer = MemoryUtils.buffer(1024 * 512); + buffer = MemoryBuffer.buffer(1024 * 512); break; case directBuffer: - buffer = MemoryUtils.wrap(ByteBuffer.allocateDirect(1024 * 512)); + buffer = MemoryBuffer.wrap(ByteBuffer.allocateDirect(1024 * 512)); break; } } diff --git a/java/fory-core/src/main/java/org/apache/fory/BaseFory.java b/java/fory-core/src/main/java/org/apache/fory/BaseFory.java index 3f27ecdade..04ce4962fc 100644 --- a/java/fory-core/src/main/java/org/apache/fory/BaseFory.java +++ b/java/fory-core/src/main/java/org/apache/fory/BaseFory.java @@ -21,6 +21,7 @@ import java.io.OutputStream; import java.util.function.Function; +import org.apache.fory.annotation.NotForAndroid; import org.apache.fory.io.ForyInputStream; import org.apache.fory.io.ForyReadableChannel; import org.apache.fory.memory.MemoryBuffer; @@ -115,6 +116,7 @@ public interface BaseFory { * Serialize obj to a off-heap buffer specified by address and * size. */ + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") MemoryBuffer serialize(Object obj, long address, int size); /** Serialize data into buffer. */ @@ -138,6 +140,7 @@ public interface BaseFory { * Deserialize obj from a off-heap buffer specified by address and * size. */ + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") Object deserialize(long address, int size); /** Deserialize obj from a buffer. */ diff --git a/java/fory-core/src/main/java/org/apache/fory/Fory.java b/java/fory-core/src/main/java/org/apache/fory/Fory.java index 99eed4bbf0..3f5e96db8c 100644 --- a/java/fory-core/src/main/java/org/apache/fory/Fory.java +++ b/java/fory-core/src/main/java/org/apache/fory/Fory.java @@ -30,6 +30,7 @@ import java.util.function.Consumer; import java.util.function.Function; import javax.annotation.concurrent.NotThreadSafe; +import org.apache.fory.annotation.NotForAndroid; import org.apache.fory.builder.JITContext; import org.apache.fory.collection.IdentityMap; import org.apache.fory.config.CompatibleMode; @@ -265,9 +266,10 @@ public Serializer getSerializer(Class cls) { } } + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") @Override public MemoryBuffer serialize(Object obj, long address, int size) { - MemoryBuffer buffer = MemoryUtils.buffer(address, size); + MemoryBuffer buffer = MemoryBuffer.fromNativeAddress(address, size); serialize(buffer, obj, null); return buffer; } @@ -790,13 +792,13 @@ public long readInt64(MemoryBuffer buffer) { @Override public Object deserialize(byte[] bytes) { - return deserialize(MemoryUtils.wrap(bytes), null); + return deserialize(MemoryBuffer.wrap(bytes), null); } @SuppressWarnings("unchecked") @Override public T deserialize(byte[] bytes, Class type) { - MemoryBuffer buffer = MemoryUtils.wrap(bytes); + MemoryBuffer buffer = MemoryBuffer.wrap(bytes); if (!crossLanguage && shareMeta) { byte bitmap = buffer.readByte(); if ((bitmap & isNilFlag) == isNilFlag) { @@ -816,12 +818,13 @@ public T deserialize(byte[] bytes, Class type) { @Override public Object deserialize(byte[] bytes, Iterable outOfBandBuffers) { - return deserialize(MemoryUtils.wrap(bytes), outOfBandBuffers); + return deserialize(MemoryBuffer.wrap(bytes), outOfBandBuffers); } + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") @Override public Object deserialize(long address, int size) { - return deserialize(MemoryUtils.buffer(address, size), null); + return deserialize(MemoryBuffer.fromNativeAddress(address, size), null); } @Override @@ -1207,7 +1210,7 @@ public void serializeJavaObject(OutputStream outputStream, Object obj) { @Override public T deserializeJavaObject(byte[] data, Class cls) { - return deserializeJavaObject(MemoryBuffer.fromByteArray(data), cls); + return deserializeJavaObject(MemoryBuffer.wrap(data), cls); } @Override @@ -1327,7 +1330,7 @@ public void serializeJavaObjectAndClass(OutputStream outputStream, Object obj) { */ @Override public Object deserializeJavaObjectAndClass(byte[] data) { - return deserializeJavaObjectAndClass(MemoryBuffer.fromByteArray(data)); + return deserializeJavaObjectAndClass(MemoryBuffer.wrap(data)); } /** diff --git a/java/fory-core/src/main/java/org/apache/fory/ThreadLocalFory.java b/java/fory-core/src/main/java/org/apache/fory/ThreadLocalFory.java index a0093e5bab..d16fc41fb4 100644 --- a/java/fory-core/src/main/java/org/apache/fory/ThreadLocalFory.java +++ b/java/fory-core/src/main/java/org/apache/fory/ThreadLocalFory.java @@ -28,10 +28,10 @@ import java.util.function.Function; import javax.annotation.concurrent.ThreadSafe; import org.apache.fory.annotation.Internal; +import org.apache.fory.annotation.NotForAndroid; import org.apache.fory.io.ForyInputStream; import org.apache.fory.io.ForyReadableChannel; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.serializer.BufferCallback; import org.apache.fory.util.LoaderBinding; import org.apache.fory.util.LoaderBinding.StagingType; @@ -44,7 +44,7 @@ @ThreadSafe public class ThreadLocalFory extends AbstractThreadSafeFory { private final ThreadLocal bufferLocal = - ThreadLocal.withInitial(() -> MemoryUtils.buffer(32)); + ThreadLocal.withInitial(() -> MemoryBuffer.buffer(32)); private final ThreadLocal bindingThreadLocal; private Consumer factoryCallback; @@ -107,6 +107,7 @@ public byte[] serialize(Object obj, BufferCallback callback) { return buffer.getBytes(0, buffer.writerIndex()); } + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") @Override public MemoryBuffer serialize(Object obj, long address, int size) { return bindingThreadLocal.get().get().serialize(obj, address, size); @@ -147,6 +148,7 @@ public Object deserialize(byte[] bytes, Iterable outOfBandBuffers) return bindingThreadLocal.get().get().deserialize(bytes, outOfBandBuffers); } + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") @Override public Object deserialize(long address, int size) { return bindingThreadLocal.get().get().deserialize(address, size); @@ -159,7 +161,7 @@ public Object deserialize(MemoryBuffer buffer) { @Override public Object deserialize(ByteBuffer byteBuffer) { - return bindingThreadLocal.get().get().deserialize(MemoryUtils.wrap(byteBuffer)); + return bindingThreadLocal.get().get().deserialize(MemoryBuffer.wrap(byteBuffer)); } @Override diff --git a/java/fory-core/src/main/java/org/apache/fory/annotation/NotForAndroid.java b/java/fory-core/src/main/java/org/apache/fory/annotation/NotForAndroid.java new file mode 100644 index 0000000000..3805f7106d --- /dev/null +++ b/java/fory-core/src/main/java/org/apache/fory/annotation/NotForAndroid.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fory.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.CLASS) +@Target({ + ElementType.METHOD, + ElementType.CONSTRUCTOR, + ElementType.TYPE, +}) +public @interface NotForAndroid { + String reason() default "This API is not supported or is unsafe on the Android platform."; +} diff --git a/java/fory-core/src/main/java/org/apache/fory/annotation/PartialAndroidSupport.java b/java/fory-core/src/main/java/org/apache/fory/annotation/PartialAndroidSupport.java new file mode 100644 index 0000000000..8e0c587c63 --- /dev/null +++ b/java/fory-core/src/main/java/org/apache/fory/annotation/PartialAndroidSupport.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fory.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE}) +public @interface PartialAndroidSupport { + + int minApiLevel() default -1; + + String reason() default "该方法在 Android 上的所有分支和条件下不保证完全支持,请查阅文档或源码。"; + + String docUrl() default ""; +} diff --git a/java/fory-core/src/main/java/org/apache/fory/io/AbstractStreamReader.java b/java/fory-core/src/main/java/org/apache/fory/io/AbstractStreamReader.java index 81a63280b0..f695ab244a 100644 --- a/java/fory-core/src/main/java/org/apache/fory/io/AbstractStreamReader.java +++ b/java/fory-core/src/main/java/org/apache/fory/io/AbstractStreamReader.java @@ -32,9 +32,6 @@ public int fillBuffer(int minFillSize) { @Override public void readTo(byte[] dst, int dstIndex, int length) {} - @Override - public void readToUnsafe(Object target, long targetPointer, int numBytes) {} - @Override public void readToByteBuffer(ByteBuffer dst, int length) {} diff --git a/java/fory-core/src/main/java/org/apache/fory/io/ForyInputStream.java b/java/fory-core/src/main/java/org/apache/fory/io/ForyInputStream.java index 93dbd77b7e..a487b2f63d 100644 --- a/java/fory-core/src/main/java/org/apache/fory/io/ForyInputStream.java +++ b/java/fory-core/src/main/java/org/apache/fory/io/ForyInputStream.java @@ -24,7 +24,6 @@ import java.nio.ByteBuffer; import javax.annotation.concurrent.NotThreadSafe; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.Platform; /** * A buffered stream by fory. Do not use original {@link InputStream} when this stream object @@ -45,7 +44,7 @@ public ForyInputStream(InputStream stream, int bufferSize) { this.stream = stream; this.bufferSize = bufferSize; byte[] bytes = new byte[bufferSize]; - this.buffer = MemoryBuffer.fromByteArray(bytes, 0, 0, this); + this.buffer = new MemoryBuffer(bytes, 0, 0, this); } @Override @@ -115,18 +114,50 @@ public void readTo(byte[] dst, int dstIndex, int len) { } } - @Override - public void readToUnsafe(Object target, long targetPointer, int numBytes) { - MemoryBuffer buf = buffer; - int remaining = buf.remaining(); - if (remaining < numBytes) { - fillBuffer(numBytes - remaining); - } - byte[] heapMemory = buf.getHeapMemory(); - long address = buf.getUnsafeReaderAddress(); - Platform.copyMemory(heapMemory, address, target, targetPointer, numBytes); - buf.increaseReaderIndex(numBytes); - } + // @Override + // public void readCharsTo(char[] target, int offset, int length) { + // int numBytes = length * 2; + // MemoryBuffer buf = buffer; + // int remaining = buf.remaining(); + // if (remaining < numBytes) { + // fillBuffer(numBytes - remaining); + // } + // buf.readCharsDirect(target, offset, length); + // } + // + // @Override + // public void readLongsTo(long[] target, int offset, int length) { + // int numBytes = length * 8; + // MemoryBuffer buf = buffer; + // int remaining = buf.remaining(); + // if (remaining < numBytes) { + // fillBuffer(numBytes - remaining); + // } + // buf.readLongsDirect(target, offset, length); + // } + // + // @Override + // public void readBoolsTo(boolean[] target, int offset, int length) { + // MemoryBuffer buf = buffer; + // int remaining = buf.remaining(); + // if (remaining < length) { + // fillBuffer(length - remaining); + // } + // buf.readBoolsDirect(target, offset, length); + // } + + // @Override + // public void readToUnsafe(Object target, long targetPointer, int numBytes) { + // MemoryBuffer buf = buffer; + // int remaining = buf.remaining(); + // if (remaining < numBytes) { + // fillBuffer(numBytes - remaining); + // } + // byte[] heapMemory = buf.getHeapMemory(); + // long address = buf.getUnsafeReaderAddress(); + // Platform.copyMemory(heapMemory, address, target, targetPointer, numBytes); + // buf.increaseReaderIndex(numBytes); + // } @Override public void readToByteBuffer(ByteBuffer dst, int length) { diff --git a/java/fory-core/src/main/java/org/apache/fory/io/ForyReadableChannel.java b/java/fory-core/src/main/java/org/apache/fory/io/ForyReadableChannel.java index 1afbcbf7b3..d3157bd915 100644 --- a/java/fory-core/src/main/java/org/apache/fory/io/ForyReadableChannel.java +++ b/java/fory-core/src/main/java/org/apache/fory/io/ForyReadableChannel.java @@ -24,9 +24,7 @@ import java.nio.channels.ReadableByteChannel; import javax.annotation.concurrent.NotThreadSafe; import org.apache.fory.exception.DeserializationException; -import org.apache.fory.memory.ByteBufferUtil; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.Platform; import org.apache.fory.util.Preconditions; @NotThreadSafe @@ -63,7 +61,7 @@ public int fillBuffer(int minFillSize) { byteBuf.position(0); newByteBuf.put(byteBuf); byteBuf = byteBuffer = newByteBuf; - memoryBuf.initDirectBuffer(ByteBufferUtil.getAddress(byteBuf), position, byteBuf); + memoryBuf.initDirectBuffer(byteBuf, newSize); } byteBuf.limit(newLimit); int readCount = channel.read(byteBuf); @@ -105,17 +103,49 @@ public void readTo(byte[] dst, int dstIndex, int length) { } } - @Override - public void readToUnsafe(Object target, long targetPointer, int numBytes) { - MemoryBuffer buf = memoryBuffer; - int remaining = buf.remaining(); - if (remaining < numBytes) { - fillBuffer(numBytes - remaining); - } - long address = buf.getUnsafeReaderAddress(); - Platform.copyMemory(null, address, target, targetPointer, numBytes); - buf.increaseReaderIndex(numBytes); - } + // @Override + // public void readCharsTo(char[] target, int offset, int length) { + // int numBytes = length * 2; + // MemoryBuffer buf = memoryBuffer; + // int remaining = buf.remaining(); + // if (remaining < numBytes) { + // fillBuffer(numBytes - remaining); + // } + // buf.readCharsDirect(target, offset, length); + // } + // + // @Override + // public void readLongsTo(long[] target, int offset, int length) { + // int numBytes = length * 8; + // MemoryBuffer buf = memoryBuffer; + // int remaining = buf.remaining(); + // if (remaining < numBytes) { + // fillBuffer(numBytes - remaining); + // } + // buf.readLongsDirect(target, offset, length); + // } + // + // @Override + // public void readBoolsTo(boolean[] target, int offset, int length) { + // MemoryBuffer buf = memoryBuffer; + // int remaining = buf.remaining(); + // if (remaining < length) { + // fillBuffer(length - remaining); + // } + // buf.readBoolsDirect(target, offset, length); + // } + + // @Override + // public void readToUnsafe(Object target, long targetPointer, int numBytes) { + // MemoryBuffer buf = memoryBuffer; + // int remaining = buf.remaining(); + // if (remaining < numBytes) { + // fillBuffer(numBytes - remaining); + // } + // long address = buf.getUnsafeReaderAddress(); + // Platform.copyMemory(null, address, target, targetPointer, numBytes); + // buf.increaseReaderIndex(numBytes); + // } @Override public void readToByteBuffer(ByteBuffer dst, int length) { diff --git a/java/fory-core/src/main/java/org/apache/fory/io/ForyStreamReader.java b/java/fory-core/src/main/java/org/apache/fory/io/ForyStreamReader.java index 352abef9b2..ff1a811fe5 100644 --- a/java/fory-core/src/main/java/org/apache/fory/io/ForyStreamReader.java +++ b/java/fory-core/src/main/java/org/apache/fory/io/ForyStreamReader.java @@ -42,7 +42,14 @@ public interface ForyStreamReader { * Read data into `target`. This method will block until the enough data are written into the * `target`. */ - void readToUnsafe(Object target, long targetPointer, int numBytes); + + // void readCharsTo(char[] target, int offset, int length); + // + // void readLongsTo(long[] target, int offset, int length); + // + // void readBoolsTo(boolean[] target, int offset, int length); + // + // void readToUnsafe(Object target, long targetPointer, int numBytes); /** * Read data into `dst`. This method will block until the enough data are written into the `dst`. diff --git a/java/fory-core/src/main/java/org/apache/fory/memory/BufferPool.java b/java/fory-core/src/main/java/org/apache/fory/memory/BufferPool.java new file mode 100644 index 0000000000..ab4ba352f8 --- /dev/null +++ b/java/fory-core/src/main/java/org/apache/fory/memory/BufferPool.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fory.memory; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; + +/** + * A global, non-blocking, thread-safe byte array buffer pool. + * + *

This class provides direct access to pooled {@code byte[]} arrays to minimize allocation + * overhead and GC pressure in high-performance applications. + * + *

WARNING: This is a low-level utility. The consumer is solely responsible for + * returning the borrowed buffer by calling {@link #release(byte[])} in a {@code finally} block. + * Failure to do so will result in a buffer leak, eventually exhausting the pool. + */ +public final class BufferPool { + + /** Singleton instance for global access. */ + public static final BufferPool INSTANCE = new BufferPool(); + + /** + * Defines the pooling strategy (buffer size -> number of buffers). This map is made unmodifiable + * for safety. + */ + private static final Map POOL_CONFIG; + + static { + // This static initializer block is compatible with all Java versions, including Java 8. + Map config = new HashMap<>(); + // These sizes are chosen based on common network packet sizes and memory page alignment. + config.put(512, 10); + config.put(1024, 6); + config.put(2048, 4); // 1KB, for small messages + config.put(3072, 2); // 4KB, common page size + config.put(4096, 1); // 16KB, for medium data chunks + POOL_CONFIG = Collections.unmodifiableMap(config); + } + + /** + * The core data structure of the pool. Key: The size of the buffer arrays in a tier. Value: A + * thread-safe queue holding the available buffers for that size. + */ + private final Map> pool; + + /** + * An array of the available buffer sizes, sorted in ascending order. This is used for efficient + * lookup of the appropriate buffer tier. + */ + private final int[] bufferSizes; + + /** Private constructor to enforce singleton pattern and initialize the pool. */ + private BufferPool() { + this.pool = new ConcurrentHashMap<>(); + + // Initialize the sorted array of buffer sizes for fast lookups. + this.bufferSizes = POOL_CONFIG.keySet().stream().mapToInt(Integer::intValue).sorted().toArray(); + + // Pre-allocate all buffers and populate the pool. + for (int size : bufferSizes) { + ConcurrentLinkedDeque queue = new ConcurrentLinkedDeque<>(); + int count = POOL_CONFIG.get(size); + for (int i = 0; i < count; i++) { + queue.offer(new byte[size]); + } + this.pool.put(size, queue); + } + } + + /** + * Borrows a {@code byte[]} from the pool, only searching for buffers large enough to satisfy the + * request. + * + * @param requiredSize The minimum required capacity of the buffer in bytes. + * @return An {@link Optional} containing a {@code byte[]}, or an empty Optional if no suitable + * buffer is available. + */ + public byte[] borrow(int requiredSize) { + return borrow(requiredSize, false); + } + + /** + * Borrows a {@code byte[]} from the pool with extended search options. + * + *

This is a non-blocking method. It first attempts to find the smallest available buffer that + * is greater than or equal to the required size. If no such buffer is found and {@code + * acceptSmaller} is true, it will then search downwards from the largest tier to find any + * available buffer. + * + * @param requiredSize The minimum required capacity of the buffer in bytes. + * @param acceptSmaller If true, the method will return a smaller buffer if no suitable large + * buffer is found. + * @return An {@link Optional} containing a {@code byte[]}, or an empty Optional if the pool is + * exhausted. + */ + public byte[] borrow(int requiredSize, boolean acceptSmaller) { + // Use binary search to find the smallest suitable buffer tier. + int searchResult = Arrays.binarySearch(bufferSizes, requiredSize); + int startIndex = (searchResult >= 0) ? searchResult : (-(searchResult + 1)); + + // First, iterate upwards from the best-fit size to find a suitable buffer. + for (int i = startIndex; i < bufferSizes.length; i++) { + int size = bufferSizes[i]; + ConcurrentLinkedDeque queue = pool.get(size); + byte[] buffer = queue.poll(); // poll() is non-blocking. + if (buffer != null) { + return buffer; + } + } + // If no suitable large buffer was found and the user accepts a smaller one... + if (acceptSmaller) { + // ...iterate downwards from the largest tier to find any available buffer. + for (int i = bufferSizes.length - 1; i >= 0; i--) { + int size = bufferSizes[i]; + ConcurrentLinkedDeque queue = pool.get(size); + byte[] buffer = queue.poll(); + if (buffer != null) { + return buffer; + } + } + } + // All suitable pools are empty, or the requested size is larger than any available tier. + return null; + } + + /** + * Returns a borrowed {@code byte[]} to the pool. + * + *

It is critical for the consumer to call this method for every buffer borrowed to prevent + * pool leaks. + * + * @param buffer The byte array to return to the pool. It must be an array that was previously + * borrowed from this pool. + */ + public void release(byte[] buffer) { + if (buffer == null) { + return; + } + int size = buffer.length; + ConcurrentLinkedDeque queue = pool.get(size); + if (queue != null) { + queue.offer(buffer); + } + // Note: In a production system, returning a buffer of an unknown size + // might be logged to a proper logging framework. Here, we silently ignore it + // for maximum performance. + } + + /** Provides statistics about the current state of the pool for monitoring or debugging. */ + public void printStats() { + System.out.println("--- BufferPool Stats ---"); + for (int size : bufferSizes) { + System.out.printf("Tier Size %5d B: %d available%n", size, pool.get(size).size()); + } + System.out.println("------------------------"); + } +} diff --git a/java/fory-core/src/main/java/org/apache/fory/memory/ByteBufferUtil.java b/java/fory-core/src/main/java/org/apache/fory/memory/ByteBufferUtil.java index c78cd08cb6..dbbc7fae92 100644 --- a/java/fory-core/src/main/java/org/apache/fory/memory/ByteBufferUtil.java +++ b/java/fory-core/src/main/java/org/apache/fory/memory/ByteBufferUtil.java @@ -22,6 +22,7 @@ import java.lang.reflect.Field; import java.nio.Buffer; import java.nio.ByteBuffer; +import org.apache.fory.annotation.NotForAndroid; import org.apache.fory.util.Preconditions; public class ByteBufferUtil { @@ -33,9 +34,14 @@ public class ByteBufferUtil { Field addressField = Buffer.class.getDeclaredField("address"); BUFFER_ADDRESS_FIELD_OFFSET = Platform.objectFieldOffset(addressField); Preconditions.checkArgument(BUFFER_ADDRESS_FIELD_OFFSET != 0); - Field capacityField = Buffer.class.getDeclaredField("capacity"); - BUFFER_CAPACITY_FIELD_OFFSET = Platform.objectFieldOffset(capacityField); - Preconditions.checkArgument(BUFFER_CAPACITY_FIELD_OFFSET != 0); + if (Platform.IS_ANDROID) { + BUFFER_CAPACITY_FIELD_OFFSET = -1; + } else { + Field capacityField = + Buffer.class.getDeclaredField("capacity"); // Android does not support this field + BUFFER_CAPACITY_FIELD_OFFSET = Platform.objectFieldOffset(capacityField); + Preconditions.checkArgument(BUFFER_CAPACITY_FIELD_OFFSET != 0); + } } catch (NoSuchFieldException e) { throw new IllegalStateException(e); } @@ -56,6 +62,7 @@ public static long getAddress(ByteBuffer buffer) { private static final ByteBuffer localBuffer = ByteBuffer.allocateDirect(0); /** Create a direct buffer from native memory represented by address [address, address + size). */ + @NotForAndroid(reason = "Android cannot directly operate the capacity field") public static ByteBuffer createDirectByteBufferFromNativeAddress(long address, int size) { try { // ByteBuffer.allocateDirect(0) is about 30x slower than `localBuffer.duplicate()`. @@ -69,21 +76,13 @@ public static ByteBuffer createDirectByteBufferFromNativeAddress(long address, i } } - /** Wrap a buffer [address, address + size) into provided buffer. */ - public static void wrapDirectByteBufferFromNativeAddress( - ByteBuffer buffer, long address, int size) { - Preconditions.checkArgument( - buffer.isDirect(), "Can't wrap native memory into a non-direct ByteBuffer."); - Platform.putLong(buffer, BUFFER_ADDRESS_FIELD_OFFSET, address); - Platform.putInt(buffer, BUFFER_CAPACITY_FIELD_OFFSET, size); - buffer.clear(); - } - + @NotForAndroid public static ByteBuffer wrapDirectBuffer(long address, int size) { return createDirectByteBufferFromNativeAddress(address, size); } /** Wrap a buffer [address, address + size) into provided buffer. */ + @NotForAndroid(reason = "Android cannot directly operate the capacity field") public static void wrapDirectBuffer(ByteBuffer buffer, long address, int size) { Platform.putLong(buffer, BUFFER_ADDRESS_FIELD_OFFSET, address); Platform.putInt(buffer, BUFFER_CAPACITY_FIELD_OFFSET, size); @@ -101,8 +100,4 @@ public static void flipBuffer(Buffer buffer) { public static void rewind(Buffer buffer) { buffer.rewind(); } - - public static void position(Buffer buffer, int pos) { - buffer.position(pos); - } } diff --git a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java index ae35d16334..835bf6af07 100644 --- a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java +++ b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java @@ -21,11 +21,14 @@ import static org.apache.fory.util.Preconditions.checkArgument; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.Arrays; +import javax.naming.OperationNotSupportedException; import org.apache.fory.annotation.CodegenInvoke; +import org.apache.fory.annotation.NotForAndroid; +import org.apache.fory.annotation.PartialAndroidSupport; import org.apache.fory.io.AbstractStreamReader; import org.apache.fory.io.ForyStreamReader; +import org.apache.fory.type.Types; import sun.misc.Unsafe; /** @@ -60,9 +63,12 @@ * DesiredMethodLimit,MaxRecursiveInlineLevel,FreqInlineSize,MaxInlineSize */ public final class MemoryBuffer { + public static final int BOOLEAN_TRANSFER_THRESHOLD = 512; public static final int BUFFER_GROW_STEP_THRESHOLD = 100 * 1024 * 1024; private static final Unsafe UNSAFE = Platform.UNSAFE; - private static final boolean LITTLE_ENDIAN = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN); + private static final boolean LITTLE_ENDIAN = Platform.IS_LITTLE_ENDIAN; + + private final boolean onHeap; // If the data in on the heap, `heapMemory` will be non-null, and its' the object relative to // which we access the memory. @@ -70,15 +76,22 @@ public final class MemoryBuffer { // to undefined addresses outside the heap and may in out-of-order execution cases cause // buffer faults. private byte[] heapMemory; - private int heapOffset; - // If the data is off the heap, `offHeapBuffer` will be non-null, and it's the direct byte buffer - // that allocated on the off-heap memory. - // This memory buffer holds a reference to that buffer, so as long as this memory buffer lives, - // the memory will not be released. - private ByteBuffer offHeapBuffer; + + // the offset in the heap memory byte array, i.e. the relative offset to the // `heapMemory` byte + // array. + // 注意当是 off-heap时,这个是一开始传入时buffer的position + // 如果是 on-heap, 这个是一开始传入数组的offset + private int memoryOffset; // 用于记录为相对于最底层的内存的偏移(忽略中间任何切片) + + // represents the both off-heap and on-heap memory. + private ByteBuffer buffer; + // The readable/writeable range is [address, addressLimit). // If the data in on the heap, this is the relative offset to the `heapMemory` byte array. // If the data is off the heap, this is the absolute memory address. + // 注意,当是off-heap, 这个是是算上一开始传入时buffer的position的 + // 当是heap,Platform.BYTE_ARRAY_OFFSET + 一开始传入数组的offset + // 用于代表第一个可以(允许读取的字节,onHeap: Platform._ARRAY_OFFSET + elementOffset, offHeap: address + position) private long address; // The address one byte after the last addressable byte, i.e. `address + size` while the // buffer is not disposed. @@ -97,7 +110,7 @@ public final class MemoryBuffer { * array.length. * @param length buffer size */ - private MemoryBuffer(byte[] buffer, int offset, int length) { + public MemoryBuffer(byte[] buffer, int offset, int length) { this(buffer, offset, length, null); } @@ -110,12 +123,13 @@ private MemoryBuffer(byte[] buffer, int offset, int length) { * @param length buffer size * @param streamReader a reader for reading from a stream. */ - private MemoryBuffer(byte[] buffer, int offset, int length, ForyStreamReader streamReader) { + public MemoryBuffer(byte[] buffer, int offset, int length, ForyStreamReader streamReader) { checkArgument(offset >= 0 && length >= 0); if (offset + length > buffer.length) { throw new IllegalArgumentException( String.format("%d exceeds buffer size %d", offset + length, buffer.length)); } + this.onHeap = true; initHeapBuffer(buffer, offset, length); if (streamReader != null) { this.streamReader = streamReader; @@ -128,55 +142,78 @@ private MemoryBuffer(byte[] buffer, int offset, int length, ForyStreamReader str * Creates a new memory buffer that represents the native memory at the absolute address given by * the pointer. * - * @param offHeapAddress The address of the memory represented by this memory buffer. - * @param size The size of this memory buffer. * @param offHeapBuffer The byte buffer whose memory is represented by this memory buffer which * may be null if the memory is not allocated by `DirectByteBuffer`. Hold this buffer to avoid * the memory being released. + * @param length The size of this memory buffer. + * @param streamReader a reader for reading from a stream. */ - private MemoryBuffer(long offHeapAddress, int size, ByteBuffer offHeapBuffer) { - this(offHeapAddress, size, offHeapBuffer, null); + private MemoryBuffer( + long offHeapAddress, + ByteBuffer offHeapBuffer, + int length, + ForyStreamReader streamReader, + boolean useBufferObject) { + assert (offHeapAddress == -1 && offHeapBuffer != null) + || (offHeapAddress != -1 && offHeapBuffer == null); + this.onHeap = false; + initDirectBuffer(offHeapAddress, offHeapBuffer, length, useBufferObject); + if (streamReader != null) { + this.streamReader = streamReader; + } else { + this.streamReader = new BoundChecker(); + } } /** * Creates a new memory buffer that represents the native memory at the absolute address given by * the pointer. * - * @param offHeapAddress The address of the memory represented by this memory buffer. - * @param size The size of this memory buffer. + * @param length The size of this memory buffer. * @param offHeapBuffer The byte buffer whose memory is represented by this memory buffer which * may be null if the memory is not allocated by `DirectByteBuffer`. Hold this buffer to avoid * the memory being released. - * @param streamReader a reader for reading from a stream. */ - private MemoryBuffer( - long offHeapAddress, int size, ByteBuffer offHeapBuffer, ForyStreamReader streamReader) { - initDirectBuffer(offHeapAddress, size, offHeapBuffer); - if (streamReader != null) { - this.streamReader = streamReader; - } else { - this.streamReader = new BoundChecker(); - } + public void initDirectBuffer(ByteBuffer offHeapBuffer, int length) { + initDirectBuffer(-1, offHeapBuffer, length, false); } - public void initDirectBuffer(long offHeapAddress, int size, ByteBuffer offHeapBuffer) { - this.offHeapBuffer = offHeapBuffer; - if (offHeapAddress <= 0) { + private void initDirectBuffer( + long offHeapAddress, ByteBuffer offHeapBuffer, int length, boolean useBufferObject) { + assert (offHeapAddress == -1 && offHeapBuffer != null) + || (offHeapAddress != -1 && offHeapBuffer == null); + if (offHeapBuffer == null && Platform.IS_ANDROID) { + Platform.throwException( + new OperationNotSupportedException( + "Android does not support off-heap memory only by address, use ByteBuffer instead")); + } + if (offHeapBuffer != null) { + if (useBufferObject) { + this.buffer = offHeapBuffer; // 不进行slice, 直接使用传入的buffer对象 + } else { + this.buffer = + offHeapBuffer.slice().order(Platform.NATIVE_BYTE_ORDER); // 先slice再order, 防止影响到参数buffer + } + this.address = + ByteBufferUtil.getAddress(this.buffer); // 注意要用被赋值的this.buffer而不是参数offHeapBuffer + this.buffer.limit(length); + } else { + this.address = offHeapAddress; + } + if (this.address <= 0) { throw new IllegalArgumentException("negative pointer or size"); } - if (offHeapAddress >= Long.MAX_VALUE - Integer.MAX_VALUE) { + if (this.address >= Long.MAX_VALUE - Integer.MAX_VALUE) { // this is necessary to make sure the collapsed checks are safe against numeric overflows throw new IllegalArgumentException( "Buffer initialized with too large address: " - + offHeapAddress + + this.address + " ; Max allowed address is " + (Long.MAX_VALUE - Integer.MAX_VALUE - 1)); } - this.heapMemory = null; - this.address = offHeapAddress; + this.size = length; this.addressLimit = this.address + size; - this.size = size; } private class BoundChecker extends AbstractStreamReader { @@ -194,16 +231,18 @@ public MemoryBuffer getBuffer() { } } - public void initHeapBuffer(byte[] buffer, int offset, int length) { - if (buffer == null) { + public void initHeapBuffer(byte[] bytes, int offset, int length) { + if (bytes == null) { throw new NullPointerException("buffer"); } - this.heapMemory = buffer; - this.heapOffset = offset; + this.heapMemory = bytes; + this.memoryOffset = offset; final long startPos = Platform.BYTE_ARRAY_OFFSET + offset; this.address = startPos; this.size = length; this.addressLimit = startPos + length; + // 若不进行slice(), 则ByteBuffer[offset=0, pos = offset], 切片后ByteBuffer[offset=offset, pos=0] + this.buffer = ByteBuffer.wrap(bytes, offset, length).slice().order(Platform.NATIVE_BYTE_ORDER); } // ------------------------------------------------------------------------ @@ -223,22 +262,12 @@ public void increaseSize(int diff) { this.addressLimit = address + (size += diff); } - /** - * Checks whether this memory buffer is backed by off-heap memory. - * - * @return true, if the memory buffer is backed by off-heap memory, false if it - * is backed by heap memory. - */ - public boolean isOffHeap() { - return heapMemory == null; - } - /** * Returns true, if the memory buffer is backed by heap memory and memory buffer can * write to the whole memory region of underlying byte array. */ public boolean isHeapFullyWriteable() { - return heapMemory != null && heapOffset == 0; + return heapMemory != null && memoryOffset == 0; } /** @@ -256,12 +285,8 @@ public byte[] getHeapMemory() { * * @return The byte buffer that owns the memory of this memory buffer. */ - public ByteBuffer getOffHeapBuffer() { - if (offHeapBuffer != null) { - return offHeapBuffer; - } else { - throw new IllegalStateException("Memory buffer does not represent off heap ByteBuffer"); - } + public ByteBuffer getInnerBuffer() { + return buffer; } /** @@ -285,7 +310,7 @@ public byte[] getArray() { * @throws IllegalStateException if the memory buffer does not represent off-heap memory */ public long getAddress() { - if (heapMemory == null) { + if (!onHeap) { return address; } else { throw new IllegalStateException("Memory buffer does not represent off heap memory"); @@ -308,15 +333,11 @@ private void checkPosition(long index, long pos, long length) { } } - public void get(int index, byte[] dst) { - get(index, dst, 0, dst.length); - } - public void get(int index, byte[] dst, int offset, int length) { final byte[] heapMemory = this.heapMemory; if (heapMemory != null) { // System.arraycopy faster for some jdk than Unsafe. - System.arraycopy(heapMemory, heapOffset + index, dst, offset, length); + System.arraycopy(heapMemory, memoryOffset + index, dst, offset, length); } else { final long pos = address + index; if ((index @@ -328,10 +349,11 @@ public void get(int index, byte[] dst, int offset, int length) { < 0) { throwOOBException(); } - Platform.copyMemory(null, pos, dst, Platform.BYTE_ARRAY_OFFSET + offset, length); + copyTo(index, dst, offset, length, Types.JavaArray.BYTE, false); } } + @SuppressWarnings("deprecation") public void get(int offset, ByteBuffer target, int numBytes) { if ((offset | numBytes | (offset + numBytes)) < 0) { throwOOBException(); @@ -344,18 +366,27 @@ public void get(int offset, ByteBuffer target, int numBytes) { } final int targetPos = target.position(); if (target.isDirect()) { + final long sourceOffset = address + offset; + if (sourceOffset > addressLimit - numBytes) { + throwOOBException(); + } final long targetAddr = ByteBufferUtil.getAddress(target) + targetPos; - final long sourceAddr = address + offset; - if (sourceAddr <= addressLimit - numBytes) { - Platform.copyMemory(heapMemory, sourceAddr, null, targetAddr, numBytes); + if (Platform.IS_ANDROID) { + if (onHeap) { + target.put(heapMemory, memoryOffset + offset, numBytes); // 此操作会改变target的position,无需再调整了 + return; + } else { + // Android只支持这个三个参数的copyMemory + Platform.UNSAFE.copyMemory(sourceOffset, targetAddr, numBytes); + } } else { - throwOOBException(); + Platform.copyMemory(heapMemory, sourceOffset, null, targetAddr, numBytes); } } else { assert target.hasArray(); get(offset, target.array(), targetPos + target.arrayOffset(), numBytes); } - ByteBufferUtil.position(target, targetPos + numBytes); + target.position(targetPos + numBytes); } public void put(int offset, ByteBuffer source, int numBytes) { @@ -367,16 +398,24 @@ public void put(int offset, ByteBuffer source, int numBytes) { if (source.isDirect()) { final long sourceAddr = ByteBufferUtil.getAddress(source) + sourcePos; final long targetAddr = address + offset; - if (targetAddr <= addressLimit - numBytes) { - Platform.copyMemory(null, sourceAddr, heapMemory, targetAddr, numBytes); - } else { + if (targetAddr > addressLimit - numBytes) { throwOOBException(); } + if (Platform.IS_ANDROID) { + if (onHeap) { + source.get(heapMemory, memoryOffset + offset, numBytes); // 此操作会改变source的position,无需再调整了 + return; + } + // Android只支持这个三个参数的copyMemory + Platform.UNSAFE.copyMemory(sourceAddr, targetAddr, numBytes); + } else { + Platform.copyMemory(null, sourceAddr, heapMemory, targetAddr, numBytes); + } } else { assert source.hasArray(); put(offset, source.array(), sourcePos + source.arrayOffset(), numBytes); } - ByteBufferUtil.position(source, sourcePos + numBytes); + source.position(sourcePos + numBytes); } public void put(int index, byte[] src) { @@ -387,7 +426,7 @@ public void put(int index, byte[] src, int offset, int length) { final byte[] heapMemory = this.heapMemory; if (heapMemory != null) { // System.arraycopy faster for some jdk than Unsafe. - System.arraycopy(src, offset, heapMemory, heapOffset + index, length); + System.arraycopy(src, offset, heapMemory, memoryOffset + index, length); } else { final long pos = address + index; // check the byte array offset and length @@ -400,8 +439,7 @@ public void put(int index, byte[] src, int offset, int length) { < 0) { throwOOBException(); } - final long arrayAddress = Platform.BYTE_ARRAY_OFFSET + offset; - Platform.copyMemory(src, arrayAddress, null, pos, length); + coverMemoryWithArray(index, src, offset, length, Types.JavaArray.BYTE, false); } } @@ -613,7 +651,7 @@ public void _unsafeWriterIndex(int writerIndex) { // CHECKSTYLE.OFF:MethodName public int _unsafeHeapWriterIndex() { // CHECKSTYLE.ON:MethodName - return writerIndex + heapOffset; + return writerIndex + memoryOffset; } // CHECKSTYLE.OFF:MethodName @@ -1203,31 +1241,133 @@ public void write(ByteBuffer source, int numBytes) { writerIndex = newIdx; } + /*--------------------------------------------------------------------------------*/ + /** + * Writes a boolean array to the buffer using an optimized chunking strategy. + * + *

For large arrays, it borrows a temporary byte buffer from a pool to convert booleans to + * bytes in chunks, minimizing method call overhead. For small arrays or if the pool is exhausted, + * it falls back to a simple, direct loop. + * + * @param arr The source boolean array. + * @param offset The starting offset in the source array. + * @param length The number of booleans to write. + */ + // ByteBuffer需要在外部调整好position, 此函数不会移动writerIndex + private void coverMemoryWithBoolArrayInner(boolean[] arr, int offset, int length) { + // Fast Path: Use pooling and chunking for large arrays. + if (length >= BOOLEAN_TRANSFER_THRESHOLD) { + byte[] tmpBytes = BufferPool.INSTANCE.borrow(length, true); + // If borrowing was successful, proceed with the optimized path. + if (tmpBytes != null && tmpBytes.length >= BOOLEAN_TRANSFER_THRESHOLD / 3) { + int remaining = length; + int currentOffset = offset; + while (remaining > 0) { + int chunkSize = Math.min(remaining, tmpBytes.length); + for (int i = 0; i < chunkSize; i++) { + tmpBytes[i] = arr[currentOffset + i] ? (byte) 1 : (byte) 0; + } + buffer.put(tmpBytes, 0, chunkSize); + remaining -= chunkSize; + currentOffset += chunkSize; + } + BufferPool.INSTANCE.release(tmpBytes); + return; + } + } + // Fallback Path: For small arrays or if the buffer pool was exhausted. + int limit = offset + length; + for (int i = offset; i < limit; i++) { + buffer.put(arr[i] ? (byte) 1 : (byte) 0); + } + } + + @SuppressWarnings("deprecation") + // 此函数不会自动扩容,在保证空间足够的情况下使用 + public void coverMemoryWithArray( + int bufOffset, + Object arr, + int offset, + int length, + Types.JavaArray eleType, + boolean autoFill) { + boolean writeMode = bufOffset < 0; + if (writeMode) { + bufOffset = writerIndex; + } + int numBytes = length * eleType.bytesPerEle; + if (autoFill) { + ensure(bufOffset + numBytes); + } + if (eleType == Types.JavaArray.BYTE && onHeap) { + System.arraycopy(arr, offset, heapMemory, memoryOffset + bufOffset, numBytes); + } else { + if (!Platform.IS_ANDROID) { + Platform.copyMemory( + arr, + eleType.arrayMemOffset + (long) offset * eleType.bytesPerEle, + heapMemory, + address + bufOffset, + numBytes); + } else { + buffer.position(bufOffset); + switch (eleType) { + case BOOL: + coverMemoryWithBoolArrayInner((boolean[]) arr, offset, length); + break; + case BYTE: + buffer.put((byte[]) arr, offset, length); + break; + case CHAR: + buffer.asCharBuffer().put((char[]) arr, offset, length); + break; + case SHORT: + buffer.asShortBuffer().put((short[]) arr, offset, length); + break; + case INT: + buffer.asIntBuffer().put((int[]) arr, offset, length); + break; + case LONG: + buffer.asLongBuffer().put((long[]) arr, offset, length); + break; + case FLOAT: + buffer.asFloatBuffer().put((float[]) arr, offset, length); + break; + case DOUBLE: + buffer.asDoubleBuffer().put((double[]) arr, offset, length); + break; + default: + throw new IllegalStateException("Unexpected value: " + eleType); + } + } + } + if (writeMode) { + writerIndex += numBytes; + } + } + + public void writeArray( + Object arr, int offset, int length, Types.JavaArray eleType, boolean autoFill) { + coverMemoryWithArray(-1, arr, offset, length, eleType, autoFill); + } + /** Write a primitive array into buffer with size varint encoded into the buffer. */ - public void writePrimitiveArrayWithSize(Object arr, int offset, int numBytes) { - int idx = writerIndex; - ensure(idx + 5 + numBytes); - idx += _unsafeWriteVarUint32(numBytes); - Platform.copyMemory(arr, offset, heapMemory, address + idx, numBytes); - writerIndex = idx + numBytes; + public void writeArrayWithSize(Object arr, int offset, int length, Types.JavaArray eleType) { + int numBytes = length * eleType.bytesPerEle; + ensure(writerIndex + 5 + numBytes); + writerIndex += _unsafeWriteVarUint32(numBytes); + writeArray(arr, offset, length, eleType, false); } - public void writePrimitiveArrayAlignedSize(Object arr, int offset, int numBytes) { + /*--------------------------------------------------------------------------------*/ + public void writeArrayAlignedSize(Object arr, int offset, int length, Types.JavaArray eleType) { + int numBytes = length * eleType.bytesPerEle; writeVarUint32Aligned(numBytes); - final int writerIdx = writerIndex; - final int newIdx = writerIdx + numBytes; - ensure(newIdx); - Platform.copyMemory(arr, offset, heapMemory, address + writerIdx, numBytes); - writerIndex = newIdx; + ensure(writerIndex + numBytes); + writeArray(arr, offset, length, eleType, false); } - public void writePrimitiveArray(Object arr, int offset, int numBytes) { - final int writerIdx = writerIndex; - final int newIdx = writerIdx + numBytes; - ensure(newIdx); - Platform.copyMemory(arr, offset, heapMemory, address + writerIdx, numBytes); - writerIndex = newIdx; - } + /*--------------------------------------------------------------------------------*/ /** For off-heap buffer, this will make a heap buffer internally. */ public void grow(int neededSize) { @@ -1250,7 +1390,7 @@ private void growBuffer(int length) { ? length << 2 : (int) Math.min(length * 1.5d, Integer.MAX_VALUE - 8); byte[] data = new byte[newSize]; - copyToUnsafe(0, data, Platform.BYTE_ARRAY_OFFSET, size()); + copyTo(0, data, 0, size, Types.JavaArray.BYTE, false); initHeapBuffer(data, 0, data.length); } @@ -1298,7 +1438,7 @@ public void readerIndex(int readerIndex) { // CHECKSTYLE.OFF:MethodName public int _unsafeHeapReaderIndex() { // CHECKSTYLE.ON:MethodName - return readerIndex + heapOffset; + return readerIndex + memoryOffset; } // CHECKSTYLE.OFF:MethodName @@ -2167,21 +2307,13 @@ private long skipPadding(long pos, int b) { } public byte[] readBytes(int length) { - int readerIdx = readerIndex; byte[] bytes = new byte[length]; // use subtract to avoid overflow - if (length > size - readerIdx) { + if (length > size - readerIndex) { streamReader.readTo(bytes, 0, length); return bytes; } - byte[] heapMemory = this.heapMemory; - if (heapMemory != null) { - // System.arraycopy faster for some jdk than Unsafe. - System.arraycopy(heapMemory, heapOffset + readerIdx, bytes, 0, length); - } else { - Platform.copyMemory(null, address + readerIdx, bytes, Platform.BYTE_ARRAY_OFFSET, length); - } - readerIndex = readerIdx + length; + readToUnchecked(bytes, 0, length, Types.JavaArray.BYTE); return bytes; } @@ -2195,8 +2327,7 @@ public void readBytes(byte[] dst, int dstIndex, int length) { if (dstIndex < 0 || dstIndex > dst.length - length) { throwIndexOOBExceptionForRead(); } - copyToUnsafe(readerIdx, dst, Platform.BYTE_ARRAY_OFFSET + dstIndex, length); - readerIndex = readerIdx + length; + readToUnchecked(dst, dstIndex, length, Types.JavaArray.BYTE); } public void readBytes(byte[] dst) { @@ -2226,7 +2357,7 @@ private long slowReadBytesAsInt64(int remaining, int len) { long result = 0; byte[] heapMemory = this.heapMemory; if (heapMemory != null) { - for (int i = 0, start = heapOffset + readerIdx; i < len; i++) { + for (int i = 0, start = memoryOffset + readerIdx; i < len; i++) { result |= (((long) heapMemory[start + i]) & 0xff) << (i * 8); } } else { @@ -2246,7 +2377,7 @@ public int read(ByteBuffer dst) { return streamReader.readToByteBuffer(dst); } if (heapMemory != null) { - dst.put(heapMemory, readerIndex + heapOffset, len); + dst.put(heapMemory, readerIndex + memoryOffset, len); } else { dst.put(sliceAsByteBuffer(readerIdx, len)); } @@ -2261,7 +2392,7 @@ public void read(ByteBuffer dst, int len) { streamReader.readToByteBuffer(dst, len); } else { if (heapMemory != null) { - dst.put(heapMemory, readerIndex + heapOffset, len); + dst.put(heapMemory, readerIndex + memoryOffset, len); } else { dst.put(sliceAsByteBuffer(readerIdx, len)); } @@ -2332,10 +2463,9 @@ public byte[] readBytesAndSize() { } byte[] heapMemory = this.heapMemory; if (heapMemory != null) { - System.arraycopy(heapMemory, heapOffset + readerIdx, arr, 0, numBytes); + System.arraycopy(heapMemory, memoryOffset + readerIdx, arr, 0, numBytes); } else { - Platform.UNSAFE.copyMemory( - null, address + readerIdx, arr, Platform.BYTE_ARRAY_OFFSET, numBytes); + Platform.copyMemory(null, address + readerIdx, arr, Platform.BYTE_ARRAY_OFFSET, numBytes); } readerIndex = readerIdx + numBytes; return arr; @@ -2350,51 +2480,31 @@ public byte[] readBytesWithAlignedSize() { streamReader.readTo(arr, 0, numBytes); return arr; } - Platform.UNSAFE.copyMemory( + Platform.copyMemory( this.heapMemory, this.address + readerIdx, arr, Platform.BYTE_ARRAY_OFFSET, numBytes); readerIndex = readerIdx + numBytes; return arr; } - /** This method should be used to read data written by {@link #writePrimitiveArrayWithSize}. */ + /** This method should be used to read data written by {@link #writeArrayWithSize}. */ public char[] readChars(int numBytes) { - int readerIdx = readerIndex; - final char[] chars = new char[numBytes >> 1]; - // use subtract to avoid overflow - if (readerIdx > size - numBytes) { - streamReader.readToUnsafe(chars, 0, numBytes); - return chars; - } - Platform.copyMemory( - heapMemory, address + readerIdx, chars, Platform.CHAR_ARRAY_OFFSET, numBytes); - readerIndex = readerIdx + numBytes; + int charLength = numBytes >> 1; + final char[] chars = new char[charLength]; + readTo(chars, 0, charLength, Types.JavaArray.CHAR); return chars; } - public void readChars(char[] chars, int offset, int numBytes) { - final int readerIdx = readerIndex; - // use subtract to avoid overflow - if (readerIdx > size - numBytes) { - streamReader.readToUnsafe(chars, offset, numBytes); - return; - } - Platform.copyMemory(heapMemory, address + readerIdx, chars, offset, numBytes); - readerIndex = readerIdx + numBytes; - } - @CodegenInvoke public char[] readCharsAndSize() { final int numBytes = readBinarySize(); - int readerIdx = readerIndex; - final char[] arr = new char[numBytes >> 1]; + int length = numBytes >> 1; + assert numBytes % 2 == 0; + final char[] arr = new char[length]; // use subtract to avoid overflow - if (readerIdx > size - numBytes) { - streamReader.readToUnsafe(arr, 0, numBytes); - return arr; + if (readerIndex > size - numBytes) { + streamReader.fillBuffer(numBytes - (size - readerIndex)); } - Platform.UNSAFE.copyMemory( - heapMemory, address + readerIdx, arr, Platform.CHAR_ARRAY_OFFSET, numBytes); - readerIndex = readerIdx + numBytes; + readToUnchecked(arr, 0, length, Types.JavaArray.CHAR); return arr; } @@ -2404,35 +2514,151 @@ public char[] readCharsWithAlignedSize() { } public long[] readLongs(int numBytes) { - int readerIdx = readerIndex; int numElements = numBytes >> 3; + assert (numBytes & 7) == 0; final long[] longs = new long[numElements]; // use subtract to avoid overflow - if (readerIdx > size - numBytes) { - streamReader.readToUnsafe(longs, 0, numElements); - return longs; + if (readerIndex > size - numBytes) { + streamReader.fillBuffer(numBytes - (size - readerIndex)); } - Platform.copyMemory( - heapMemory, address + readerIdx, longs, Platform.LONG_ARRAY_OFFSET, numBytes); - readerIndex = readerIdx + numBytes; + readToUnchecked(longs, 0, numElements, Types.JavaArray.LONG); return longs; } - /** - * Bulk copy method. Copies {@code numBytes} bytes to target unsafe object and pointer. NOTE: This - * is a unsafe method, no check here, please be carefully. - */ - public void readToUnsafe(Object target, long targetPointer, int numBytes) { - int remaining = size - readerIndex; - if (numBytes > remaining) { - streamReader.readToUnsafe(target, targetPointer, numBytes); + /*--------------------------------------------------------------------------------*/ + // 此函数依赖调用者事先调整好buffer的position, 并且他不会改变readerIndex + private void copyToBoolsInner(boolean[] target, int offset, int length) { + // Fast Path: Use pooling and chunking for large arrays. + if (length >= BOOLEAN_TRANSFER_THRESHOLD) { + byte[] tmpBytes = BufferPool.INSTANCE.borrow(length, true); + // If borrowing was successful, proceed with the optimized path. + if (tmpBytes != null && tmpBytes.length >= BOOLEAN_TRANSFER_THRESHOLD / 3) { + int remaining = length; + int currentOffset = offset; + while (remaining > 0) { + int chunkSize = Math.min(remaining, tmpBytes.length); + buffer.get(tmpBytes, 0, chunkSize); + for (int i = 0; i < chunkSize; i++) { + target[currentOffset + i] = (tmpBytes[i] == 1); + } + remaining -= chunkSize; + currentOffset += chunkSize; + } + BufferPool.INSTANCE.release(tmpBytes); + return; + } + } + // Fallback Path: For small arrays or if the buffer pool was exhausted. + int limit = offset + length; + for (int i = offset; i < limit; i++) { + target[i] = (buffer.get() != 0); + } + } + + @SuppressWarnings("deprecation") + // bufOffset为负数代表为阅读模式,使用readerIndex, 否则为纯copy, 不会对指针有影响 + public void copyTo( + int bufOffset, + Object target, + int offset, + int length, + Types.JavaArray eleType, + boolean checkSize) { + boolean readMode = bufOffset < 0; + if (readMode) { + bufOffset = readerIndex; + } + int numBytes = length * eleType.bytesPerEle; + if (checkSize) { + int remaining = size - bufOffset; + if (numBytes > remaining) { + streamReader.fillBuffer(numBytes - remaining); + } + } + if (eleType == Types.JavaArray.BYTE && onHeap) { + System.arraycopy(heapMemory, memoryOffset + bufOffset, target, offset, numBytes); + } else { + if (!Platform.IS_ANDROID) { + Platform.copyMemory( + heapMemory, + address + bufOffset, + target, + eleType.arrayMemOffset + (long) offset * eleType.bytesPerEle, + numBytes); + } else { + buffer.position(bufOffset); + switch (eleType) { + case BOOL: + copyToBoolsInner((boolean[]) target, offset, length); + break; + case BYTE: + buffer.get((byte[]) target, offset, length); + break; + case CHAR: + buffer.asCharBuffer().get((char[]) target, offset, length); + break; + case SHORT: + buffer.asShortBuffer().get((short[]) target, offset, length); + break; + case INT: + buffer.asIntBuffer().get((int[]) target, offset, length); + break; + case LONG: + buffer.asLongBuffer().get((long[]) target, offset, length); + break; + case FLOAT: + buffer.asFloatBuffer().get((float[]) target, offset, length); + break; + case DOUBLE: + buffer.asDoubleBuffer().get((double[]) target, offset, length); + break; + default: + throw new IllegalStateException("Unsupported element type: " + eleType); + } + } + } + if (readMode) { + readerIndex += numBytes; + } + } + + public void copyTo(int offset, MemoryBuffer target, int targetOffset, int numBytes) { + final long thisPointer = this.address + offset; + final long otherPointer = target.address + targetOffset; + if ((numBytes | offset | targetOffset) >= 0 + && thisPointer <= this.addressLimit - numBytes + && otherPointer <= target.addressLimit - numBytes) { + if (Platform.IS_ANDROID) { + int thisOldLimit = this.buffer.limit(); + this.buffer.position(offset); + this.buffer.limit(offset + numBytes); + target.buffer.position(targetOffset); + target.buffer.put(this.buffer); + this.buffer.limit(thisOldLimit); + } else { + Platform.copyMemory( + this.heapMemory, thisPointer, target.heapMemory, otherPointer, numBytes); + } } else { - int readerIdx = readerIndex; - Platform.copyMemory(heapMemory, address + readerIdx, target, targetPointer, numBytes); - readerIndex = readerIdx + numBytes; + throw new IndexOutOfBoundsException( + String.format( + "offset=%d, targetOffset=%d, numBytes=%d, address=%d, targetAddress=%d", + offset, targetOffset, numBytes, this.address, target.address)); } } + public void readTo(Object target, int offset, int length, Types.JavaArray eleType) { + copyTo(-1, target, offset, length, eleType, true); + } + + public void readToUnchecked(Object target, int offset, int length, Types.JavaArray eleType) { + copyTo(-1, target, offset, length, eleType, false); + } + + /*--------------------------------------------------------------------------------*/ + + /*--------------------------------------------------------------------------------*/ + public void checkReadableBytes(int minimumReadableBytes) { // use subtract to avoid overflow int remaining = size - readerIndex; @@ -2447,7 +2673,7 @@ public void checkReadableBytes(int minimumReadableBytes) { */ public byte[] getRemainingBytes() { int length = size - readerIndex; - if (heapMemory != null && size == length && heapOffset == 0) { + if (heapMemory != null && size == length && memoryOffset == 0) { return heapMemory; } else { return getBytes(readerIndex, length); @@ -2455,42 +2681,50 @@ public byte[] getRemainingBytes() { } // ------------------------- Read Methods Finished ------------------------------------- - /** * Bulk copy method. Copies {@code numBytes} bytes to target unsafe object and pointer. NOTE: This * is a unsafe method, no check here, please be carefully. */ - public void copyToUnsafe(long offset, Object target, long targetPointer, int numBytes) { + @NotForAndroid + @SuppressWarnings("deprecation") + public void copyToDirectUnsafe(int offset, long targetAddress, int numBytes) { final long thisPointer = this.address + offset; checkArgument(thisPointer + numBytes <= addressLimit); - Platform.copyMemory(this.heapMemory, thisPointer, target, targetPointer, numBytes); + if (Platform.IS_ANDROID) { + if (onHeap) { + Platform.throwException( + new OperationNotSupportedException( + "Cannot copy heap memory to native address on Android.")); + } else { + // android的copyMemory只支持这个三个参数的(堆外内存拷贝) + Platform.UNSAFE.copyMemory(thisPointer, targetAddress, numBytes); + } + return; + } + Platform.copyMemory(this.heapMemory, thisPointer, null, targetAddress, numBytes); } /** * Bulk copy method. Copies {@code numBytes} bytes from source unsafe object and pointer. NOTE: * This is an unsafe method, no check here, please be careful. */ - public void copyFromUnsafe(long offset, Object source, long sourcePointer, long numBytes) { + @NotForAndroid + @SuppressWarnings("deprecation") + public void copyFromDirectUnsafe(long offset, long sourcePointer, long numBytes) { final long thisPointer = this.address + offset; checkArgument(thisPointer + numBytes <= addressLimit); - Platform.copyMemory(source, sourcePointer, this.heapMemory, thisPointer, numBytes); - } - - public void copyTo(int offset, MemoryBuffer target, int targetOffset, int numBytes) { - final byte[] thisHeapRef = this.heapMemory; - final byte[] otherHeapRef = target.heapMemory; - final long thisPointer = this.address + offset; - final long otherPointer = target.address + targetOffset; - if ((numBytes | offset | targetOffset) >= 0 - && thisPointer <= this.addressLimit - numBytes - && otherPointer <= target.addressLimit - numBytes) { - UNSAFE.copyMemory(thisHeapRef, thisPointer, otherHeapRef, otherPointer, numBytes); - } else { - throw new IndexOutOfBoundsException( - String.format( - "offset=%d, targetOffset=%d, numBytes=%d, address=%d, targetAddress=%d", - offset, targetOffset, numBytes, this.address, target.address)); + if (Platform.IS_ANDROID) { + if (onHeap) { + Platform.throwException( + new OperationNotSupportedException( + "Cannot copy heap memory to native address on Android.")); + } else { + // android的copyMemory只支持这个三个参数的(堆外内存拷贝) + Platform.UNSAFE.copyMemory(sourcePointer, thisPointer, numBytes); + } + return; } + Platform.copyMemory(null, sourcePointer, this.heapMemory, thisPointer, numBytes); } public void copyFrom(int offset, MemoryBuffer source, int sourcePointer, int numBytes) { @@ -2498,7 +2732,7 @@ public void copyFrom(int offset, MemoryBuffer source, int sourcePointer, int num } public byte[] getBytes(int index, int length) { - if (index == 0 && heapMemory != null && heapOffset == 0) { + if (index == 0 && heapMemory != null && memoryOffset == 0) { // Arrays.copyOf is an intrinsics, which is faster return Arrays.copyOf(heapMemory, length); } @@ -2506,20 +2740,10 @@ public byte[] getBytes(int index, int length) { throwIndexOOBExceptionForRead(length); } byte[] data = new byte[length]; - copyToUnsafe(index, data, Platform.BYTE_ARRAY_OFFSET, length); + copyTo(index, data, 0, length, Types.JavaArray.BYTE, false); return data; } - public void getBytes(int index, byte[] dst, int dstIndex, int length) { - if (dstIndex > dst.length - length) { - throwOOBException(); - } - if (index > size - length) { - throwOOBException(); - } - copyToUnsafe(index, dst, Platform.BYTE_ARRAY_OFFSET + dstIndex, length); - } - public MemoryBuffer slice(int offset) { return slice(offset, size - offset); } @@ -2528,10 +2752,16 @@ public MemoryBuffer slice(int offset, int length) { if (offset + length > size) { throwOOBExceptionForRange(offset, length); } - if (heapMemory != null) { - return new MemoryBuffer(heapMemory, heapOffset + offset, length); + if (onHeap) { + return new MemoryBuffer(heapMemory, memoryOffset + offset, length); } else { - return new MemoryBuffer(address + offset, length, offHeapBuffer); + if (this.buffer == null) { + // for android, can't construct a ByteBuffer from native address directly + return MemoryBuffer.fromNativeAddress(address + offset, length); + } else { + buffer.position(offset); + return MemoryBuffer.fromByteBuffer(buffer, length); + } } } @@ -2539,21 +2769,19 @@ public ByteBuffer sliceAsByteBuffer() { return sliceAsByteBuffer(readerIndex, size - readerIndex); } + @PartialAndroidSupport public ByteBuffer sliceAsByteBuffer(int offset, int length) { if (offset + length > size) { throwOOBExceptionForRange(offset, length); } if (heapMemory != null) { - return ByteBuffer.wrap(heapMemory, heapOffset + offset, length).slice(); + return ByteBuffer.wrap(heapMemory, memoryOffset + offset, length).slice(); } else { - ByteBuffer offHeapBuffer = this.offHeapBuffer; - if (offHeapBuffer != null) { - ByteBuffer duplicate = offHeapBuffer.duplicate(); - int start = (int) (address - ByteBufferUtil.getAddress(duplicate)); - ByteBufferUtil.position(duplicate, start + offset); - duplicate.limit(start + offset + length); - return duplicate.slice(); + if (this.buffer != null) { + this.buffer.position(offset); + return buffer.slice(); } else { + // for android, can't construct a ByteBuffer from native address directly return ByteBufferUtil.createDirectByteBufferFromNativeAddress(address + offset, length); } } @@ -2564,10 +2792,6 @@ private void throwOOBExceptionForRange(int offset, int length) { String.format("offset(%d) + length(%d) exceeds size(%d): %s", offset, length, size, this)); } - public ForyStreamReader getStreamReader() { - return streamReader; - } - /** * Equals two memory buffer regions. * @@ -2597,9 +2821,9 @@ public String toString() { + ", heapMemory=" + (heapMemory == null ? null : "len(" + heapMemory.length + ")") + ", heapOffset=" - + heapOffset + + memoryOffset + ", offHeapBuffer=" - + offHeapBuffer + + buffer + ", address=" + address + ", addressLimit=" @@ -2612,57 +2836,71 @@ public void pointTo(byte[] buffer, int offset, int length) { initHeapBuffer(buffer, offset, length); } - /** Creates a new memory buffer that targets to the given heap memory region. */ - public static MemoryBuffer fromByteArray(byte[] buffer, int offset, int length) { - return new MemoryBuffer(buffer, offset, length, null); + /** + * Creates a new memory buffer that represents the provided native memory. The buffer will change + * into a heap buffer automatically if not enough. + */ + // TODO: support android + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") + public static MemoryBuffer fromNativeAddress(long address, int size) { + if (Platform.IS_ANDROID) { + throw new UnsupportedOperationException( + "Android does not support support off-heap memory only by address"); + } + return new MemoryBuffer(address, null, size, null, false); } - public static MemoryBuffer fromByteArray( - byte[] buffer, int offset, int length, ForyStreamReader streamReader) { - return new MemoryBuffer(buffer, offset, length, streamReader); - } + /*-------------------------------static named constructor----------------------------------*/ /** Creates a new memory buffer that targets to the given heap memory region. */ - public static MemoryBuffer fromByteArray(byte[] buffer) { + public static MemoryBuffer wrap(byte[] buffer) { return new MemoryBuffer(buffer, 0, buffer.length); } /** - * Creates a new memory buffer that represents the memory backing the given byte buffer section of - * {@code [buffer.position(), buffer.limit())}. The buffer will change into a heap buffer - * automatically if not enough. + * Creates a new memory segment that represents the memory backing the given byte buffer section + * of [buffer.position(), buffer,limit()]. * - * @param buffer a direct buffer or heap buffer + * @param byteBuffer a direct buffer or heap buffer */ - public static MemoryBuffer fromByteBuffer(ByteBuffer buffer) { - if (buffer.isDirect()) { - return new MemoryBuffer( - ByteBufferUtil.getAddress(buffer) + buffer.position(), buffer.remaining(), buffer); - } else { - int offset = buffer.arrayOffset() + buffer.position(); - return new MemoryBuffer(buffer.array(), offset, buffer.remaining()); - } + public static MemoryBuffer wrap(ByteBuffer byteBuffer) { + return fromByteBuffer(byteBuffer, byteBuffer.remaining()); } - public static MemoryBuffer fromDirectByteBuffer( - ByteBuffer buffer, int size, ForyStreamReader streamReader) { - long offHeapAddress = ByteBufferUtil.getAddress(buffer) + buffer.position(); - return new MemoryBuffer(offHeapAddress, size, buffer, streamReader); + public static MemoryBuffer buffer(int size) { + return newHeapBuffer(size); } /** - * Creates a new memory buffer that represents the provided native memory. The buffer will change - * into a heap buffer automatically if not enough. + * Create a heap buffer of specified initial size. The buffer will grow automatically if not + * enough. */ - public static MemoryBuffer fromNativeAddress(long address, int size) { - return new MemoryBuffer(address, size, null); + public static MemoryBuffer newHeapBuffer(int initialSize) { + return wrap(new byte[initialSize]); + } + + public static MemoryBuffer bufferDirect(int size) { + return new MemoryBuffer(-1, ByteBuffer.allocateDirect(size), size, null, true); } /** - * Create a heap buffer of specified initial size. The buffer will grow automatically if not - * enough. + * Creates a new memory buffer that represents the native memory at the absolute address given by + * the pointer. + * + * @param length The size of this memory buffer. + * @param byteBuffer The byte buffer whose memory is represented by this memory buffer which */ - public static MemoryBuffer newHeapBuffer(int initialSize) { - return fromByteArray(new byte[initialSize]); + private static MemoryBuffer fromByteBuffer(ByteBuffer byteBuffer, int length) { + if (byteBuffer.isDirect()) { + return new MemoryBuffer(-1, byteBuffer, length, null, false); + } else { + int offset = byteBuffer.arrayOffset() + byteBuffer.position(); + return new MemoryBuffer(byteBuffer.array(), offset, byteBuffer.remaining()); + } + } + + public static MemoryBuffer fromDirectByteBuffer( + ByteBuffer buffer, int size, ForyStreamReader streamReader) { + return new MemoryBuffer(-1, buffer, size, streamReader, false); } } diff --git a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryUtils.java b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryUtils.java index 1eee8d6915..bc81d1c43f 100644 --- a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryUtils.java +++ b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryUtils.java @@ -21,51 +21,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; import org.apache.fory.util.Preconditions; /** Memory utils for fory. */ public class MemoryUtils { - public static MemoryBuffer buffer(int size) { - return wrap(new byte[size]); - } - - public static MemoryBuffer buffer(long address, int size) { - return MemoryBuffer.fromNativeAddress(address, size); - } - - /** - * Creates a new memory segment that targets to the given heap memory region. - * - *

This method should be used to turn short lived byte arrays into memory segments. - * - * @param buffer The heap memory region. - * @return A new memory segment that targets the given heap memory region. - */ - public static MemoryBuffer wrap(byte[] buffer, int offset, int length) { - return MemoryBuffer.fromByteArray(buffer, offset, length); - } - - public static MemoryBuffer wrap(byte[] buffer) { - return MemoryBuffer.fromByteArray(buffer); - } - - /** - * Creates a new memory segment that represents the memory backing the given byte buffer section - * of [buffer.position(), buffer,limit()). - * - * @param buffer a direct buffer or heap buffer - */ - public static MemoryBuffer wrap(ByteBuffer buffer) { - if (buffer.isDirect()) { - return MemoryBuffer.fromByteBuffer(buffer); - } else { - int offset = buffer.arrayOffset() + buffer.position(); - return MemoryBuffer.fromByteArray(buffer.array(), offset, buffer.remaining()); - } - } - // Lazy load offset and also follow graalvm offset auto replace pattern. private static class Offset { private static final long BAS_BUF_BUF; @@ -105,7 +65,7 @@ public static void wrap(ByteArrayOutputStream stream, MemoryBuffer buffer) { } /** - * Wrap a @link MemoryBuffer} into a {@link ByteArrayOutputStream}. The count of stream will be + * Wrap a @{link MemoryBuffer} into a {@link ByteArrayOutputStream}. The count of stream will be * the writerIndex of buffer. */ public static void wrap(MemoryBuffer buffer, ByteArrayOutputStream stream) { diff --git a/java/fory-core/src/main/java/org/apache/fory/memory/Platform.java b/java/fory-core/src/main/java/org/apache/fory/memory/Platform.java index 7d87262754..73926fe78a 100644 --- a/java/fory-core/src/main/java/org/apache/fory/memory/Platform.java +++ b/java/fory-core/src/main/java/org/apache/fory/memory/Platform.java @@ -33,8 +33,10 @@ public final class Platform { @SuppressWarnings("restriction") public static final Unsafe UNSAFE = _JDKAccess.UNSAFE; + public static final boolean IS_ANDROID = _JDKAccess.IS_ANDROID; public static final int JAVA_VERSION = _JDKAccess.JAVA_VERSION; - public static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; + public static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder(); + public static final boolean IS_LITTLE_ENDIAN = NATIVE_BYTE_ORDER == ByteOrder.LITTLE_ENDIAN; public static final Class HEAP_BYTE_BUFFER_CLASS = ByteBuffer.allocate(1).getClass(); public static final Class DIRECT_BYTE_BUFFER_CLASS = ByteBuffer.allocateDirect(1).getClass(); public static final int BOOLEAN_ARRAY_OFFSET; @@ -220,6 +222,7 @@ public static void setMemory(long address, byte value, long size) { UNSAFE.setMemory(address, size, value); } + @Deprecated public static void copyMemory( Object src, long srcOffset, Object dst, long dstOffset, long length) { if (length < UNSAFE_COPY_THRESHOLD) { @@ -282,8 +285,15 @@ public static boolean arrayEquals( return true; } + private static void sneakyThrow(Throwable throwable) throws T { + throw (T) throwable; // 将受检异常强制转换为一个未知的泛型异常类型并抛出 + } + /** Raises an exception bypassing compiler checks for checked exceptions. */ public static void throwException(Throwable t) { + if (IS_ANDROID) { + sneakyThrow(t); + } UNSAFE.throwException(t); } diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefDecoder.java b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefDecoder.java index 5a6ec59333..d531952466 100644 --- a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefDecoder.java +++ b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefDecoder.java @@ -66,7 +66,7 @@ static Tuple2 decodeClassDefBuf( public static ClassDef decodeClassDef(ClassResolver resolver, MemoryBuffer buffer, long id) { Tuple2 decoded = decodeClassDefBuf(buffer, resolver, id); - MemoryBuffer classDefBuf = MemoryBuffer.fromByteArray(decoded.f0); + MemoryBuffer classDefBuf = MemoryBuffer.wrap(decoded.f0); int numClasses = classDefBuf.readByte(); if (numClasses == NUM_CLASS_THRESHOLD) { numClasses += classDefBuf.readVarUint32Small7(); diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefEncoder.java b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefEncoder.java index 53c6b04675..7bdd139bcf 100644 --- a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefEncoder.java +++ b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDefEncoder.java @@ -37,7 +37,6 @@ import org.apache.fory.Fory; import org.apache.fory.collection.Tuple2; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.meta.ClassDef.FieldInfo; import org.apache.fory.meta.ClassDef.FieldType; import org.apache.fory.reflect.ReflectionUtils; @@ -176,7 +175,7 @@ static MemoryBuffer encodeClassDef( boolean isCompressed = false; if (compressed.length < classDefBuf.writerIndex()) { isCompressed = true; - classDefBuf = MemoryBuffer.fromByteArray(compressed); + classDefBuf = MemoryBuffer.wrap(compressed); classDefBuf.writerIndex(compressed.length); } return prependHeader(classDefBuf, isCompressed, hasFieldsMeta); @@ -196,7 +195,7 @@ static MemoryBuffer prependHeader( header |= HAS_FIELDS_META_FLAG; } header |= Math.min(metaSize, META_SIZE_MASKS); - MemoryBuffer result = MemoryUtils.buffer(metaSize + 8); + MemoryBuffer result = MemoryBuffer.buffer(metaSize + 8); result.writeInt64(header); if (metaSize > META_SIZE_MASKS) { result.writeVarUint32(metaSize - META_SIZE_MASKS); diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefDecoder.java b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefDecoder.java index 88cbceb714..adfc2ccd6e 100644 --- a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefDecoder.java +++ b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefDecoder.java @@ -46,7 +46,7 @@ class TypeDefDecoder { public static ClassDef decodeClassDef(XtypeResolver resolver, MemoryBuffer inputBuffer, long id) { Tuple2 decoded = decodeClassDefBuf(inputBuffer, resolver, id); - MemoryBuffer buffer = MemoryBuffer.fromByteArray(decoded.f0); + MemoryBuffer buffer = MemoryBuffer.wrap(decoded.f0); byte header = buffer.readByte(); int numFields = header & SMALL_NUM_FIELDS_THRESHOLD; if (numFields == SMALL_NUM_FIELDS_THRESHOLD) { diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java index 7981aba18b..873c5ad1a6 100644 --- a/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java +++ b/java/fory-core/src/main/java/org/apache/fory/meta/TypeDefEncoder.java @@ -123,7 +123,7 @@ static MemoryBuffer encodeClassDef( boolean isCompressed = false; if (compressed.length < buffer.writerIndex()) { isCompressed = true; - buffer = MemoryBuffer.fromByteArray(compressed); + buffer = MemoryBuffer.wrap(compressed); buffer.writerIndex(compressed.length); } return prependHeader(buffer, isCompressed, true); diff --git a/java/fory-core/src/main/java/org/apache/fory/pool/ThreadPoolFory.java b/java/fory-core/src/main/java/org/apache/fory/pool/ThreadPoolFory.java index 6f81066c93..95560679d5 100644 --- a/java/fory-core/src/main/java/org/apache/fory/pool/ThreadPoolFory.java +++ b/java/fory-core/src/main/java/org/apache/fory/pool/ThreadPoolFory.java @@ -28,12 +28,12 @@ import org.apache.fory.AbstractThreadSafeFory; import org.apache.fory.Fory; import org.apache.fory.annotation.Internal; +import org.apache.fory.annotation.NotForAndroid; import org.apache.fory.io.ForyInputStream; import org.apache.fory.io.ForyReadableChannel; import org.apache.fory.logging.Logger; import org.apache.fory.logging.LoggerFactory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.resolver.ClassChecker; import org.apache.fory.serializer.BufferCallback; import org.apache.fory.util.LoaderBinding; @@ -100,6 +100,7 @@ public byte[] serialize(Object obj, BufferCallback callback) { return execute(fory -> fory.serialize(obj, callback)); } + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") @Override public MemoryBuffer serialize(Object obj, long address, int size) { return execute(fory -> fory.serialize(obj, address, size)); @@ -148,6 +149,7 @@ public Object deserialize(byte[] bytes, Iterable outOfBandBuffers) return execute(fory -> fory.deserialize(bytes, outOfBandBuffers)); } + @NotForAndroid(reason = "Android does not support support off-heap memory only by address") @Override public Object deserialize(long address, int size) { return execute(fory -> fory.deserialize(address, size)); @@ -160,7 +162,7 @@ public Object deserialize(MemoryBuffer buffer) { @Override public Object deserialize(ByteBuffer byteBuffer) { - return execute(fory -> fory.deserialize(MemoryUtils.wrap(byteBuffer))); + return execute(fory -> fory.deserialize(MemoryBuffer.wrap(byteBuffer))); } @Override diff --git a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java index 0e62c54d40..1c02f24035 100644 --- a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java +++ b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java @@ -345,9 +345,11 @@ private void addDefaultSerializers() { CollectionSerializers.registerDefaultSerializers(fory); MapSerializers.registerDefaultSerializers(fory); addDefaultSerializer(Locale.class, new LocaleSerializer(fory)); - addDefaultSerializer( - LambdaSerializer.ReplaceStub.class, - new LambdaSerializer(fory, LambdaSerializer.ReplaceStub.class)); + if (!Platform.IS_ANDROID) { + addDefaultSerializer( + LambdaSerializer.ReplaceStub.class, + new LambdaSerializer(fory, LambdaSerializer.ReplaceStub.class)); + } addDefaultSerializer( JdkProxySerializer.ReplaceStub.class, new JdkProxySerializer(fory, JdkProxySerializer.ReplaceStub.class)); @@ -358,7 +360,7 @@ private void addDefaultSerializers() { UnmodifiableSerializers.registerSerializers(fory); ImmutableCollectionSerializers.registerSerializers(fory); SubListSerializers.registerSerializers(fory, true); - if (fory.getConfig().registerGuavaTypes()) { + if (fory.getConfig().registerGuavaTypes() && !Platform.IS_ANDROID) { GuavaCollectionSerializers.registerDefaultSerializers(fory); } if (fory.getConfig().deserializeNonexistentClass()) { diff --git a/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java b/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java index dbb63f6c43..7ba32f8b6c 100644 --- a/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java +++ b/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java @@ -21,11 +21,9 @@ import java.lang.reflect.Array; import java.util.Arrays; -import java.util.IdentityHashMap; import org.apache.fory.Fory; import org.apache.fory.config.CompatibleMode; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.Platform; import org.apache.fory.resolver.ClassInfo; import org.apache.fory.resolver.ClassInfoHolder; import org.apache.fory.resolver.ClassResolver; @@ -34,7 +32,7 @@ import org.apache.fory.serializer.collection.ForyArrayAsListSerializer; import org.apache.fory.type.GenericType; import org.apache.fory.type.TypeUtils; -import org.apache.fory.type.Types; +import org.apache.fory.type.Types.JavaArray; import org.apache.fory.util.Preconditions; /** Serializers for array types. */ @@ -212,14 +210,14 @@ private Object[] newArray(int numElements) { public static final class PrimitiveArrayBufferObject implements BufferObject { private final Object array; - private final int offset; private final int elemSize; private final int length; + private final JavaArray eleType; - public PrimitiveArrayBufferObject(Object array, int offset, int elemSize, int length) { + public PrimitiveArrayBufferObject(Object array, int length, JavaArray eleType) { this.array = array; - this.offset = offset; - this.elemSize = elemSize; + this.eleType = eleType; + this.elemSize = eleType.bytesPerEle; this.length = length; } @@ -230,12 +228,7 @@ public int totalBytes() { @Override public void writeTo(MemoryBuffer buffer) { - int size = Math.multiplyExact(length, elemSize); - int writerIndex = buffer.writerIndex(); - int end = writerIndex + size; - buffer.ensure(end); - buffer.copyFromUnsafe(writerIndex, array, offset, size); - buffer.writerIndex(end); + buffer.writeArray(array, 0, length, eleType, true); } @Override @@ -252,12 +245,14 @@ public abstract static class PrimitiveArraySerializer extends Serializers.CrossLanguageCompatibleSerializer { protected final int offset; protected final int elemSize; + protected final JavaArray eleType; - public PrimitiveArraySerializer(Fory fory, Class cls) { + public PrimitiveArraySerializer(Fory fory, Class cls, JavaArray eleType) { super(fory, cls); - Class innerType = TypeUtils.getArrayComponentInfo(cls).f0; - this.offset = primitiveInfo.get(innerType)[0]; - this.elemSize = primitiveInfo.get(innerType)[1]; + this.eleType = eleType; + // Class innerType = TypeUtils.getArrayComponentInfo(cls).f0; + this.offset = eleType.arrayMemOffset; + this.elemSize = eleType.bytesPerEle; } @Override @@ -274,17 +269,18 @@ public T xread(MemoryBuffer buffer) { public static final class BooleanArraySerializer extends PrimitiveArraySerializer { public BooleanArraySerializer(Fory fory) { - super(fory, boolean[].class); + super(fory, boolean[].class, JavaArray.BOOL); } @Override public void write(MemoryBuffer buffer, boolean[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, elemSize); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, elemSize); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, elemSize, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -300,13 +296,14 @@ public boolean[] read(MemoryBuffer buffer) { int size = buf.remaining(); int numElements = size / elemSize; boolean[] values = new boolean[numElements]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, numElements, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); int numElements = size / elemSize; boolean[] values = new boolean[numElements]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, numElements, eleType); return values; } } @@ -315,17 +312,18 @@ public boolean[] read(MemoryBuffer buffer) { public static final class ByteArraySerializer extends PrimitiveArraySerializer { public ByteArraySerializer(Fory fory) { - super(fory, byte[].class); + super(fory, byte[].class, JavaArray.BYTE); } @Override public void write(MemoryBuffer buffer, byte[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, 1); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, 1); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, 1, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -340,12 +338,13 @@ public byte[] read(MemoryBuffer buffer) { MemoryBuffer buf = fory.readBufferObject(buffer); int size = buf.remaining(); byte[] values = new byte[size]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, size, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); byte[] values = new byte[size]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, size, eleType); return values; } } @@ -354,17 +353,18 @@ public byte[] read(MemoryBuffer buffer) { public static final class CharArraySerializer extends PrimitiveArraySerializer { public CharArraySerializer(Fory fory) { - super(fory, char[].class); + super(fory, char[].class, JavaArray.CHAR); } @Override public void write(MemoryBuffer buffer, char[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, elemSize); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, elemSize); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, elemSize, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -380,13 +380,14 @@ public char[] read(MemoryBuffer buffer) { int size = buf.remaining(); int numElements = size / elemSize; char[] values = new char[numElements]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, numElements, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); int numElements = size / elemSize; char[] values = new char[numElements]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, numElements, eleType); return values; } } @@ -405,17 +406,18 @@ public char[] xread(MemoryBuffer buffer) { public static final class ShortArraySerializer extends PrimitiveArraySerializer { public ShortArraySerializer(Fory fory) { - super(fory, short[].class); + super(fory, short[].class, JavaArray.SHORT); } @Override public void write(MemoryBuffer buffer, short[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, elemSize); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, elemSize); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, elemSize, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -431,13 +433,14 @@ public short[] read(MemoryBuffer buffer) { int size = buf.remaining(); int numElements = size / elemSize; short[] values = new short[numElements]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, numElements, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); int numElements = size / elemSize; short[] values = new short[numElements]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, numElements, eleType); return values; } } @@ -446,17 +449,18 @@ public short[] read(MemoryBuffer buffer) { public static final class IntArraySerializer extends PrimitiveArraySerializer { public IntArraySerializer(Fory fory) { - super(fory, int[].class); + super(fory, int[].class, JavaArray.INT); } @Override public void write(MemoryBuffer buffer, int[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, elemSize); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, elemSize); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, elemSize, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -472,13 +476,14 @@ public int[] read(MemoryBuffer buffer) { int size = buf.remaining(); int numElements = size / elemSize; int[] values = new int[numElements]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, numElements, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); int numElements = size / elemSize; int[] values = new int[numElements]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, numElements, eleType); return values; } } @@ -487,17 +492,18 @@ public int[] read(MemoryBuffer buffer) { public static final class LongArraySerializer extends PrimitiveArraySerializer { public LongArraySerializer(Fory fory) { - super(fory, long[].class); + super(fory, long[].class, JavaArray.LONG); } @Override public void write(MemoryBuffer buffer, long[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, elemSize); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, elemSize); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, elemSize, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -513,13 +519,14 @@ public long[] read(MemoryBuffer buffer) { int size = buf.remaining(); int numElements = size / elemSize; long[] values = new long[numElements]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, numElements, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); int numElements = size / elemSize; long[] values = new long[numElements]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, numElements, eleType); return values; } } @@ -528,17 +535,18 @@ public long[] read(MemoryBuffer buffer) { public static final class FloatArraySerializer extends PrimitiveArraySerializer { public FloatArraySerializer(Fory fory) { - super(fory, float[].class); + super(fory, float[].class, JavaArray.FLOAT); } @Override public void write(MemoryBuffer buffer, float[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, elemSize); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, elemSize); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, elemSize, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -554,13 +562,14 @@ public float[] read(MemoryBuffer buffer) { int size = buf.remaining(); int numElements = size / elemSize; float[] values = new float[numElements]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, numElements, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); int numElements = size / elemSize; float[] values = new float[numElements]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, numElements, eleType); return values; } } @@ -569,17 +578,18 @@ public float[] read(MemoryBuffer buffer) { public static final class DoubleArraySerializer extends PrimitiveArraySerializer { public DoubleArraySerializer(Fory fory) { - super(fory, double[].class); + super(fory, double[].class, JavaArray.DOUBLE); } @Override public void write(MemoryBuffer buffer, double[] value) { if (fory.getBufferCallback() == null) { - int size = Math.multiplyExact(value.length, elemSize); - buffer.writePrimitiveArrayWithSize(value, offset, size); + // int size = Math.multiplyExact(value.length, elemSize); + // buffer.writePrimitiveArrayWithSize(value, offset, size); + buffer.writeArrayWithSize(value, 0, value.length, eleType); } else { fory.writeBufferObject( - buffer, new PrimitiveArrayBufferObject(value, offset, elemSize, value.length)); + buffer, new PrimitiveArrayBufferObject(value, value.length, eleType)); } } @@ -595,13 +605,14 @@ public double[] read(MemoryBuffer buffer) { int size = buf.remaining(); int numElements = size / elemSize; double[] values = new double[numElements]; - buf.copyToUnsafe(0, values, offset, size); + // buf.copyToUnsafe(0, values, offset, size); + buf.copyTo(0, values, 0, numElements, eleType, false); return values; } else { int size = buffer.readVarUint32Small7(); int numElements = size / elemSize; double[] values = new double[numElements]; - buffer.readToUnsafe(values, offset, size); + buffer.readTo(values, 0, numElements, eleType); return values; } } @@ -735,38 +746,6 @@ public static void registerDefaultSerializers(Fory fory) { } // ########################## utils ########################## - - static void writePrimitiveArray( - MemoryBuffer buffer, Object arr, int offset, int numElements, int elemSize) { - int size = Math.multiplyExact(numElements, elemSize); - buffer.writeVarUint32Small7(size); - int writerIndex = buffer.writerIndex(); - int end = writerIndex + size; - buffer.ensure(end); - buffer.copyFromUnsafe(writerIndex, arr, offset, size); - buffer.writerIndex(end); - } - - public static PrimitiveArrayBufferObject byteArrayBufferObject(byte[] array) { - return new PrimitiveArrayBufferObject(array, Platform.BYTE_ARRAY_OFFSET, 1, array.length); - } - - static final IdentityHashMap, int[]> primitiveInfo = new IdentityHashMap<>(); - - static { - primitiveInfo.put( - boolean.class, new int[] {Platform.BOOLEAN_ARRAY_OFFSET, 1, Types.BOOL_ARRAY}); - primitiveInfo.put(byte.class, new int[] {Platform.BYTE_ARRAY_OFFSET, 1, Types.BINARY}); - primitiveInfo.put( - char.class, new int[] {Platform.CHAR_ARRAY_OFFSET, 2, Fory.NOT_SUPPORT_XLANG}); - primitiveInfo.put(short.class, new int[] {Platform.SHORT_ARRAY_OFFSET, 2, Types.INT16_ARRAY}); - primitiveInfo.put(int.class, new int[] {Platform.INT_ARRAY_OFFSET, 4, Types.INT32_ARRAY}); - primitiveInfo.put(long.class, new int[] {Platform.LONG_ARRAY_OFFSET, 8, Types.INT64_ARRAY}); - primitiveInfo.put(float.class, new int[] {Platform.FLOAT_ARRAY_OFFSET, 4, Types.FLOAT32_ARRAY}); - primitiveInfo.put( - double.class, new int[] {Platform.DOUBLE_ARRAY_OFFSET, 8, Types.FLOAT64_ARRAY}); - } - public abstract static class AbstractedNonexistentArrayClassSerializer extends Serializer { protected final String className; private final int dims; diff --git a/java/fory-core/src/main/java/org/apache/fory/serializer/ForwardSerializer.java b/java/fory-core/src/main/java/org/apache/fory/serializer/ForwardSerializer.java index 2df75a6f03..930da46305 100644 --- a/java/fory-core/src/main/java/org/apache/fory/serializer/ForwardSerializer.java +++ b/java/fory-core/src/main/java/org/apache/fory/serializer/ForwardSerializer.java @@ -28,7 +28,6 @@ import org.apache.fory.Fory; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; import org.apache.fory.util.LoaderBinding; import org.apache.fory.util.LoaderBinding.StagingType; @@ -89,7 +88,7 @@ protected Object deserialize(T serializer, long address, int size) { } protected Object deserialize(T serializer, ByteBuffer byteBuffer) { - return deserialize(serializer, MemoryUtils.wrap(byteBuffer)); + return deserialize(serializer, MemoryBuffer.wrap(byteBuffer)); } protected Object deserialize(T serializer, MemoryBuffer buffer) { @@ -105,7 +104,7 @@ protected Object copy(T serializer, Object obj) { public static class DefaultForyProxy extends SerializerProxy { private final ThreadLocal bufferLocal = - ThreadLocal.withInitial(() -> MemoryUtils.buffer(32)); + ThreadLocal.withInitial(() -> MemoryBuffer.buffer(32)); /** Override this method to register custom serializers. */ @Override diff --git a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java index ce936d7405..f5f6ce0dad 100644 --- a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java +++ b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java @@ -202,25 +202,32 @@ public T xread(MemoryBuffer buffer) { } } - private static final ToIntFunction GET_CODER; - private static final Function GET_VALUE; - - static { - GET_VALUE = (Function) makeGetterFunction(StringBuilder.class.getSuperclass(), "getValue"); - ToIntFunction getCoder; - try { - Method getCoderMethod = StringBuilder.class.getSuperclass().getDeclaredMethod("getCoder"); - getCoder = (ToIntFunction) makeGetterFunction(getCoderMethod, int.class); - } catch (NoSuchMethodException e) { - getCoder = null; - } - GET_CODER = getCoder; - } - public abstract static class AbstractStringBuilderSerializer extends Serializer { protected final StringSerializer stringSerializer; + private static final ToIntFunction GET_CODER; + private static final Function GET_VALUE; + + private static final boolean RESTRICTED_STRING_BUILDER = Platform.IS_ANDROID; + + static { + if (RESTRICTED_STRING_BUILDER) { + GET_CODER = null; + GET_VALUE = null; + } else { + GET_VALUE = (Function) makeGetterFunction(StringBuilder.class.getSuperclass(), "getValue"); + ToIntFunction getCoder; + try { + Method getCoderMethod = StringBuilder.class.getSuperclass().getDeclaredMethod("getCoder"); + getCoder = (ToIntFunction) makeGetterFunction(getCoderMethod, int.class); + } catch (NoSuchMethodException e) { + getCoder = null; + } + GET_CODER = getCoder; + } + } + public AbstractStringBuilderSerializer(Fory fory, Class type) { super(fory, type); stringSerializer = new StringSerializer(fory); @@ -233,6 +240,12 @@ public void xwrite(MemoryBuffer buffer, T value) { @Override public void write(MemoryBuffer buffer, T value) { + if (RESTRICTED_STRING_BUILDER) { + // Restricted StringBuilder doesn't have getCoder method, so we use + // the StringSerializer to write the string. + stringSerializer.writeString(buffer, value.toString()); + return; + } if (GET_CODER != null) { int coder = GET_CODER.applyAsInt(value); byte[] v = (byte[]) GET_VALUE.apply(value); diff --git a/java/fory-core/src/main/java/org/apache/fory/serializer/StringSerializer.java b/java/fory-core/src/main/java/org/apache/fory/serializer/StringSerializer.java index f755f270b1..04692fe2d0 100644 --- a/java/fory-core/src/main/java/org/apache/fory/serializer/StringSerializer.java +++ b/java/fory-core/src/main/java/org/apache/fory/serializer/StringSerializer.java @@ -29,12 +29,14 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Field; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.function.BiFunction; import java.util.function.Function; import org.apache.fory.Fory; import org.apache.fory.annotation.CodegenInvoke; +import org.apache.fory.annotation.NotForAndroid; import org.apache.fory.codegen.Expression; import org.apache.fory.codegen.Expression.Invoke; import org.apache.fory.codegen.Expression.StaticInvoke; @@ -42,6 +44,7 @@ import org.apache.fory.memory.MemoryBuffer; import org.apache.fory.memory.Platform; import org.apache.fory.reflect.ReflectionUtils; +import org.apache.fory.type.Types; import org.apache.fory.util.MathUtils; import org.apache.fory.util.Preconditions; import org.apache.fory.util.StringEncodingUtils; @@ -66,44 +69,56 @@ public final class StringSerializer extends ImmutableSerializer { private static final Byte UTF16_BOXED = UTF16; private static final byte UTF8 = 2; private static final int DEFAULT_BUFFER_SIZE = 1024; + private static final boolean RESTRICTED_STRING = Platform.IS_ANDROID; // Make offset compatible with graalvm native image. private static final long STRING_VALUE_FIELD_OFFSET; private static class Offset { // Make offset compatible with graalvm native image. - private static final long STRING_CODER_FIELD_OFFSET; + private static final long + STRING_CODER_FIELD_OFFSET; // android can't access this field through reflection static { - try { - STRING_CODER_FIELD_OFFSET = - Platform.objectFieldOffset(String.class.getDeclaredField("coder")); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); + if (RESTRICTED_STRING) { + STRING_CODER_FIELD_OFFSET = -1; + } else { + try { + STRING_CODER_FIELD_OFFSET = + Platform.objectFieldOffset(String.class.getDeclaredField("coder")); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } } } } static { - Field valueField = ReflectionUtils.getFieldNullable(String.class, "value"); - // Java8 string - STRING_VALUE_FIELD_IS_CHARS = valueField != null && valueField.getType() == char[].class; - // Java11 string - STRING_VALUE_FIELD_IS_BYTES = valueField != null && valueField.getType() == byte[].class; - try { - // Make offset compatible with graalvm native image. - STRING_VALUE_FIELD_OFFSET = - Platform.objectFieldOffset(String.class.getDeclaredField("value")); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); + if (Platform.IS_ANDROID) { + STRING_VALUE_FIELD_IS_CHARS = false; + STRING_VALUE_FIELD_IS_BYTES = true; + STRING_VALUE_FIELD_OFFSET = -1; + } else { + Field valueField = ReflectionUtils.getFieldNullable(String.class, "value"); + // Java8 string + STRING_VALUE_FIELD_IS_CHARS = valueField != null && valueField.getType() == char[].class; + // Java11 string + STRING_VALUE_FIELD_IS_BYTES = valueField != null && valueField.getType() == byte[].class; + try { + // Make offset compatible with graalvm native image. + STRING_VALUE_FIELD_OFFSET = + Platform.objectFieldOffset(String.class.getDeclaredField("value")); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + // String length field for android. + Preconditions.checkArgument( + ReflectionUtils.getFieldNullable(String.class, "count") == null, + "Current jdk not supported"); + Preconditions.checkArgument( + ReflectionUtils.getFieldNullable(String.class, "offset") == null, + "Current jdk not supported"); } - // String length field for android. - Preconditions.checkArgument( - ReflectionUtils.getFieldNullable(String.class, "count") == null, - "Current jdk not supported"); - Preconditions.checkArgument( - ReflectionUtils.getFieldNullable(String.class, "offset") == null, - "Current jdk not supported"); } private final boolean compressString; @@ -223,8 +238,10 @@ public String readCompressedBytesString(MemoryBuffer buffer) { if (coder == UTF8) { byte[] data; if (writeNumUtf16BytesForUtf8Encoding) { + System.out.println("Read compressed bytes string with UTF8 encoding, optimized for perf"); data = readBytesUTF8PerfOptimized(buffer, numBytes); } else { + System.out.println("Read compressed bytes string with UTF8 encoding"); data = readBytesUTF8(buffer, numBytes); } return newBytesStringZeroCopy(UTF16, data); @@ -257,6 +274,26 @@ public String readCompressedCharsString(MemoryBuffer buffer) { // Invoked by fory JIT public void writeJavaString(MemoryBuffer buffer, String value) { + // TODO: haven't implemented a fast path in android version yet. + if (RESTRICTED_STRING) { + byte coder; + byte[] bytes; + if (StringUtils.isLatin1(value)) { + // 如果是 Latin-1 字符串,我们就用 ISO_8859_1 编码来获取单字节数组。 + // 这与 String 内部的 LATIN1 存储方式兼容。 + coder = LATIN1; // 0 for LATIN1 + bytes = value.getBytes(StandardCharsets.ISO_8859_1); + } else { + // 如果包含更复杂的字符,我们就用 UTF-16LE 编码。 + // 这与 String 内部的 UTF16 存储方式兼容。 + // 注意:Java 内部是 UTF-16,通常是 Little Endian。如果您的接收端有特定要求,请调整。 + coder = UTF16; // 1 for UTF16 + bytes = value.getBytes(StandardCharsets.UTF_16LE); + } + // 调用您原来的核心序列化方法,这个方法不需要任何改动。 + writeBytesString(buffer, coder, bytes); + return; + } if (STRING_VALUE_FIELD_IS_BYTES) { if (compressString) { writeCompressedBytesString(buffer, value); @@ -293,14 +330,29 @@ public String readJavaString(MemoryBuffer buffer) { @CodegenInvoke public void writeCompressedBytesString(MemoryBuffer buffer, String value) { - final byte[] bytes = (byte[]) Platform.getObject(value, STRING_VALUE_FIELD_OFFSET); - final byte coder = Platform.getByte(value, Offset.STRING_CODER_FIELD_OFFSET); + final byte[] bytes; + final byte coder; + if (RESTRICTED_STRING) { + if (StringUtils.isLatin1(value)) { + coder = LATIN1; // 0 for LATIN1 + bytes = value.getBytes(StandardCharsets.ISO_8859_1); + } else { + coder = UTF16; // 1 for UTF16 + bytes = value.getBytes(StandardCharsets.UTF_16LE); + } + } else { + bytes = (byte[]) Platform.getObject(value, STRING_VALUE_FIELD_OFFSET); + coder = Platform.getByte(value, Offset.STRING_CODER_FIELD_OFFSET); + } if (coder == LATIN1 || bestCoder(bytes) == UTF16) { + System.out.println("Write compressed bytes string with LATIN1 or UTF16 encoding"); writeBytesString(buffer, coder, bytes); } else { if (writeNumUtf16BytesForUtf8Encoding) { + System.out.println("Write compressed bytes string with UTF8 encoding, optimized for perf"); writeBytesUTF8PerfOptimized(buffer, bytes); } else { + System.out.println("Write compressed bytes string with UTF8 encoding"); writeBytesUTF8(buffer, bytes); } } @@ -308,6 +360,7 @@ public void writeCompressedBytesString(MemoryBuffer buffer, String value) { @CodegenInvoke public void writeCompressedCharsString(MemoryBuffer buffer, String value) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte final char[] chars = (char[]) Platform.getObject(value, STRING_VALUE_FIELD_OFFSET); final byte coder = bestCoder(chars); if (coder == LATIN1) { @@ -325,8 +378,20 @@ public void writeCompressedCharsString(MemoryBuffer buffer, String value) { @CodegenInvoke public static void writeBytesString(MemoryBuffer buffer, String value) { - byte[] bytes = (byte[]) Platform.getObject(value, STRING_VALUE_FIELD_OFFSET); - byte coder = Platform.getByte(value, Offset.STRING_CODER_FIELD_OFFSET); + final byte[] bytes; + final byte coder; + if (RESTRICTED_STRING) { + if (StringUtils.isLatin1(value)) { + coder = LATIN1; // 0 for LATIN1 + bytes = value.getBytes(StandardCharsets.ISO_8859_1); + } else { + coder = UTF16; // 1 for UTF16 + bytes = value.getBytes(StandardCharsets.UTF_16LE); + } + } else { + bytes = (byte[]) Platform.getObject(value, STRING_VALUE_FIELD_OFFSET); + coder = Platform.getByte(value, Offset.STRING_CODER_FIELD_OFFSET); + } writeBytesString(buffer, coder, bytes); } @@ -337,27 +402,14 @@ public static void writeBytesString(MemoryBuffer buffer, byte coder, byte[] byte // The `ensure` ensure next operations are safe without bound checks, // and inner heap buffer doesn't change. buffer.ensure(writerIndex + 9 + bytesLen); // 1 byte coder + varint max 8 bytes - final byte[] targetArray = buffer.getHeapMemory(); - if (targetArray != null) { - // Some JDK11 Unsafe.copyMemory will `copyMemoryChecks`, and - // jvm doesn't eliminate well in some jdk. - final int targetIndex = buffer._unsafeHeapWriterIndex(); - int arrIndex = targetIndex; - arrIndex += LittleEndian.putVarUint36Small(targetArray, arrIndex, header); - writerIndex += arrIndex - targetIndex; - System.arraycopy(bytes, 0, targetArray, arrIndex, bytesLen); - } else { - writerIndex += buffer._unsafePutVarUint36Small(writerIndex, header); - long offHeapAddress = buffer.getUnsafeAddress(); - Platform.copyMemory( - bytes, Platform.BYTE_ARRAY_OFFSET, null, offHeapAddress + writerIndex, bytesLen); - } - writerIndex += bytesLen; - buffer._unsafeWriterIndex(writerIndex); + int consumedLen = buffer._unsafePutVarUint36Small(writerIndex, header); + buffer._increaseWriterIndexUnsafe(consumedLen); + buffer.writeArray(bytes, 0, bytesLen, Types.JavaArray.BYTE, false); } @CodegenInvoke public void writeCharsString(MemoryBuffer buffer, String value) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte final char[] chars = (char[]) Platform.getObject(value, STRING_VALUE_FIELD_OFFSET); if (StringUtils.isLatin(chars)) { writeCharsLatin1(buffer, chars, chars.length); @@ -440,10 +492,12 @@ public byte[] readBytesUnCompressedUTF16(MemoryBuffer buffer, int numBytes) { } public char[] readCharsUTF16(MemoryBuffer buffer, int numBytes) { - char[] chars = new char[numBytes >> 1]; + int elementNum = numBytes >> 1; + assert (numBytes & 1) == 0; + char[] chars = new char[elementNum]; if (Platform.IS_LITTLE_ENDIAN) { // FIXME JDK11 utf16 string uses little-endian order. - buffer.readChars(chars, Platform.CHAR_ARRAY_OFFSET, numBytes); + buffer.readTo(chars, 0, elementNum, Types.JavaArray.CHAR); } else { buffer.checkReadableBytes(numBytes); final byte[] targetArray = buffer.getHeapMemory(); @@ -512,15 +566,16 @@ public String readCharsUTF8PerfOptimized(MemoryBuffer buffer, int numBytes) { } public void writeCharsLatin1(MemoryBuffer buffer, char[] chars, int numBytes) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte int writerIndex = buffer.writerIndex(); long header = ((long) numBytes << 2) | LATIN1; buffer.ensure(writerIndex + 5 + numBytes); byte[] targetArray = buffer.getHeapMemory(); if (targetArray != null) { - final int targetIndex = buffer._unsafeHeapWriterIndex(); - int arrIndex = targetIndex; - arrIndex += LittleEndian.putVarUint36Small(targetArray, arrIndex, header); - writerIndex += arrIndex - targetIndex; + int arrIndex = buffer._unsafeHeapWriterIndex(); + int varLen = LittleEndian.putVarUint36Small(targetArray, arrIndex, header); + arrIndex += varLen; + writerIndex += varLen; for (int i = 0; i < numBytes; i++) { targetArray[arrIndex + i] = (byte) chars[i]; } @@ -537,27 +592,25 @@ public void writeCharsLatin1(MemoryBuffer buffer, char[] chars, int numBytes) { } public void writeCharsUTF16(MemoryBuffer buffer, char[] chars, int numChars) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte int numBytes = MathUtils.doubleExact(numChars); int writerIndex = buffer.writerIndex(); long header = ((long) numBytes << 2) | UTF16; buffer.ensure(writerIndex + 5 + numBytes); final byte[] targetArray = buffer.getHeapMemory(); if (targetArray != null) { - final int targetIndex = buffer._unsafeHeapWriterIndex(); - int arrIndex = targetIndex; - arrIndex += LittleEndian.putVarUint36Small(targetArray, arrIndex, header); - writerIndex += arrIndex - targetIndex + numBytes; + int targetIndex = buffer._unsafeHeapWriterIndex(); + int varIntLen = LittleEndian.putVarUint36Small(targetArray, targetIndex, header); + writerIndex += varIntLen; + targetIndex += varIntLen; if (Platform.IS_LITTLE_ENDIAN) { // FIXME JDK11 utf16 string uses little-endian order. - Platform.UNSAFE.copyMemory( - chars, - Platform.CHAR_ARRAY_OFFSET, - targetArray, - Platform.BYTE_ARRAY_OFFSET + arrIndex, - numBytes); + buffer.coverMemoryWithArray( + writerIndex, chars, 0, numBytes / 2, Types.JavaArray.CHAR, false); } else { - heapWriteCharsUTF16BE(chars, arrIndex, numBytes, targetArray); + heapWriteCharsUTF16BE(chars, targetIndex, numBytes, targetArray); } + writerIndex += numBytes; } else { writerIndex += buffer._unsafePutVarUint36Small(writerIndex, header); writerIndex = offHeapWriteCharsUTF16(buffer, chars, writerIndex, numBytes); @@ -566,6 +619,7 @@ public void writeCharsUTF16(MemoryBuffer buffer, char[] chars, int numChars) { } public void writeCharsUTF8(MemoryBuffer buffer, char[] chars) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte int estimateMaxBytes = chars.length * 3; // num bytes of utf8 should be smaller than utf16, otherwise we should // utf16 instead. @@ -608,6 +662,7 @@ public void writeCharsUTF8(MemoryBuffer buffer, char[] chars) { } public void writeCharsUTF8PerfOptimized(MemoryBuffer buffer, char[] chars) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte int estimateMaxBytes = chars.length * 3; int numBytes = MathUtils.doubleExact(chars.length); // noinspection Duplicates @@ -730,6 +785,21 @@ public static String newCharsStringZeroCopy(char[] data) { // coder param first to make inline call args // `(buffer.readByte(), buffer.readBytesWithSizeEmbedded())` work. public static String newBytesStringZeroCopy(byte coder, byte[] data) { + if (RESTRICTED_STRING) { + Charset charset; + if (coder == LATIN1) { // LATIN1 + charset = StandardCharsets.ISO_8859_1; + } else if (coder == UTF16) { // UTF16 + charset = StandardCharsets.UTF_16LE; // 注意:Java 内部是 UTF-16,通常是 Little Endian。 + } else if (coder == UTF8) { // UTF8 + charset = StandardCharsets.UTF_8; + } else { + throw new IllegalArgumentException("Unknown coder type: " + coder); + } + // 使用标准的、会产生拷贝的构造函数。 + // 这是在 Android 上唯一保证有效的方法。 + return new String(data, charset); + } if (coder == LATIN1) { // 700% faster than unsafe put field in java11, only 10% slower than `new String(str)` for // string length 230. @@ -753,7 +823,11 @@ public static String newBytesStringZeroCopy(byte coder, byte[] data) { } } + @NotForAndroid private static BiFunction getCharsStringZeroCopyCtr() { + if (RESTRICTED_STRING) { + return null; // Android version not implemented yet. + } if (!STRING_VALUE_FIELD_IS_CHARS) { return null; } @@ -777,7 +851,11 @@ private static BiFunction getCharsStringZeroCopyCtr() { } } + @NotForAndroid private static BiFunction getBytesStringZeroCopyCtr() { + if (RESTRICTED_STRING) { + return null; // Android version not implemented yet. + } if (!STRING_VALUE_FIELD_IS_BYTES) { return null; } @@ -803,7 +881,11 @@ private static BiFunction getBytesStringZeroCopyCtr() { } } + @NotForAndroid private static Function getLatinBytesStringZeroCopyCtr() { + if (RESTRICTED_STRING) { + return null; // Android version not implemented yet. + } if (!STRING_VALUE_FIELD_IS_BYTES) { return null; } @@ -825,15 +907,18 @@ private static Function getLatinBytesStringZeroCopyCtr() { } private static MethodHandle getJavaStringZeroCopyCtrHandle() { + assert !RESTRICTED_STRING; Preconditions.checkArgument(Platform.JAVA_VERSION >= 8); if (STRING_LOOK_UP == null) { return null; } try { if (STRING_VALUE_FIELD_IS_CHARS) { + // android can't get this return STRING_LOOK_UP.findConstructor( String.class, MethodType.methodType(void.class, char[].class, boolean.class)); } else { + // android can't get this return STRING_LOOK_UP.findConstructor( String.class, MethodType.methodType(void.class, byte[].class, byte.class)); } @@ -844,6 +929,7 @@ private static MethodHandle getJavaStringZeroCopyCtrHandle() { private static void heapWriteCharsUTF16BE( char[] chars, int arrIndex, int numBytes, byte[] targetArray) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte // Write to heap memory then copy is 250% faster than unsafe write to direct memory. int charIndex = 0; for (int i = arrIndex, end = i + numBytes; i < end; i += 2) { @@ -855,6 +941,7 @@ private static void heapWriteCharsUTF16BE( private int offHeapWriteCharsUTF16( MemoryBuffer buffer, char[] chars, int writerIndex, int numBytes) { + assert !RESTRICTED_STRING; // Android version not implemented yet. 我们限制了Android只用byte byte[] tmpArray = getByteArray(numBytes); int charIndex = 0; for (int i = 0; i < numBytes; i += 2) { diff --git a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java index c77d01b569..fa1c0120b4 100644 --- a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java +++ b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java @@ -57,6 +57,7 @@ import org.apache.fory.serializer.ReplaceResolveSerializer; import org.apache.fory.serializer.Serializer; import org.apache.fory.serializer.Serializers; +import org.apache.fory.type.Types; import org.apache.fory.util.Preconditions; import org.apache.fory.util.unsafe._JDKAccess; @@ -634,8 +635,7 @@ public BitSetSerializer(Fory fory, Class type) { @Override public void write(MemoryBuffer buffer, BitSet set) { long[] values = set.toLongArray(); - buffer.writePrimitiveArrayWithSize( - values, Platform.LONG_ARRAY_OFFSET, Math.multiplyExact(values.length, 8)); + buffer.writeArrayWithSize(values, 0, values.length, Types.JavaArray.LONG); } @Override @@ -820,7 +820,9 @@ public static void registerDefaultSerializers(Fory fory) { CopyOnWriteArrayList.class, new CopyOnWriteArrayListSerializer(fory, CopyOnWriteArrayList.class)); final Class setFromMapClass = Collections.newSetFromMap(new HashMap<>()).getClass(); - resolver.registerSerializer(setFromMapClass, new SetFromMapSerializer(fory, setFromMapClass)); + if (!Platform.IS_ANDROID) { + resolver.registerSerializer(setFromMapClass, new SetFromMapSerializer(fory, setFromMapClass)); + } resolver.registerSerializer( ConcurrentHashMap.KeySetView.class, new ConcurrentHashMapKeySetViewSerializer(fory, ConcurrentHashMap.KeySetView.class)); diff --git a/java/fory-core/src/main/java/org/apache/fory/type/Types.java b/java/fory-core/src/main/java/org/apache/fory/type/Types.java index 3a2a287d6d..110de4a1f9 100644 --- a/java/fory-core/src/main/java/org/apache/fory/type/Types.java +++ b/java/fory-core/src/main/java/org/apache/fory/type/Types.java @@ -22,6 +22,8 @@ import static org.apache.fory.collection.Collections.ofHashMap; import java.util.Map; +import org.apache.fory.Fory; +import org.apache.fory.memory.Platform; import org.apache.fory.util.Preconditions; public class Types { @@ -164,6 +166,27 @@ public class Types { public static final int UNKNOWN = 63; + public enum JavaArray { + BOOL(Platform.BOOLEAN_ARRAY_OFFSET, 1, Types.BOOL_ARRAY), + BYTE(Platform.BYTE_ARRAY_OFFSET, 1, Types.BINARY), + CHAR(Platform.CHAR_ARRAY_OFFSET, 2, Fory.NOT_SUPPORT_XLANG), + SHORT(Platform.SHORT_ARRAY_OFFSET, 2, Types.INT16_ARRAY), + INT(Platform.INT_ARRAY_OFFSET, 4, Types.INT32_ARRAY), + LONG(Platform.LONG_ARRAY_OFFSET, 8, Types.INT64_ARRAY), + FLOAT(Platform.FLOAT_ARRAY_OFFSET, 4, Types.FLOAT32_ARRAY), + DOUBLE(Platform.DOUBLE_ARRAY_OFFSET, 8, Types.FLOAT64_ARRAY); + + public final int arrayMemOffset; + public final int bytesPerEle; + public final int typeCode; + + JavaArray(int arrayMemOffset, int bytesPerEle, int typeCode) { + this.arrayMemOffset = arrayMemOffset; + this.bytesPerEle = bytesPerEle; + this.typeCode = typeCode; + } + } + // Helper methods public static boolean isStructType(int value) { return value == STRUCT diff --git a/java/fory-core/src/main/java/org/apache/fory/util/StringEncodingUtils.java b/java/fory-core/src/main/java/org/apache/fory/util/StringEncodingUtils.java index 4d121aa2ee..2af9e86855 100644 --- a/java/fory-core/src/main/java/org/apache/fory/util/StringEncodingUtils.java +++ b/java/fory-core/src/main/java/org/apache/fory/util/StringEncodingUtils.java @@ -118,7 +118,7 @@ public static int convertUTF16ToUTF8(byte[] src, byte[] dst, int dp) { /** * A fast convert algorithm to convert an utf8 encoded byte array into an utf16 encoded byte - * array. + * array.(aware: utf16le) */ public static int convertUTF8ToUTF16(byte[] src, int offset, int len, byte[] dst) { final int end = offset + len; diff --git a/java/fory-core/src/main/java/org/apache/fory/util/StringUtils.java b/java/fory-core/src/main/java/org/apache/fory/util/StringUtils.java index 394f429b34..b7612af37f 100644 --- a/java/fory-core/src/main/java/org/apache/fory/util/StringUtils.java +++ b/java/fory-core/src/main/java/org/apache/fory/util/StringUtils.java @@ -303,4 +303,15 @@ public static boolean isLatin(char[] chars, int start) { } return isLatin; } + + // need to be optimized + public static boolean isLatin1(String s) { + for (int i = 0; i < s.length(); i++) { + // char 是16位的,Latin-1 字符的码点都在 255 (0xFF) 以内 + if (s.charAt(i) > 0xFF) { + return false; + } + } + return true; + } } diff --git a/java/fory-core/src/main/java/org/apache/fory/util/unsafe/_JDKAccess.java b/java/fory-core/src/main/java/org/apache/fory/util/unsafe/_JDKAccess.java index 1a5765fb3f..0911c47494 100644 --- a/java/fory-core/src/main/java/org/apache/fory/util/unsafe/_JDKAccess.java +++ b/java/fory-core/src/main/java/org/apache/fory/util/unsafe/_JDKAccess.java @@ -55,18 +55,25 @@ public class _JDKAccess { // CHECKSTYLE.ON:TypeName public static final int JAVA_VERSION; public static final boolean IS_OPEN_J9; + public static final boolean IS_ANDROID; public static final Unsafe UNSAFE; public static final Class _INNER_UNSAFE_CLASS; public static final Object _INNER_UNSAFE; static { - String property = System.getProperty("java.specification.version"); - if (property.startsWith("1.")) { - property = property.substring(2); + IS_ANDROID = checkIsAndroid(); + if (IS_ANDROID) { + IS_OPEN_J9 = false; + JAVA_VERSION = 8; // TODO: 只是一个尝试,之后一定要改 + } else { + String property = System.getProperty("java.specification.version"); + if (property.startsWith("1.")) { + property = property.substring(2); + } + String jmvName = System.getProperty("java.vm.name", ""); + IS_OPEN_J9 = jmvName.contains("OpenJ9"); + JAVA_VERSION = Integer.parseInt(property); } - String jmvName = System.getProperty("java.vm.name", ""); - IS_OPEN_J9 = jmvName.contains("OpenJ9"); - JAVA_VERSION = Integer.parseInt(property); Unsafe unsafe; try { Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); @@ -77,6 +84,8 @@ public class _JDKAccess { } UNSAFE = unsafe; if (JAVA_VERSION >= 11) { + // TODO: make sure android can't reach here + assert !IS_ANDROID; try { Field theInternalUnsafeField = Unsafe.class.getDeclaredField("theInternalUnsafe"); theInternalUnsafeField.setAccessible(true); @@ -91,6 +100,16 @@ public class _JDKAccess { } } + private static boolean checkIsAndroid() { + try { + // try to load a class that only android has + Class.forName("android.os.Build"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + private static final ClassValue lookupCache = new ClassValue() { @Override diff --git a/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java b/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java index 1d887425e5..6e18bf0946 100644 --- a/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/CrossLanguageTest.java @@ -60,7 +60,6 @@ import org.apache.fory.logging.Logger; import org.apache.fory.logging.LoggerFactory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.serializer.ArraySerializersTest; import org.apache.fory.serializer.BufferObject; import org.apache.fory.serializer.EnumSerializerTest; @@ -114,7 +113,7 @@ public static A create() { @Test public void testBuffer() throws IOException { - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); buffer.writeBoolean(true); buffer.writeByte(Byte.MAX_VALUE); buffer.writeInt16(Short.MAX_VALUE); @@ -136,7 +135,7 @@ public void testBuffer() throws IOException { "test_buffer", dataFile.toAbsolutePath().toString()); Assert.assertTrue(executeCommand(command, 30)); - buffer = MemoryUtils.wrap(Files.readAllBytes(dataFile)); + buffer = MemoryBuffer.wrap(Files.readAllBytes(dataFile)); Assert.assertTrue(buffer.readBoolean()); Assert.assertEquals(buffer.readByte(), Byte.MAX_VALUE); Assert.assertEquals(buffer.readInt16(), Short.MAX_VALUE); @@ -150,7 +149,7 @@ public void testBuffer() throws IOException { @Test public void testMurmurHash3() throws IOException { - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); byte[] hash1 = Hashing.murmur3_128(47).hashBytes(new byte[] {1, 2, 8}).asBytes(); buffer.writeBytes(hash1); byte[] hash2 = @@ -229,7 +228,7 @@ public void testCrossLanguageSerializer() throws Exception { .withRefTracking(true) .requireClassRegistration(false) .build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); fory.serialize(buffer, true); fory.serialize(buffer, false); fory.serialize(buffer, -1); @@ -309,7 +308,7 @@ public void testCrossLanguageSerializer() throws Exception { "test_cross_language_serializer", dataFile.toAbsolutePath().toString()); Assert.assertTrue(executeCommand(command, 30)); - MemoryBuffer buffer2 = MemoryUtils.wrap(Files.readAllBytes(dataFile)); + MemoryBuffer buffer2 = MemoryBuffer.wrap(Files.readAllBytes(dataFile)); function.accept(buffer2, true); } @@ -407,7 +406,7 @@ public void testCrossLanguageReference() throws Exception { list.add(map); map.put("k1", map); map.put("k2", list); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); fory.serialize(buffer, list); Consumer function = @@ -432,7 +431,7 @@ public void testCrossLanguageReference() throws Exception { "test_cross_language_reference", dataFile.toAbsolutePath().toString()); Assert.assertTrue(executeCommand(command, 30)); - MemoryBuffer buffer2 = MemoryUtils.wrap(Files.readAllBytes(dataFile)); + MemoryBuffer buffer2 = MemoryBuffer.wrap(Files.readAllBytes(dataFile)); function.accept(buffer2); } @@ -670,8 +669,8 @@ public void testOutOfBandBuffer() throws Exception { outOfBandDataFile.toAbsolutePath().toString()); Assert.assertTrue(executeCommand(command, 30)); - MemoryBuffer inBandBuffer = MemoryUtils.wrap(Files.readAllBytes(intBandDataFile)); - outOfBandBuffer = MemoryUtils.wrap(Files.readAllBytes(outOfBandDataFile)); + MemoryBuffer inBandBuffer = MemoryBuffer.wrap(Files.readAllBytes(intBandDataFile)); + outOfBandBuffer = MemoryBuffer.wrap(Files.readAllBytes(outOfBandDataFile)); int numBuffers = outOfBandBuffer.readInt32(); buffers = new ArrayList<>(); for (int i = 0; i < numBuffers; i++) { diff --git a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java index 335cc9720e..081200b2dc 100644 --- a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java @@ -62,7 +62,6 @@ import org.apache.fory.exception.ForyException; import org.apache.fory.exception.InsecureException; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; import org.apache.fory.resolver.MetaContext; import org.apache.fory.serializer.ArraySerializersTest; @@ -168,7 +167,7 @@ public void basicTest(boolean referenceTracking) { public void testSerializationToBuffer(Language language) { Fory fory1 = Fory.builder().withLanguage(language).requireClassRegistration(false).build(); Fory fory2 = Fory.builder().withLanguage(language).requireClassRegistration(false).build(); - MemoryBuffer buffer = MemoryUtils.buffer(64); + MemoryBuffer buffer = MemoryBuffer.buffer(64); assertSerializationToBuffer(fory1, fory2, buffer); } @@ -176,7 +175,7 @@ public void testSerializationToBuffer(Language language) { public void testSerializationSlicedBuffer(Language language) { Fory fory1 = Fory.builder().withLanguage(language).requireClassRegistration(false).build(); Fory fory2 = Fory.builder().withLanguage(language).requireClassRegistration(false).build(); - MemoryBuffer buffer0 = MemoryUtils.buffer(64); + MemoryBuffer buffer0 = MemoryBuffer.buffer(64); buffer0.writeInt64(-1); buffer0.writeInt64(-1); buffer0.readInt64(); @@ -520,7 +519,7 @@ public void testSerializeJavaObject() { fory.deserializeJavaObjectAndClass(fory.serializeJavaObjectAndClass(beanA)), beanA); assertEquals( fory.deserializeJavaObjectAndClass( - MemoryBuffer.fromByteArray(fory.serializeJavaObjectAndClass(beanA))), + MemoryBuffer.wrap(fory.serializeJavaObjectAndClass(beanA))), beanA); } diff --git a/java/fory-core/src/test/java/org/apache/fory/StreamTest.java b/java/fory-core/src/test/java/org/apache/fory/StreamTest.java index b57ad362f2..2aa5c6297a 100644 --- a/java/fory-core/src/test/java/org/apache/fory/StreamTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/StreamTest.java @@ -84,7 +84,7 @@ public synchronized int read(byte[] b, int off, int len) { return 1; } }); - MemoryBuffer buffer = MemoryBuffer.fromByteArray(bytes, 0, 0, stream); + MemoryBuffer buffer = new MemoryBuffer(bytes, 0, 0, stream); for (int i = 0; i < 10; i++) { assertEquals(buffer.readByte(), i); assertEquals(buffer.readChar(), i); @@ -164,7 +164,7 @@ public void testOutputStream() throws IOException { bas.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(bas.toByteArray()); ForyInputStream stream = of(bis); - MemoryBuffer buf = MemoryBuffer.fromByteArray(bas.toByteArray()); + MemoryBuffer buf = MemoryBuffer.wrap(bas.toByteArray()); Object newObj = fory.deserialize(stream); assertEquals(newObj, beanA); newObj = fory.deserialize(buf); @@ -178,7 +178,7 @@ public void testOutputStream() throws IOException { // test reader buffer grow bis = new ByteArrayInputStream(bas.toByteArray()); stream = of(bis); - buf = MemoryBuffer.fromByteArray(bas.toByteArray()); + buf = MemoryBuffer.wrap(bas.toByteArray()); newObj = fory.deserialize(stream); assertEquals(newObj, beanA); newObj = fory.deserialize(buf); @@ -215,7 +215,7 @@ public synchronized int read(byte[] b, int off, int len) throws IOException { // test reader buffer grow bis = new ByteArrayInputStream(bas.toByteArray()); stream = of(bis); - MemoryBuffer buf = MemoryBuffer.fromByteArray(bas.toByteArray()); + MemoryBuffer buf = MemoryBuffer.wrap(bas.toByteArray()); newObj = fory.deserialize(stream); assertEquals(newObj, beanA); newObj = fory.deserialize(buf); @@ -238,7 +238,7 @@ public void testJavaOutputStream() throws IOException { bas.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(bas.toByteArray()); ForyInputStream stream = of(bis); - MemoryBuffer buf = MemoryBuffer.fromByteArray(bas.toByteArray()); + MemoryBuffer buf = MemoryBuffer.wrap(bas.toByteArray()); Object newObj = fory.deserializeJavaObject(stream, BeanA.class); assertEquals(newObj, beanA); newObj = fory.deserializeJavaObject(buf, BeanA.class); @@ -255,7 +255,7 @@ public void testJavaOutputStream() throws IOException { bas.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(bas.toByteArray()); ForyInputStream stream = of(bis); - MemoryBuffer buf = MemoryBuffer.fromByteArray(bas.toByteArray()); + MemoryBuffer buf = MemoryBuffer.wrap(bas.toByteArray()); Object newObj = fory.deserializeJavaObjectAndClass(stream); assertEquals(newObj, beanA); newObj = fory.deserializeJavaObjectAndClass(buf); @@ -269,7 +269,7 @@ public void testJavaOutputStream() throws IOException { // test reader buffer grow bis = new ByteArrayInputStream(bas.toByteArray()); stream = of(bis); - buf = MemoryBuffer.fromByteArray(bas.toByteArray()); + buf = MemoryBuffer.wrap(bas.toByteArray()); newObj = fory.deserializeJavaObjectAndClass(stream); assertEquals(newObj, beanA); newObj = fory.deserializeJavaObjectAndClass(buf); diff --git a/java/fory-core/src/test/java/org/apache/fory/builder/CodecUtilsTest.java b/java/fory-core/src/test/java/org/apache/fory/builder/CodecUtilsTest.java index 540b4d611c..6909663e82 100644 --- a/java/fory-core/src/test/java/org/apache/fory/builder/CodecUtilsTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/builder/CodecUtilsTest.java @@ -24,7 +24,6 @@ import org.apache.fory.Fory; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.test.bean.BeanA; import org.testng.annotations.Test; @@ -45,11 +44,11 @@ public void loadOrGenObjectCodecClass() throws Exception { .asSubclass(Generated.GeneratedSerializer.class) .getConstructor(Fory.class, Class.class) .newInstance(fory, BeanA.class); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); BeanA beanA = BeanA.createBeanA(2); serializer.write(buffer, beanA); byte[] bytes = buffer.getBytes(0, buffer.writerIndex()); - Object obj = serializer.read(MemoryUtils.wrap(bytes)); + Object obj = serializer.read(MemoryBuffer.wrap(bytes)); assertEquals(obj, beanA); } } diff --git a/java/fory-core/src/test/java/org/apache/fory/io/BlockedStreamUtilsTest.java b/java/fory-core/src/test/java/org/apache/fory/io/BlockedStreamUtilsTest.java index f75a017d3d..5652e5d0d2 100644 --- a/java/fory-core/src/test/java/org/apache/fory/io/BlockedStreamUtilsTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/io/BlockedStreamUtilsTest.java @@ -51,7 +51,7 @@ public void testDeserializeChannel() { BlockedStreamUtils.serialize(fory, stream, foo); BlockedStreamUtils.serializeJavaObject(fory, stream, foo); try (MemoryBufferReadableChannel channel = - new MemoryBufferReadableChannel(MemoryBuffer.fromByteArray(stream.toByteArray()))) { + new MemoryBufferReadableChannel(MemoryBuffer.wrap(stream.toByteArray()))) { assertEquals(BlockedStreamUtils.deserialize(fory, channel), foo); assertEquals(BlockedStreamUtils.deserializeJavaObject(fory, channel, Foo.class), foo); } diff --git a/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectInputTest.java b/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectInputTest.java index bd750c8cdd..df5f5693ce 100644 --- a/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectInputTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectInputTest.java @@ -26,7 +26,6 @@ import org.apache.fory.Fory; import org.apache.fory.ForyTestBase; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.annotations.Test; public class MemoryBufferObjectInputTest extends ForyTestBase { @@ -34,7 +33,7 @@ public class MemoryBufferObjectInputTest extends ForyTestBase { @Test(dataProvider = "compressNumber") public void testForyObjectInput(boolean compressNumber) throws IOException { Fory fory = Fory.builder().withNumberCompressed(compressNumber).build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); buffer.writeByte(1); if (compressNumber) { buffer.writeVarInt32(2); diff --git a/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectOutputTest.java b/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectOutputTest.java index 86645ddfa7..5ad709bd32 100644 --- a/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectOutputTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/io/MemoryBufferObjectOutputTest.java @@ -25,7 +25,6 @@ import java.io.IOException; import org.apache.fory.Fory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.annotations.Test; public class MemoryBufferObjectOutputTest { @@ -33,7 +32,7 @@ public class MemoryBufferObjectOutputTest { @Test public void testForyObjectOutput() throws IOException { Fory fory = Fory.builder().build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); try (MemoryBufferObjectOutput output = new MemoryBufferObjectOutput(fory, buffer)) { output.writeByte(1); output.writeInt(2); diff --git a/java/fory-core/src/test/java/org/apache/fory/memory/BitUtilsTest.java b/java/fory-core/src/test/java/org/apache/fory/memory/BitUtilsTest.java index 5e5e16217c..9cb7918b10 100644 --- a/java/fory-core/src/test/java/org/apache/fory/memory/BitUtilsTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/memory/BitUtilsTest.java @@ -30,7 +30,7 @@ public class BitUtilsTest { @Test public void anyUnSet() { int valueCount = 10; - MemoryBuffer buffer = MemoryUtils.buffer(valueCount); + MemoryBuffer buffer = MemoryBuffer.buffer(valueCount); int i = 0; BitUtils.set(buffer, 0, i++); BitUtils.set(buffer, 0, i++); @@ -49,7 +49,7 @@ public void anyUnSet() { @Test public void getNullCount() { int valueCount = 14; - MemoryBuffer buffer = MemoryUtils.buffer(valueCount); + MemoryBuffer buffer = MemoryBuffer.buffer(valueCount); buffer.putByte(0, (byte) 0b11000000); assertEquals(BitUtils.getNullCount(buffer, 0, 8), 6); } @@ -57,7 +57,7 @@ public void getNullCount() { @Test public void testSetAll() { int valueCount = 10; - MemoryBuffer buffer = MemoryUtils.buffer(8); + MemoryBuffer buffer = MemoryBuffer.buffer(8); BitUtils.setAll(buffer, 0, valueCount); assertEquals(BitUtils.getNullCount(buffer, 0, valueCount), 0); assertEquals("ff03000000000000", StringUtils.encodeHexString(buffer.getRemainingBytes())); diff --git a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java index 2a57bb13c3..d6c46f00fe 100644 --- a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java @@ -24,6 +24,7 @@ import java.nio.ByteBuffer; import java.util.Random; +import org.apache.fory.type.Types; import org.testng.Assert; import org.testng.annotations.Test; @@ -31,7 +32,7 @@ public class MemoryBufferTest { @Test public void testBufferPut() { - MemoryBuffer buffer = MemoryUtils.buffer(16); + MemoryBuffer buffer = MemoryBuffer.buffer(16); buffer.putByte(0, (byte) 10); assertEquals(buffer.getByte(0), (byte) 10); buffer.putChar(0, 'a'); @@ -50,7 +51,7 @@ public void testBufferPut() { @Test public void testBufferWrite() { - MemoryBuffer buffer = MemoryUtils.buffer(8); + MemoryBuffer buffer = MemoryBuffer.buffer(8); buffer.writeBoolean(true); buffer.writeByte(Byte.MIN_VALUE); buffer.writeChar('a'); @@ -77,7 +78,7 @@ public void testBufferWrite() { @Test public void testBufferUnsafeWrite() { { - MemoryBuffer buffer = MemoryUtils.buffer(1024); + MemoryBuffer buffer = MemoryBuffer.buffer(1024); byte[] heapMemory = buffer.getHeapMemory(); long pos = buffer.getUnsafeAddress(); assertEquals(buffer._unsafeWriterAddress(), pos); @@ -106,7 +107,7 @@ public void testBufferUnsafeWrite() { assertEquals(buffer.getByte((int) (pos - Platform.BYTE_ARRAY_OFFSET)), Byte.MIN_VALUE); } { - MemoryBuffer buffer = MemoryUtils.buffer(1024); + MemoryBuffer buffer = MemoryBuffer.buffer(1024); int index = 0; buffer.putByte(index, Byte.MIN_VALUE); index += 1; @@ -139,13 +140,13 @@ public void testWrapBuffer() { byte[] bytes = new byte[8]; int offset = 2; bytes[offset] = 1; - MemoryBuffer buffer = MemoryUtils.wrap(bytes, offset, 2); + MemoryBuffer buffer = new MemoryBuffer(bytes, offset, 2); assertEquals(buffer.readByte(), bytes[offset]); } { byte[] bytes = new byte[8]; int offset = 2; - MemoryBuffer buffer = MemoryUtils.wrap(ByteBuffer.wrap(bytes, offset, 2)); + MemoryBuffer buffer = MemoryBuffer.wrap(ByteBuffer.wrap(bytes, offset, 2)); assertEquals(buffer.readByte(), bytes[offset]); } { @@ -153,7 +154,7 @@ public void testWrapBuffer() { int offset = 2; direct.put(offset, (byte) 1); direct.position(offset); - MemoryBuffer buffer = MemoryUtils.wrap(direct); + MemoryBuffer buffer = MemoryBuffer.wrap(direct); assertEquals(buffer.readByte(), direct.get(offset)); } } @@ -163,7 +164,7 @@ public void testSliceAsByteBuffer() { byte[] data = new byte[10]; new Random().nextBytes(data); { - MemoryBuffer buffer = MemoryUtils.wrap(data, 5, 5); + MemoryBuffer buffer = new MemoryBuffer(data, 5, 5); assertEquals(buffer.sliceAsByteBuffer(), ByteBuffer.wrap(data, 5, 5)); } { @@ -171,25 +172,35 @@ public void testSliceAsByteBuffer() { direct.put(data); direct.flip(); direct.position(5); - MemoryBuffer buffer = MemoryUtils.wrap(direct); + MemoryBuffer buffer = MemoryBuffer.wrap(direct); assertEquals(buffer.sliceAsByteBuffer(), direct); Assert.assertEquals( ByteBufferUtil.getAddress(buffer.sliceAsByteBuffer()), ByteBufferUtil.getAddress(direct) + 5); } { - long address = 0; + long address = -1; try { - address = Platform.allocateMemory(10); - ByteBuffer direct = ByteBufferUtil.wrapDirectBuffer(address, 10); - direct.put(data); - direct.flip(); - direct.position(5); - MemoryBuffer buffer = MemoryUtils.wrap(direct); - assertEquals(buffer.sliceAsByteBuffer(), direct); - assertEquals(ByteBufferUtil.getAddress(buffer.sliceAsByteBuffer()), address + 5); + ByteBuffer direct; + if (Platform.IS_ANDROID) { + direct = ByteBuffer.allocateDirect(10); + direct.put(data); + direct.flip(); + direct.position(5); + MemoryBuffer buffer = MemoryBuffer.wrap(direct); + assertEquals(buffer.sliceAsByteBuffer(), direct); + } else { + address = Platform.allocateMemory(10); + direct = ByteBufferUtil.wrapDirectBuffer(address, 10); + direct.put(data); + direct.flip(); + direct.position(5); + MemoryBuffer buffer = MemoryBuffer.wrap(direct); + assertEquals(buffer.sliceAsByteBuffer(), direct); + assertEquals(ByteBufferUtil.getAddress(buffer.sliceAsByteBuffer()), address + 5); + } } finally { - Platform.freeMemory(address); + if (address != -1) Platform.freeMemory(address); } } } @@ -207,8 +218,8 @@ public void testSliceAndGetRemainingBytes() { @Test public void testEqualTo() { - MemoryBuffer buf1 = MemoryUtils.buffer(16); - MemoryBuffer buf2 = MemoryUtils.buffer(16); + MemoryBuffer buf1 = MemoryBuffer.buffer(16); + MemoryBuffer buf2 = MemoryBuffer.buffer(16); buf1.putInt64(0, 10); buf2.putInt64(0, 10); buf1.putByte(9, (byte) 1); @@ -220,7 +231,7 @@ public void testEqualTo() { @Test public void testWritePrimitiveArrayWithSizeEmbedded() { - MemoryBuffer buf = MemoryUtils.buffer(16); + MemoryBuffer buf = MemoryBuffer.buffer(16); Random random = new Random(0); byte[] bytes = new byte[100]; random.nextBytes(bytes); @@ -228,12 +239,12 @@ public void testWritePrimitiveArrayWithSizeEmbedded() { for (int i = 0; i < chars.length; i++) { chars[i] = (char) random.nextInt(); } - buf.writePrimitiveArrayWithSize(bytes, Platform.BYTE_ARRAY_OFFSET, bytes.length); - buf.writePrimitiveArrayWithSize(chars, Platform.CHAR_ARRAY_OFFSET, chars.length * 2); + buf.writeArrayWithSize(bytes, 0, bytes.length, Types.JavaArray.BYTE); + buf.writeArrayWithSize(chars, 0, chars.length, Types.JavaArray.CHAR); assertEquals(bytes, buf.readBytesAndSize()); assertEquals(chars, buf.readChars(buf.readVarUint32())); - buf.writePrimitiveArrayAlignedSize(bytes, Platform.BYTE_ARRAY_OFFSET, bytes.length); - buf.writePrimitiveArrayAlignedSize(chars, Platform.CHAR_ARRAY_OFFSET, chars.length * 2); + buf.writeArrayAlignedSize(bytes, 0, bytes.length, Types.JavaArray.BYTE); + buf.writeArrayAlignedSize(chars, 0, chars.length, Types.JavaArray.CHAR); assertEquals(bytes, buf.readBytesWithAlignedSize()); assertEquals(chars, buf.readCharsWithAlignedSize()); } @@ -241,7 +252,7 @@ public void testWritePrimitiveArrayWithSizeEmbedded() { @Test public void testWriteVarUint32() { for (int i = 0; i < 32; i++) { - MemoryBuffer buf = MemoryUtils.buffer(8); + MemoryBuffer buf = MemoryBuffer.buffer(8); for (int j = 0; j < i; j++) { buf.writeByte((byte) 1); // make address unaligned. buf.readByte(); @@ -328,7 +339,7 @@ public void testWriteVarInt() { } private MemoryBuffer buf(int numUnaligned) { - MemoryBuffer buf = MemoryUtils.buffer(1); + MemoryBuffer buf = MemoryBuffer.buffer(1); for (int j = 0; j < numUnaligned; j++) { buf.writeByte((byte) 1); // make address unaligned. buf.readByte(); @@ -350,7 +361,7 @@ private void checkVarInt(MemoryBuffer buf, int value, int bytesWritten) { @Test public void testWriteVarInt64() { - MemoryBuffer buf = MemoryUtils.buffer(8); + MemoryBuffer buf = MemoryBuffer.buffer(8); checkVarInt64(buf, -1, 1); for (int i = 0; i < 9; i++) { for (int j = 0; j < i; j++) { @@ -422,7 +433,7 @@ private void checkVarInt64(MemoryBuffer buf, long value, int bytesWritten) { @Test public void testWriteVarUint64() { - MemoryBuffer buf = MemoryUtils.buffer(8); + MemoryBuffer buf = MemoryBuffer.buffer(8); checkVarUint64(buf, -1, 9); for (int i = 0; i < 9; i++) { for (int j = 0; j < i; j++) { @@ -490,7 +501,7 @@ private void checkVarUint64(MemoryBuffer buf, long value, int bytesWritten) { @Test public void testWriteVarUint32Aligned() { - MemoryBuffer buf = MemoryUtils.buffer(16); + MemoryBuffer buf = MemoryBuffer.buffer(16); assertEquals(buf.writeVarUint32Aligned(1), 4); assertEquals(buf.readAlignedVarUint(), 1); assertEquals(buf.writeVarUint32Aligned(1 << 5), 4); @@ -514,10 +525,10 @@ public void testWriteVarUint32Aligned() { buf.readInt16(); assertEquals(buf.readAlignedVarUint(), Integer.MAX_VALUE); for (int i = 0; i < 32; i++) { - MemoryBuffer buf1 = MemoryUtils.buffer(16); + MemoryBuffer buf1 = MemoryBuffer.buffer(16); assertAligned(i, buf1); } - MemoryBuffer buf1 = MemoryUtils.buffer(16); + MemoryBuffer buf1 = MemoryBuffer.buffer(16); for (int i = 0; i < 32; i++) { assertAligned(i, buf1); } @@ -555,7 +566,7 @@ public void testGetShortB() { @Test public void testWriteSliInt64() { - MemoryBuffer buf = MemoryUtils.buffer(8); + MemoryBuffer buf = MemoryBuffer.buffer(8); checkSliInt64(buf, -1, 4); for (int i = 0; i < 10; i++) { for (int j = 0; j < i; j++) { @@ -595,7 +606,7 @@ private void checkSliInt64(MemoryBuffer buf, long value, int bytesWritten) { @Test public void testVarUint32Small7() { - MemoryBuffer buf = MemoryUtils.buffer(1); + MemoryBuffer buf = MemoryBuffer.buffer(1); buf.writeVarUint32Small7(1); assertEquals(buf.readVarUint32Small7(), 1); assertEquals(buf.writeVarUint32Small7(127), 1); @@ -612,7 +623,7 @@ public void testVarUint32Small7() { @Test public void testVarUint36Small() { - MemoryBuffer buf = MemoryUtils.buffer(80); + MemoryBuffer buf = MemoryBuffer.buffer(80); int index = 0; { int diff = LittleEndian.putVarUint36Small(buf.getHeapMemory(), index, 10); @@ -661,7 +672,7 @@ public void testVarUint36Small() { public void testReadBytesAsInt64() { for (MemoryBuffer buffer : new MemoryBuffer[] { - MemoryUtils.buffer(16), MemoryUtils.wrap(ByteBuffer.allocateDirect(32)), + MemoryBuffer.buffer(16), MemoryBuffer.bufferDirect(32), }) { buffer.writeByte(10); buffer.writeByte(20); diff --git a/java/fory-core/src/test/java/org/apache/fory/meta/ClassDefEncoderTest.java b/java/fory-core/src/test/java/org/apache/fory/meta/ClassDefEncoderTest.java index eec203fd96..c05d384ca6 100644 --- a/java/fory-core/src/test/java/org/apache/fory/meta/ClassDefEncoderTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/meta/ClassDefEncoderTest.java @@ -58,8 +58,7 @@ public void testBigMetaEncoding() { }) { Fory fory = Fory.builder().withMetaShare(true).build(); ClassDef classDef = ClassDef.buildClassDef(fory, type); - ClassDef classDef1 = - ClassDef.readClassDef(fory, MemoryBuffer.fromByteArray(classDef.getEncoded())); + ClassDef classDef1 = ClassDef.readClassDef(fory, MemoryBuffer.wrap(classDef.getEncoded())); Assert.assertEquals(classDef1, classDef); } } @@ -75,8 +74,7 @@ public static class Foo2 extends Foo1 {} public void testEmptySubClassSerializer() { Fory fory = Fory.builder().withLanguage(Language.JAVA).requireClassRegistration(true).build(); ClassDef classDef = ClassDef.buildClassDef(fory, Foo2.class); - ClassDef classDef1 = - ClassDef.readClassDef(fory, MemoryBuffer.fromByteArray(classDef.getEncoded())); + ClassDef classDef1 = ClassDef.readClassDef(fory, MemoryBuffer.wrap(classDef.getEncoded())); Assert.assertEquals(classDef, classDef1); } @@ -88,8 +86,7 @@ public void testBigClassNameObject() { fory, TestClassLengthTestClassLengthTestClassLengthTestClassLengthTestClassLengthTestClassLengthTestClassLength .InnerClassTestLengthInnerClassTestLengthInnerClassTestLength.class); - ClassDef classDef1 = - ClassDef.readClassDef(fory, MemoryBuffer.fromByteArray(classDef.getEncoded())); + ClassDef classDef1 = ClassDef.readClassDef(fory, MemoryBuffer.wrap(classDef.getEncoded())); Assert.assertEquals(classDef1, classDef); } diff --git a/java/fory-core/src/test/java/org/apache/fory/reflect/PlatformTest.java b/java/fory-core/src/test/java/org/apache/fory/reflect/PlatformTest.java index 5befaafe76..947d0200bb 100644 --- a/java/fory-core/src/test/java/org/apache/fory/reflect/PlatformTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/reflect/PlatformTest.java @@ -101,15 +101,20 @@ private boolean arrayEquals(byte[] bytes, byte[] bytes2) { @Test public void wrapDirectBuffer() { - long address = 0; + long address = -1; try { int size = 16; - address = Platform.allocateMemory(size); - ByteBuffer buffer = ByteBufferUtil.wrapDirectBuffer(address, size); + ByteBuffer buffer; + if (Platform.IS_ANDROID) { + buffer = ByteBuffer.allocateDirect(size); + } else { + address = Platform.allocateMemory(size); + buffer = ByteBufferUtil.wrapDirectBuffer(address, size); + } buffer.putLong(0, 1); assertEquals(1, buffer.getLong(0)); } finally { - Platform.freeMemory(address); + if (address != -1) Platform.freeMemory(address); } } diff --git a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java index 1960466334..d9fc886cc3 100644 --- a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java @@ -51,7 +51,6 @@ import org.apache.fory.logging.Logger; import org.apache.fory.logging.LoggerFactory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.reflect.TypeRef; import org.apache.fory.resolver.longlongpkg.C1; import org.apache.fory.resolver.longlongpkg.C2; @@ -229,7 +228,7 @@ public void testWriteClassName() { .requireClassRegistration(false) .build(); ClassResolver classResolver = fory.getClassResolver(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); classResolver.writeClassInternal(buffer, getClass()); int writerIndex = buffer.writerIndex(); classResolver.writeClassInternal(buffer, getClass()); @@ -244,7 +243,7 @@ public void testWriteClassName() { .requireClassRegistration(false) .build(); ClassResolver classResolver = fory.getClassResolver(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); classResolver.writeClassAndUpdateCache(buffer, getClass()); classResolver.writeClassAndUpdateCache(buffer, getClass()); Assert.assertSame(classResolver.readClassInfo(buffer).getCls(), getClass()); diff --git a/java/fory-core/src/test/java/org/apache/fory/resolver/MetaStringResolverTest.java b/java/fory-core/src/test/java/org/apache/fory/resolver/MetaStringResolverTest.java index b9d393534c..9e739721c0 100644 --- a/java/fory-core/src/test/java/org/apache/fory/resolver/MetaStringResolverTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/resolver/MetaStringResolverTest.java @@ -22,9 +22,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import java.nio.ByteBuffer; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.meta.MetaString; import org.apache.fory.meta.MetaStringEncoder; import org.apache.fory.util.StringUtils; @@ -34,7 +32,7 @@ public class MetaStringResolverTest { @Test public void testWriteMetaString() { - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); String str = StringUtils.random(128, 0); MetaStringResolver stringResolver = new MetaStringResolver(); for (int i = 0; i < 128; i++) { @@ -54,7 +52,7 @@ public void testWriteMetaString() { public void testWriteSmallMetaString() { for (MemoryBuffer buffer : new MemoryBuffer[] { - MemoryUtils.buffer(32), MemoryUtils.wrap(ByteBuffer.allocateDirect(32)), + MemoryBuffer.buffer(32), MemoryBuffer.bufferDirect(32), }) { for (int i = 0; i < 32; i++) { String str = StringUtils.random(i, 0); diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/CodegenSerializerTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/CodegenSerializerTest.java index 6a274c25e2..0e99006b79 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/CodegenSerializerTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/CodegenSerializerTest.java @@ -37,7 +37,6 @@ import org.apache.fory.config.CompatibleMode; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.test.bean.Cyclic; import org.testng.Assert; import org.testng.annotations.Test; @@ -88,7 +87,7 @@ public void testSerializeCircularReference() { .withRefTracking(true) .requireClassRegistration(false) .build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); fory.serialize(buffer, cyclic); fory.deserialize(buffer); diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/DuplicateFieldsTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/DuplicateFieldsTest.java index 3dcbf219cf..6b3c05d2fe 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/DuplicateFieldsTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/DuplicateFieldsTest.java @@ -30,7 +30,6 @@ import org.apache.fory.config.ForyBuilder; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.annotations.Test; public class DuplicateFieldsTest extends ForyTestBase { @@ -64,7 +63,7 @@ public void testDuplicateFieldsNoCompatible() { .build(); { ObjectSerializer serializer = new ObjectSerializer<>(fory, C.class); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); serializer.write(buffer, c); C newC = serializer.read(buffer); assertEquals(newC.f1, c.f1); @@ -75,7 +74,7 @@ public void testDuplicateFieldsNoCompatible() { Serializer serializer = Serializers.newSerializer( fory, C.class, CodecUtils.loadOrGenObjectCodecClass(C.class, fory)); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); serializer.write(buffer, c); C newC = serializer.read(buffer); assertEquals(newC.f1, c.f1); @@ -116,7 +115,7 @@ public void testDuplicateFieldsCompatible(boolean scopedMetaShare) { Fory fory = builder.build(); { CompatibleSerializer serializer = new CompatibleSerializer<>(fory, C.class); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); serializer.write(buffer, c); C newC = serializer.read(buffer); assertEquals(newC.f1, c.f1); @@ -127,7 +126,7 @@ public void testDuplicateFieldsCompatible(boolean scopedMetaShare) { Serializer serializer = Serializers.newSerializer( fory, C.class, CodecUtils.loadOrGenCompatibleCodecClass(C.class, fory)); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); serializer.write(buffer, c); C newC = serializer.read(buffer); assertEquals(newC.f1, c.f1); diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectSerializerTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectSerializerTest.java index 15cc87d4f7..a369a16ca6 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectSerializerTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectSerializerTest.java @@ -27,7 +27,6 @@ import org.apache.fory.ForyTestBase; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.test.bean.Cyclic; import org.apache.fory.util.Preconditions; import org.testng.Assert; @@ -51,7 +50,7 @@ public String foo(String s) { .requireClassRegistration(false) .build(); ObjectSerializer serializer = new ObjectSerializer(fory, Foo.class); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); Foo foo = new Foo(); serializer.write(buffer, foo); Object obj = serializer.read(buffer); @@ -95,7 +94,7 @@ public String foo(String s) { .requireClassRegistration(false) .build(); ObjectSerializer serializer = new ObjectSerializer(fory, foo.getClass()); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); serializer.write(buffer, foo); Object obj = serializer.read(buffer); assertEquals(foo.foo("str"), ((Foo) obj).foo("str")); @@ -131,7 +130,7 @@ public void testSerializeCircularReference() { .withRefTracking(true) .requireClassRegistration(false) .build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); ObjectSerializer serializer = new ObjectSerializer<>(fory, Cyclic.class); fory.getRefResolver().writeRefOrNull(buffer, cyclic); @@ -172,7 +171,7 @@ public void testSerialization() { .withRefTracking(false) .requireClassRegistration(false) .build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); ObjectSerializer serializer = new ObjectSerializer<>(fory, A.class); A a = new A(); serializer.write(buffer, a); diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/StringSerializerTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/StringSerializerTest.java index 436180ebe3..e32fdcdab4 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/StringSerializerTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/StringSerializerTest.java @@ -23,7 +23,6 @@ import static org.testng.Assert.assertEquals; import java.lang.reflect.Field; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; @@ -35,9 +34,9 @@ import org.apache.fory.collection.Tuple2; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; import org.apache.fory.reflect.ReflectionUtils; +import org.apache.fory.type.Types; import org.apache.fory.util.MathUtils; import org.apache.fory.util.StringUtils; import org.testng.Assert; @@ -139,13 +138,13 @@ static void writeJDK8String(MemoryBuffer buffer, String value) { final char[] chars = (char[]) Platform.getObject(value, ReflectionUtils.getFieldOffset(String.class, "value")); int numBytes = MathUtils.doubleExact(value.length()); - buffer.writePrimitiveArrayWithSize(chars, Platform.CHAR_ARRAY_OFFSET, numBytes); + buffer.writeArrayWithSize(chars, 0, value.length(), Types.JavaArray.CHAR); } @Test public void testJavaStringSimple() { Fory fory = Fory.builder().withStringCompressed(true).requireClassRegistration(false).build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); StringSerializer serializer = new StringSerializer(fory); { String str = "str"; @@ -211,7 +210,7 @@ public void testJavaString(boolean stringCompress, boolean writeNumUtf16BytesFor .withWriteNumUtf16BytesForUtf8Encoding(writeNumUtf16BytesForUtf8Encoding) .requireClassRegistration(false) .build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); StringSerializer serializer = new StringSerializer(fory); String longStr = new String(new char[50]).replace("\0", "abc"); @@ -237,7 +236,7 @@ public void testJavaStringOffHeap( .withWriteNumUtf16BytesForUtf8Encoding(writeNumUtf16BytesForUtf8Encoding) .requireClassRegistration(false) .build(); - MemoryBuffer buffer = MemoryUtils.wrap(ByteBuffer.allocateDirect(1024)); + MemoryBuffer buffer = MemoryBuffer.bufferDirect(1024); Object o1 = "你好, Fory" + StringUtils.random(64); Object o2 = new String[] {"你好, Fory" + StringUtils.random(64), "你好, Fory" + StringUtils.random(64)}; @@ -340,7 +339,7 @@ public void testCompressJava8String() { char[] utf16StrChars = utf16Str.toCharArray(); for (MemoryBuffer buffer : new MemoryBuffer[] { - MemoryUtils.buffer(512), MemoryUtils.wrap(ByteBuffer.allocateDirect(512)), + MemoryBuffer.buffer(512), MemoryBuffer.bufferDirect(512), }) { stringSerializer.writeJavaString(buffer, utf16Str); assertEquals(stringSerializer.readJavaString(buffer), utf16Str); @@ -363,7 +362,7 @@ public void testReadUtf8String(boolean writeNumUtf16BytesForUtf8Encoding) { .build(); for (MemoryBuffer buffer : new MemoryBuffer[] { - MemoryUtils.buffer(32), MemoryUtils.wrap(ByteBuffer.allocateDirect(2048)) + MemoryBuffer.buffer(32), MemoryBuffer.bufferDirect(2048), }) { StringSerializer serializer = new StringSerializer(fory); serializer.write(buffer, "abc你好"); diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java index d2fcc0a1aa..dc5ba81eb4 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/CollectionSerializersTest.java @@ -64,7 +64,6 @@ import org.apache.fory.ForyTestBase; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.reflect.TypeRef; import org.apache.fory.serializer.collection.CollectionSerializers.JDKCompatibleCollectionSerializer; import org.apache.fory.test.bean.Cyclic; @@ -786,7 +785,7 @@ public void testJavaSerialization() { .withRefTracking(false) .requireClassRegistration(false) .build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); JDKCompatibleCollectionSerializer javaSerializer = new JDKCompatibleCollectionSerializer(fory, setClass); javaSerializer.write(buffer, set); diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/SynchronizedSerializersTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/SynchronizedSerializersTest.java index 2215ce4640..45fc973dc7 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/SynchronizedSerializersTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/SynchronizedSerializersTest.java @@ -39,7 +39,6 @@ import org.apache.fory.ForyTestBase; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; import org.apache.fory.reflect.ReflectionUtils; import org.apache.fory.serializer.Serializer; @@ -58,7 +57,7 @@ public class SynchronizedSerializersTest extends ForyTestBase { @Test public void testWrite() throws Exception { Fory fory = Fory.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); Object[] values = new Object[] { Collections.synchronizedCollection(Collections.singletonList("abc")), diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/UnmodifiableSerializersTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/UnmodifiableSerializersTest.java index 0275c5a9e3..e50c2accf7 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/UnmodifiableSerializersTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/UnmodifiableSerializersTest.java @@ -45,7 +45,6 @@ import org.apache.fory.ForyTestBase; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; import org.apache.fory.reflect.ReflectionUtils; import org.apache.fory.serializer.Serializer; @@ -66,7 +65,7 @@ public class UnmodifiableSerializersTest extends ForyTestBase { @Test public void testWrite() throws Exception { Fory fory = Fory.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); Object[] values = new Object[] { Collections.unmodifiableCollection(Collections.singletonList("abc")), diff --git a/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java b/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java index 18845507b8..44484e2c0e 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java @@ -47,7 +47,6 @@ import org.apache.fory.logging.Logger; import org.apache.fory.logging.LoggerFactory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.reflect.TypeRef; import org.apache.fory.type.TypeResolutionContext; import org.apache.fory.type.TypeUtils; @@ -90,7 +89,7 @@ public T fromRow(BinaryRow row) { @Override public BinaryRow toRow(T obj) { - writer.setBuffer(MemoryUtils.buffer(initialBufferSize)); + writer.setBuffer(MemoryBuffer.buffer(initialBufferSize)); writer.reset(); return encoder.toRow(obj); } @@ -155,7 +154,7 @@ public static RowEncoder bean(Class beanClass, BinaryRowWriter writer, long schemaHash = DataTypes.computeSchemaHash(schema); return new RowEncoder() { - private final MemoryBuffer buffer = MemoryUtils.buffer(16); + private final MemoryBuffer buffer = MemoryBuffer.buffer(16); @Override public Schema schema() { @@ -196,7 +195,7 @@ public T decode(MemoryBuffer buffer, int size) { @Override public T decode(byte[] bytes) { - return decode(MemoryUtils.wrap(bytes), bytes.length); + return decode(MemoryBuffer.wrap(bytes), bytes.length); } @Override @@ -405,7 +404,7 @@ public T decode(MemoryBuffer buffer, int size) { @Override public T decode(byte[] bytes) { - return decode(MemoryUtils.wrap(bytes), bytes.length); + return decode(MemoryBuffer.wrap(bytes), bytes.length); } @Override @@ -547,7 +546,7 @@ public T decode(MemoryBuffer buffer, int size) { @Override public T decode(byte[] bytes) { - return decode(MemoryUtils.wrap(bytes), bytes.length); + return decode(MemoryBuffer.wrap(bytes), bytes.length); } @Override diff --git a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryArray.java b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryArray.java index 076f2a1b40..ea8cd00711 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryArray.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryArray.java @@ -33,8 +33,8 @@ import org.apache.fory.format.type.DataTypes; import org.apache.fory.memory.BitUtils; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; +import org.apache.fory.type.Types; import org.apache.fory.util.Preconditions; /** @@ -156,49 +156,56 @@ public void setDecimal(int ordinal, BigDecimal value) { public boolean[] toBooleanArray() { boolean[] values = new boolean[numElements]; - buffer.copyToUnsafe(elementOffset, values, Platform.BOOLEAN_ARRAY_OFFSET, numElements); + // buffer.copyToUnsafe(elementOffset, values, Platform.BOOLEAN_ARRAY_OFFSET, numElements); + buffer.copyTo(elementOffset, values, 0, numElements, Types.JavaArray.BOOL, false); return values; } public byte[] toByteArray() { byte[] values = new byte[numElements]; - buffer.copyToUnsafe(elementOffset, values, Platform.BYTE_ARRAY_OFFSET, numElements); + // buffer.copyToUnsafe(elementOffset, values, Platform.BYTE_ARRAY_OFFSET, numElements); + buffer.copyTo(elementOffset, values, 0, numElements, Types.JavaArray.BYTE, false); return values; } public short[] toShortArray() { short[] values = new short[numElements]; - buffer.copyToUnsafe(elementOffset, values, Platform.SHORT_ARRAY_OFFSET, numElements * 2); + // buffer.copyToUnsafe(elementOffset, values, Platform.SHORT_ARRAY_OFFSET, numElements * 2); + buffer.copyTo(elementOffset, values, 0, numElements, Types.JavaArray.SHORT, false); return values; } public int[] toIntArray() { int[] values = new int[numElements]; - buffer.copyToUnsafe(elementOffset, values, Platform.INT_ARRAY_OFFSET, numElements * 4); + // buffer.copyToUnsafe(elementOffset, values, Platform.INT_ARRAY_OFFSET, numElements * 4); + buffer.copyTo(elementOffset, values, 0, numElements, Types.JavaArray.INT, false); return values; } public long[] toLongArray() { long[] values = new long[numElements]; - buffer.copyToUnsafe(elementOffset, values, Platform.LONG_ARRAY_OFFSET, numElements * 8); + // buffer.copyToUnsafe(elementOffset, values, Platform.LONG_ARRAY_OFFSET, numElements * 8); + buffer.copyTo(elementOffset, values, 0, numElements, Types.JavaArray.LONG, false); return values; } public float[] toFloatArray() { float[] values = new float[numElements]; - buffer.copyToUnsafe(elementOffset, values, Platform.FLOAT_ARRAY_OFFSET, numElements * 4); + // buffer.copyToUnsafe(elementOffset, values, Platform.FLOAT_ARRAY_OFFSET, numElements * 4); + buffer.copyTo(elementOffset, values, 0, numElements, Types.JavaArray.FLOAT, false); return values; } public double[] toDoubleArray() { double[] values = new double[numElements]; - buffer.copyToUnsafe(elementOffset, values, Platform.DOUBLE_ARRAY_OFFSET, numElements * 8); + // buffer.copyToUnsafe(elementOffset, values, Platform.DOUBLE_ARRAY_OFFSET, numElements * 8); + buffer.copyTo(elementOffset, values, 0, numElements, Types.JavaArray.DOUBLE, false); return values; } @Override public ArrayData copy() { - MemoryBuffer copyBuf = MemoryUtils.buffer(sizeInBytes); + MemoryBuffer copyBuf = MemoryBuffer.buffer(sizeInBytes); buffer.copyTo(baseOffset, copyBuf, 0, sizeInBytes); BinaryArray arrayCopy = new BinaryArray(field); arrayCopy.pointTo(copyBuf, 0, sizeInBytes); @@ -235,7 +242,7 @@ private static BinaryArray fromPrimitiveArray(Object arr, int offset, int length Platform.copyMemory( arr, offset, data, Platform.BYTE_ARRAY_OFFSET + headerInBytes, valueRegionInBytes); - MemoryBuffer memoryBuffer = MemoryUtils.wrap(data); + MemoryBuffer memoryBuffer = MemoryBuffer.wrap(data); result.pointTo(memoryBuffer, 0, (int) totalSize); return result; } diff --git a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryMap.java b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryMap.java index 4ff14f4122..aae2757ef0 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryMap.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryMap.java @@ -24,8 +24,7 @@ import org.apache.fory.format.row.MapData; import org.apache.fory.format.type.DataTypes; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; -import org.apache.fory.memory.Platform; +import org.apache.fory.type.Types; /** * An BinaryMap implementation of Map which is backed by two BinaryArray./ForyObjectOutput @@ -109,15 +108,16 @@ public BinaryArray valueArray() { @Override public MapData copy() { - MemoryBuffer copyBuf = MemoryUtils.buffer(sizeInBytes); + MemoryBuffer copyBuf = MemoryBuffer.buffer(sizeInBytes); buf.copyTo(baseOffset, copyBuf, 0, sizeInBytes); BinaryMap mapCopy = new BinaryMap(field); mapCopy.pointTo(copyBuf, 0, sizeInBytes); return mapCopy; } - public void writeToMemory(Object target, long targetOffset) { - buf.copyToUnsafe(baseOffset, target, targetOffset, sizeInBytes); + public void writeToBytes(byte[] target, int targetOffset) { + // buf.copyToUnsafe(baseOffset, target, targetOffset, sizeInBytes); + buf.copyTo(baseOffset, target, targetOffset, sizeInBytes, Types.JavaArray.BYTE, false); } public void writeTo(ByteBuffer buffer) { @@ -125,7 +125,7 @@ public void writeTo(ByteBuffer buffer) { byte[] target = buffer.array(); int offset = buffer.arrayOffset(); int pos = buffer.position(); - writeToMemory(target, Platform.BYTE_ARRAY_OFFSET + offset + pos); + writeToBytes(target, offset + pos); buffer.position(pos + sizeInBytes); } diff --git a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryRow.java b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryRow.java index ad9f1384ff..07bf44d364 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryRow.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/BinaryRow.java @@ -31,7 +31,6 @@ import org.apache.fory.format.type.DataTypes; import org.apache.fory.memory.BitUtils; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.util.Preconditions; /** @@ -171,7 +170,7 @@ public BinaryMap getMap(int ordinal) { @Override public Row copy() { - MemoryBuffer copyBuf = MemoryUtils.buffer(sizeInBytes); + MemoryBuffer copyBuf = MemoryBuffer.buffer(sizeInBytes); buffer.copyTo(baseOffset, copyBuf, 0, sizeInBytes); BinaryRow copyRow = new BinaryRow(schema); copyRow.pointTo(copyBuf, 0, sizeInBytes); diff --git a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/UnsafeTrait.java b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/UnsafeTrait.java index ad7447e8b3..9f1803bbff 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/UnsafeTrait.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/UnsafeTrait.java @@ -142,7 +142,7 @@ BigDecimal getDecimal(int ordinal, ArrowType.Decimal decimalType) { } MemoryBuffer buffer = getBuffer(ordinal); ArrowBuf arrowBuf = ArrowUtils.decimalArrowBuf(); - buffer.copyToUnsafe(0, null, arrowBuf.memoryAddress(), DECIMAL_BYTE_LENGTH); + buffer.copyToDirectUnsafe(0, arrowBuf.memoryAddress(), DECIMAL_BYTE_LENGTH); BigDecimal decimal = DecimalUtility.getBigDecimalFromArrowBuf( arrowBuf, 0, decimalType.getScale(), DECIMAL_BYTE_LENGTH); diff --git a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryArrayWriter.java b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryArrayWriter.java index 8627121724..adce6f3eec 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryArrayWriter.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryArrayWriter.java @@ -33,8 +33,7 @@ import org.apache.fory.format.row.binary.BinaryArray; import org.apache.fory.format.type.DataTypes; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; -import org.apache.fory.memory.Platform; +import org.apache.fory.type.Types.JavaArray; /** * Writer for binary array. See {@link BinaryArray} @@ -56,7 +55,7 @@ public class BinaryArrayWriter extends BinaryWriter { /** Must call reset before using writer constructed by this constructor. */ public BinaryArrayWriter(Field field) { // buffer size can grow - this(field, MemoryUtils.buffer(64)); + this(field, MemoryBuffer.buffer(64)); super.startIndex = 0; } @@ -162,7 +161,8 @@ public void write(int ordinal, BigDecimal value) { writeDecimal(ordinal, value, (ArrowType.Decimal) field.getChildren().get(0).getType()); } - private void fromPrimitiveArray(Object arr, int offset, int numElements, Field type) { + private void fromPrimitiveArray( + Object arr, int offset, int numElements, Field type, JavaArray eleType) { if (DataTypes.getTypeId(type.getChildren().get(0).getType()) != DataTypes.getTypeId(this.field.getChildren().get(0).getType())) { String msg = @@ -171,38 +171,36 @@ private void fromPrimitiveArray(Object arr, int offset, int numElements, Field t type.getChildren().get(0).getType(), this.field.getChildren().get(0).getType()); throw new IllegalArgumentException(msg); } - buffer.copyFromUnsafe( - startIndex + headerInBytes, arr, offset, numElements * (long) elementSize); - // no need to increasewriterIndex, because reset has already increased writerIndex + buffer.copyTo(startIndex + headerInBytes, arr, offset, numElements, eleType, false); + // no need to increase writerIndex, because reset has already increased writerIndex } public void fromPrimitiveArray(byte[] arr) { - fromPrimitiveArray(arr, Platform.BYTE_ARRAY_OFFSET, arr.length, PRIMITIVE_BYTE_ARRAY_FIELD); + fromPrimitiveArray(arr, 0, arr.length, PRIMITIVE_BYTE_ARRAY_FIELD, JavaArray.BYTE); } public void fromPrimitiveArray(boolean[] arr) { - fromPrimitiveArray( - arr, Platform.BOOLEAN_ARRAY_OFFSET, arr.length, PRIMITIVE_BOOLEAN_ARRAY_FIELD); + fromPrimitiveArray(arr, 0, arr.length, PRIMITIVE_BOOLEAN_ARRAY_FIELD, JavaArray.BOOL); } public void fromPrimitiveArray(short[] arr) { - fromPrimitiveArray(arr, Platform.SHORT_ARRAY_OFFSET, arr.length, PRIMITIVE_SHORT_ARRAY_FIELD); + fromPrimitiveArray(arr, 0, arr.length, PRIMITIVE_SHORT_ARRAY_FIELD, JavaArray.SHORT); } public void fromPrimitiveArray(int[] arr) { - fromPrimitiveArray(arr, Platform.INT_ARRAY_OFFSET, arr.length, PRIMITIVE_INT_ARRAY_FIELD); + fromPrimitiveArray(arr, 0, arr.length, PRIMITIVE_INT_ARRAY_FIELD, JavaArray.INT); } public void fromPrimitiveArray(long[] arr) { - fromPrimitiveArray(arr, Platform.LONG_ARRAY_OFFSET, arr.length, PRIMITIVE_LONG_ARRAY_FIELD); + fromPrimitiveArray(arr, 0, arr.length, PRIMITIVE_LONG_ARRAY_FIELD, JavaArray.LONG); } public void fromPrimitiveArray(float[] arr) { - fromPrimitiveArray(arr, Platform.FLOAT_ARRAY_OFFSET, arr.length, PRIMITIVE_FLOAT_ARRAY_FIELD); + fromPrimitiveArray(arr, 0, arr.length, PRIMITIVE_FLOAT_ARRAY_FIELD, JavaArray.FLOAT); } public void fromPrimitiveArray(double[] arr) { - fromPrimitiveArray(arr, Platform.DOUBLE_ARRAY_OFFSET, arr.length, PRIMITIVE_DOUBLE_ARRAY_FIELD); + fromPrimitiveArray(arr, 0, arr.length, PRIMITIVE_DOUBLE_ARRAY_FIELD, JavaArray.DOUBLE); } public BinaryArray toArray() { diff --git a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryRowWriter.java b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryRowWriter.java index 9cbd48d05d..1a6c0609d8 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryRowWriter.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryRowWriter.java @@ -26,7 +26,6 @@ import org.apache.arrow.vector.types.pojo.Schema; import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; /** * Writer to write data into buffer using row format, see {@link BinaryRow}. @@ -44,7 +43,7 @@ public class BinaryRowWriter extends BinaryWriter { private final int fixedSize; public BinaryRowWriter(Schema schema) { - super(MemoryUtils.buffer(schema.getFields().size() * 32), 0); + super(MemoryBuffer.buffer(schema.getFields().size() * 32), 0); super.startIndex = 0; this.schema = schema; this.headerInBytes = calculateBitmapWidthInBytes(schema.getFields().size()); @@ -138,7 +137,7 @@ public BinaryRow getRow() { public BinaryRow copyToRow() { BinaryRow row = new BinaryRow(schema); int size = size(); - MemoryBuffer buffer = MemoryUtils.buffer(size); + MemoryBuffer buffer = MemoryBuffer.buffer(size); this.buffer.copyTo(startIndex, buffer, 0, size); row.pointTo(buffer, startIndex, size); return row; diff --git a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryWriter.java b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryWriter.java index d24d547ed8..b399aa2ebc 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryWriter.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryWriter.java @@ -218,8 +218,8 @@ protected final void writeDecimal(int ordinal, BigDecimal value, ArrowType.Decim ArrowBuf arrowBuf = ArrowUtils.buffer(DecimalUtils.DECIMAL_BYTE_LENGTH); DecimalUtility.writeBigDecimalToArrowBuf( value, arrowBuf, 0, DecimalUtils.DECIMAL_BYTE_LENGTH); - buffer.copyFromUnsafe( - writerIndex(), null, arrowBuf.memoryAddress(), DecimalUtils.DECIMAL_BYTE_LENGTH); + buffer.copyFromDirectUnsafe( + writerIndex(), arrowBuf.memoryAddress(), DecimalUtils.DECIMAL_BYTE_LENGTH); arrowBuf.getReferenceManager().release(); setOffsetAndSize(ordinal, writerIndex(), DecimalUtils.DECIMAL_BYTE_LENGTH); increaseWriterIndex(DecimalUtils.DECIMAL_BYTE_LENGTH); diff --git a/java/fory-format/src/main/java/org/apache/fory/format/vectorized/ArrowSerializers.java b/java/fory-format/src/main/java/org/apache/fory/format/vectorized/ArrowSerializers.java index 7f5828f7bc..374cc02dbe 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/vectorized/ArrowSerializers.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/vectorized/ArrowSerializers.java @@ -35,7 +35,6 @@ import org.apache.fory.io.MemoryBufferWritableChannel; import org.apache.fory.io.MockWritableChannel; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; import org.apache.fory.serializer.BufferObject; import org.apache.fory.serializer.Serializers.CrossLanguageCompatibleSerializer; @@ -118,7 +117,7 @@ private static void write(VectorSchemaRoot root, WritableByteChannel byteChannel @Override public MemoryBuffer toBuffer() { - MemoryBuffer buffer = MemoryUtils.buffer(totalBytes); + MemoryBuffer buffer = MemoryBuffer.buffer(totalBytes); write(root, new MemoryBufferWritableChannel(buffer)); return buffer.slice(0, buffer.writerIndex()); } @@ -159,7 +158,7 @@ private static void write(ArrowTable table, WritableByteChannel byteChannel) { @Override public MemoryBuffer toBuffer() { - MemoryBuffer buffer = MemoryUtils.buffer(totalBytes); + MemoryBuffer buffer = MemoryBuffer.buffer(totalBytes); write(table, new MemoryBufferWritableChannel(buffer)); return buffer.slice(0, buffer.writerIndex()); } diff --git a/java/fory-format/src/test/java/org/apache/fory/format/CrossLanguageTest.java b/java/fory-format/src/test/java/org/apache/fory/format/CrossLanguageTest.java index 8fe07212ea..7f0363c101 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/CrossLanguageTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/CrossLanguageTest.java @@ -65,7 +65,6 @@ import org.apache.fory.logging.Logger; import org.apache.fory.logging.LoggerFactory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.serializer.BufferObject; import org.apache.fory.test.TestUtils; import org.testng.Assert; @@ -138,7 +137,7 @@ public void testSerializationWithoutSchema() throws IOException { Assert.assertTrue(executeCommand(command, 30)); } - MemoryBuffer buffer = MemoryUtils.wrap(Files.readAllBytes(dataFile)); + MemoryBuffer buffer = MemoryBuffer.wrap(Files.readAllBytes(dataFile)); BinaryRow newRow = new BinaryRow(encoder.schema()); newRow.pointTo(buffer, 0, buffer.size()); Assert.assertEquals(foo, encoder.fromRow(newRow)); @@ -167,7 +166,7 @@ public void testSerializationWithSchema() throws IOException { Assert.assertTrue(executeCommand(command, 30)); } - MemoryBuffer buffer = MemoryUtils.wrap(Files.readAllBytes(dataFile)); + MemoryBuffer buffer = MemoryBuffer.wrap(Files.readAllBytes(dataFile)); BinaryRow newRow = new BinaryRow(encoder.schema()); newRow.pointTo(buffer, 0, buffer.size()); Assert.assertEquals(foo, encoder.fromRow(newRow)); @@ -182,7 +181,7 @@ public void testRecordBatchBasic() throws IOException { VectorSchemaRoot root = new VectorSchemaRoot(Collections.singletonList(field), Collections.singletonList(vector)); Path dataFile = Files.createTempFile("foo", "data"); - MemoryBuffer buffer = MemoryUtils.buffer(128); + MemoryBuffer buffer = MemoryBuffer.buffer(128); try (ArrowStreamWriter writer = new ArrowStreamWriter(root, null, new MemoryBufferOutputStream(buffer))) { writer.start(); @@ -213,7 +212,7 @@ public void testRecordBatchWriter() throws IOException { Foo foo = Foo.create(); RowEncoder encoder = Encoders.bean(Foo.class); Path dataFile = Files.createTempFile("foo", "data"); - MemoryBuffer buffer = MemoryUtils.buffer(128); + MemoryBuffer buffer = MemoryBuffer.buffer(128); ImmutableList command = ImmutableList.of( PYTHON_EXECUTABLE, @@ -272,7 +271,7 @@ public void testWriteMultiRecordBatch() throws IOException { schemaFile.toAbsolutePath().toString(), dataFile.toAbsolutePath().toString()); { - MemoryBuffer buffer = MemoryUtils.buffer(128); + MemoryBuffer buffer = MemoryBuffer.buffer(128); buffer.writerIndex(0); DataTypes.serializeSchema(encoder.schema(), buffer); Files.write(schemaFile, buffer.getBytes(0, buffer.writerIndex())); @@ -286,7 +285,7 @@ public void testWriteMultiRecordBatch() throws IOException { arrowWriter.write(row); } ArrowRecordBatch recordBatch = arrowWriter.finishAsRecordBatch(); - MemoryBuffer buffer = MemoryUtils.buffer(128); + MemoryBuffer buffer = MemoryBuffer.buffer(128); ArrowUtils.serializeRecordBatch(recordBatch, buffer); arrowWriter.reset(); Files.write( @@ -358,7 +357,7 @@ public void testSerializeArrowInBand() throws Exception { .requireClassRegistration(false) .build(); ArrowSerializers.registerSerializers(fory); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); int size = 2000; VectorSchemaRoot root = createVectorSchemaRoot(size); fory.serialize(buffer, root); @@ -384,7 +383,7 @@ public void testSerializeArrowInBand() throws Exception { dataFile.toAbsolutePath().toString()); Assert.assertTrue(executeCommand(command, 30)); - MemoryBuffer buffer2 = MemoryUtils.wrap(Files.readAllBytes(dataFile)); + MemoryBuffer buffer2 = MemoryBuffer.wrap(Files.readAllBytes(dataFile)); assertRecordBatchEqual((VectorSchemaRoot) fory.deserialize(buffer2), root); assertTableEqual((ArrowTable) fory.deserialize(buffer2), table); } @@ -400,7 +399,7 @@ public void testSerializeArrowOutOfBand() throws Exception { .build(); ArrowSerializers.registerSerializers(fory); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); int size = 2000; VectorSchemaRoot root = createVectorSchemaRoot(size); Schema schema = root.getSchema(); @@ -429,7 +428,7 @@ public void testSerializeArrowOutOfBand() throws Exception { Files.write(intBandDataFile, buffer.getBytes(0, buffer.writerIndex())); Path outOfBandDataFile = Files.createTempFile("test_serialize_arrow_out_of_band", "out_of_band.data"); - MemoryBuffer outOfBandBuffer = MemoryUtils.buffer(32); + MemoryBuffer outOfBandBuffer = MemoryBuffer.buffer(32); outOfBandBuffer.writeInt32(bufferObjects.get(0).totalBytes()); outOfBandBuffer.writeInt32(bufferObjects.get(1).totalBytes()); bufferObjects.get(0).writeTo(outOfBandBuffer); @@ -445,8 +444,8 @@ public void testSerializeArrowOutOfBand() throws Exception { outOfBandDataFile.toAbsolutePath().toString()); Assert.assertTrue(executeCommand(command, 30)); - MemoryBuffer intBandBuffer = MemoryUtils.wrap(Files.readAllBytes(intBandDataFile)); - outOfBandBuffer = MemoryUtils.wrap(Files.readAllBytes(outOfBandDataFile)); + MemoryBuffer intBandBuffer = MemoryBuffer.wrap(Files.readAllBytes(intBandDataFile)); + outOfBandBuffer = MemoryBuffer.wrap(Files.readAllBytes(outOfBandDataFile)); int len1 = outOfBandBuffer.readInt32(); int len2 = outOfBandBuffer.readInt32(); buffers = Arrays.asList(outOfBandBuffer.slice(8, len1), outOfBandBuffer.slice(8 + len1, len2)); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/encoder/CustomCodecTest.java b/java/fory-format/src/test/java/org/apache/fory/format/encoder/CustomCodecTest.java index 33b0faa4b2..9dd1d26e26 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/encoder/CustomCodecTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/encoder/CustomCodecTest.java @@ -33,7 +33,6 @@ import org.apache.fory.format.row.binary.BinaryArray; import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.reflect.TypeRef; import org.testng.Assert; import org.testng.annotations.Test; @@ -106,7 +105,7 @@ public void testCustomTypes() { bean.f4 = new CustomByteBuf3("f4 value".getBytes(StandardCharsets.UTF_8)); final RowEncoder encoder = Encoders.bean(CustomType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final CustomType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -117,7 +116,7 @@ public void testNullFields() { final CustomType bean = new CustomType(); final RowEncoder encoder = Encoders.bean(CustomType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final CustomType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -131,7 +130,7 @@ public void testUuidFields() { bean.f3 = new TreeSet<>(Arrays.asList(new UUID(7, 8), new UUID(9, 10))); final RowEncoder encoder = Encoders.bean(UuidType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final UuidType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -163,7 +162,7 @@ public TypeRef encodedType() { static class CustomByteBufEncoder implements CustomCodec.MemoryBufferCodec { @Override public MemoryBuffer encode(final CustomByteBuf value) { - return MemoryBuffer.fromByteArray(value.buf); + return MemoryBuffer.wrap(value.buf); } @Override @@ -271,7 +270,7 @@ public void testCodecTypeInterception() { final InterceptedType bean = new InterceptedTypeImpl(42); final RowEncoder encoder = Encoders.bean(InterceptedType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final InterceptedType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1(), bean.f1() + 5); @@ -300,7 +299,7 @@ public void testNestedCodecTypeInterception() { final WrapInterceptedType bean = new WrapInterceptedTypeImpl(new InterceptedTypeImpl(42)); final RowEncoder encoder = Encoders.bean(WrapInterceptedType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final WrapInterceptedType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1().f1(), bean.f1().f1() + 5); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/encoder/EnumTest.java b/java/fory-format/src/test/java/org/apache/fory/format/encoder/EnumTest.java index 0677d67f86..88f4aed079 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/encoder/EnumTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/encoder/EnumTest.java @@ -23,7 +23,6 @@ import lombok.Data; import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.Assert; import org.testng.annotations.Test; @@ -48,7 +47,7 @@ public void testEnumPresent() { v.f2 = Optional.of(TestEnum.A); RowEncoder encoder = Encoders.bean(EnumValue.class); BinaryRow row = encoder.toRow(v); - MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); EnumValue deserializedV = encoder.fromRow(row); Assert.assertEquals(v, deserializedV); @@ -61,7 +60,7 @@ public void testEnumAbsent() { v.f2 = Optional.empty(); RowEncoder encoder = Encoders.bean(EnumValue.class); BinaryRow row = encoder.toRow(v); - MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); EnumValue deserializedV = encoder.fromRow(row); Assert.assertEquals(v, deserializedV); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/encoder/GenericTypeTest.java b/java/fory-format/src/test/java/org/apache/fory/format/encoder/GenericTypeTest.java index 6649d3d600..2551052e09 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/encoder/GenericTypeTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/encoder/GenericTypeTest.java @@ -22,7 +22,6 @@ import lombok.Data; import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.Assert; import org.testng.annotations.Test; @@ -49,7 +48,7 @@ public void testRecursiveGenericType() { bean.id.id = 42; final RowEncoder encoder = Encoders.bean(TestEntity.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final TestEntity deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java b/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java index cdd38be6cf..4bc524814a 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/encoder/ImplementInterfaceTest.java @@ -30,7 +30,6 @@ import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.format.type.DataTypes; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.reflect.TypeRef; import org.testng.Assert; import org.testng.annotations.Test; @@ -91,7 +90,7 @@ public void testInterfaceTypes() { final InterfaceType bean1 = new ImplementInterface(42, "42"); final RowEncoder encoder = Encoders.bean(InterfaceType.class); final BinaryRow row = encoder.toRow(bean1); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final InterfaceType deserializedBean = encoder.fromRow(row); assertEquals(bean1, deserializedBean); @@ -102,7 +101,7 @@ public void testNullValue() { final InterfaceType bean1 = new ImplementInterface(42, null); final RowEncoder encoder = Encoders.bean(InterfaceType.class); final BinaryRow row = encoder.toRow(bean1); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final InterfaceType deserializedBean = encoder.fromRow(row); assertEquals(deserializedBean, bean1); @@ -114,7 +113,7 @@ public void testNestedValue() { bean1.nested = new ImplementNestedType("f3"); final RowEncoder encoder = Encoders.bean(InterfaceType.class); final BinaryRow row = encoder.toRow(bean1); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final InterfaceType deserializedBean = encoder.fromRow(row); assertEquals(bean1, deserializedBean); @@ -161,7 +160,7 @@ public void testNullOptional() { final OptionalType bean1 = new OptionalTypeImpl(null); final RowEncoder encoder = Encoders.bean(OptionalType.class); final BinaryRow row = encoder.toRow(bean1); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1(), Optional.empty()); @@ -172,7 +171,7 @@ public void testPresentOptional() { final OptionalType bean1 = new OptionalTypeImpl(Optional.of("42")); final RowEncoder encoder = Encoders.bean(OptionalType.class); final BinaryRow row = encoder.toRow(bean1); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1(), Optional.of("42")); @@ -200,7 +199,7 @@ public Optional> f1() { static class IdCodec implements CustomCodec.MemoryBufferCodec> { @Override public MemoryBuffer encode(final Id value) { - return MemoryBuffer.fromByteArray(new byte[] {value.id}); + return MemoryBuffer.wrap(new byte[] {value.id}); } @Override @@ -214,7 +213,7 @@ public void testOptionalCustomType() { final OptionalCustomType bean1 = new OptionalCustomTypeImpl(); final RowEncoder encoder = Encoders.bean(OptionalCustomType.class); final BinaryRow row = encoder.toRow(bean1); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalCustomType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1().get().id, bean1.f1().get().id); @@ -259,7 +258,7 @@ public void testListTooLazy() { final ListOuter bean1 = new ListOuterImpl(Arrays.asList(new ListInnerImpl(42))); final RowEncoder encoder = Encoders.bean(ListOuter.class); final BinaryRow row = encoder.toRow(bean1); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final ListOuter deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1().get(0).f1(), 42); @@ -370,7 +369,7 @@ public void testListElementsLazy() { final RowEncoder encoder = Encoders.bean(ListLazyElemOuter.class); final BinaryRow row = encoder.toRow(bean1); ListLazyElemInner.check = true; - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final ListLazyElemOuter deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1().get(2).f1(), 42); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java b/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java index 99e1f26327..b057fa90a5 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/encoder/OptionalTest.java @@ -26,7 +26,6 @@ import lombok.Data; import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.Assert; import org.testng.annotations.Test; @@ -47,7 +46,7 @@ public void testOptionalEmpty() { bean.f2 = Optional.empty(); final RowEncoder encoder = Encoders.bean(OptionalType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -58,7 +57,7 @@ public void testOptionalNull() { final OptionalType bean = new OptionalType(); final RowEncoder encoder = Encoders.bean(OptionalType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean.f1, Optional.empty()); @@ -72,7 +71,7 @@ public void testOptionalPresent() { bean.f2 = Optional.of("Indubitably"); final RowEncoder encoder = Encoders.bean(OptionalType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -91,7 +90,7 @@ public void testIntEmpty() { bean.f1 = OptionalInt.empty(); final RowEncoder encoder = Encoders.bean(OptionalIntType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalIntType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -103,7 +102,7 @@ public void testIntPresent() { bean.f1 = OptionalInt.of(42); final RowEncoder encoder = Encoders.bean(OptionalIntType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalIntType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -122,7 +121,7 @@ public void testLongEmpty() { bean.f1 = OptionalLong.empty(); final RowEncoder encoder = Encoders.bean(OptionalLongType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalLongType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -134,7 +133,7 @@ public void testLongPresent() { bean.f1 = OptionalLong.of(42); final RowEncoder encoder = Encoders.bean(OptionalLongType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalLongType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -153,7 +152,7 @@ public void testDoubleEmpty() { bean.f1 = OptionalDouble.empty(); final RowEncoder encoder = Encoders.bean(OptionalDoubleType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalDoubleType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); @@ -165,7 +164,7 @@ public void testDoublePresent() { bean.f1 = OptionalDouble.of(42); final RowEncoder encoder = Encoders.bean(OptionalDoubleType.class); final BinaryRow row = encoder.toRow(bean); - final MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + final MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); final OptionalDoubleType deserializedBean = encoder.fromRow(row); Assert.assertEquals(deserializedBean, bean); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/encoder/RowEncoderTest.java b/java/fory-format/src/test/java/org/apache/fory/format/encoder/RowEncoderTest.java index dd6832e9a6..17d16a6c28 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/encoder/RowEncoderTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/encoder/RowEncoderTest.java @@ -30,7 +30,6 @@ import lombok.Data; import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.test.bean.BeanA; import org.apache.fory.test.bean.BeanB; import org.testng.Assert; @@ -96,7 +95,7 @@ public void testImportInnerClass() { Foo foo = new Foo(); RowEncoder encoder = Encoders.bean(Foo.class); BinaryRow row = encoder.toRow(foo); - MemoryBuffer buffer = MemoryUtils.wrap(row.toBytes()); + MemoryBuffer buffer = MemoryBuffer.wrap(row.toBytes()); row.pointTo(buffer, 0, buffer.size()); Foo deserializedFoo = encoder.fromRow(row); Assert.assertEquals(foo, deserializedFoo); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryMapTest.java b/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryMapTest.java index b11a03bc5f..6f6958551f 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryMapTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryMapTest.java @@ -27,14 +27,13 @@ import org.apache.fory.format.row.binary.writer.BinaryRowWriter; import org.apache.fory.format.type.DataTypes; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.annotations.Test; public class BinaryMapTest { @Test public void pointTo() { - MemoryBuffer buffer = MemoryUtils.buffer(1024); + MemoryBuffer buffer = MemoryBuffer.buffer(1024); int writerIndex = 8; // preserve 8 byte for numBytes BinaryArrayWriter keyArrayWriter = new BinaryArrayWriter(DataTypes.arrayField(DataTypes.utf8())); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryRowTest.java b/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryRowTest.java index a40139ddfd..0203939993 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryRowTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/row/binary/BinaryRowTest.java @@ -30,7 +30,6 @@ import org.apache.fory.logging.Logger; import org.apache.fory.logging.LoggerFactory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.memory.Platform; import org.testng.annotations.Test; @@ -40,7 +39,7 @@ public class BinaryRowTest { // test align to see whether align can bring us performance gains. @Test(enabled = false) public void testAlign() { - MemoryBuffer buf = MemoryUtils.buffer(64); + MemoryBuffer buf = MemoryBuffer.buffer(64); buf.putInt64(6, 100L); buf.putInt64(14, 100L); long nums = 1000_000_000; @@ -57,7 +56,7 @@ public void testAlign() { long duration = System.nanoTime() - t; System.out.format("non-aligned cost:\ttotal %sns %sms\n", duration, duration / 1000_000); - MemoryBuffer buf2 = MemoryUtils.buffer(64); + MemoryBuffer buf2 = MemoryBuffer.buffer(64); buf2.putInt64(8, 100L); buf2.putInt64(16, 100L); // warm diff --git a/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowSerializersTest.java b/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowSerializersTest.java index 5300ef1c8c..c3770919ef 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowSerializersTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowSerializersTest.java @@ -39,7 +39,6 @@ import org.apache.fory.io.MemoryBufferReadableChannel; import org.apache.fory.io.MemoryBufferWritableChannel; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.resolver.ClassResolver; import org.apache.fory.serializer.BufferObject; import org.testng.Assert; @@ -96,7 +95,7 @@ public void testWriteVectorSchemaRoot() throws IOException { bufferObjects.stream().map(BufferObject::toBuffer).collect(Collectors.toList()); MemoryBuffer buffer = buffers.get(0); - MemoryBuffer buffer2 = MemoryUtils.buffer(32); + MemoryBuffer buffer2 = MemoryBuffer.buffer(32); try (ArrowStreamWriter writer = new ArrowStreamWriter(root, null, new MemoryBufferWritableChannel(buffer2))) { // this will make root empty. diff --git a/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowUtilsTest.java b/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowUtilsTest.java index 48a00cc5aa..ced9cbb150 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowUtilsTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowUtilsTest.java @@ -32,7 +32,6 @@ import org.apache.arrow.vector.ipc.message.ArrowRecordBatch; import org.apache.arrow.vector.types.pojo.Field; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.testng.annotations.Test; public class ArrowUtilsTest { @@ -56,7 +55,7 @@ public void testSerializeRecordBatch() { VectorSchemaRoot vectorSchemaRoot = createVectorSchemaRoot(2); VectorUnloader unloader = new VectorUnloader(vectorSchemaRoot); ArrowRecordBatch recordBatch = unloader.getRecordBatch(); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); ArrowUtils.serializeRecordBatch(recordBatch, buffer); try (ArrowRecordBatch batch = ArrowUtils.deserializeRecordBatch(buffer)) { System.out.println("newRecordBatch " + batch); diff --git a/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowWriterTest.java b/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowWriterTest.java index 2951a91ea9..80da14ff79 100644 --- a/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowWriterTest.java +++ b/java/fory-format/src/test/java/org/apache/fory/format/vectorized/ArrowWriterTest.java @@ -26,7 +26,6 @@ import org.apache.fory.format.row.binary.BinaryRow; import org.apache.fory.format.type.TypeInference; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.test.bean.BeanA; import org.testng.annotations.Test; @@ -69,7 +68,7 @@ public void testWrite() { public void testSerializeArrowRecordBatch() { ArrowRecordBatch recordBatch = createArrowRecordBatch(); System.out.println("recordBatch serialized body size " + recordBatch.computeBodyLength()); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); ArrowUtils.serializeRecordBatch(recordBatch, buffer); System.out.println("IPC recordBatch size " + buffer.writerIndex()); ArrowRecordBatch newRecordBatch = ArrowUtils.deserializeRecordBatch(buffer); diff --git a/java/fory-testsuite/src/test/java/org/apache/fory/benchmark/SerializationBenchmark.java b/java/fory-testsuite/src/test/java/org/apache/fory/benchmark/SerializationBenchmark.java index 2d48822580..f8765f74fd 100644 --- a/java/fory-testsuite/src/test/java/org/apache/fory/benchmark/SerializationBenchmark.java +++ b/java/fory-testsuite/src/test/java/org/apache/fory/benchmark/SerializationBenchmark.java @@ -31,7 +31,6 @@ import org.apache.fory.logging.Logger; import org.apache.fory.logging.LoggerFactory; import org.apache.fory.memory.MemoryBuffer; -import org.apache.fory.memory.MemoryUtils; import org.apache.fory.test.bean.Foo; import org.nustaq.serialization.FSTConfiguration; import org.testng.annotations.BeforeTest; @@ -104,7 +103,7 @@ private void testFory(Object obj) { .requireClassRegistration(false) .build(); fory.register(obj.getClass()); - MemoryBuffer buffer = MemoryUtils.buffer(32); + MemoryBuffer buffer = MemoryBuffer.buffer(32); // warm for (int i = 0; i < iterNums; i++) { buffer.writerIndex(0);