unsafe-memcpy-for-java/native/UnsafeMemcpyImpl.h
2024-04-12 23:20:09 -07:00

185 lines
9.2 KiB
C

/*
* Copyright (c) 2024 lax1dude
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <jni.h>
#include <string.h>
#include <stdint.h>
#include "utils.h"
// =============== UNALIGNED VERSIONS ===============
#define UNSAFE_MEMCPY_IMPL(dst, src, len) memcpy((void*)(dst), (const void*)(src), (size_t)(len))
#define UNSAFE_MEMCPY_ARRAY_TO_NATIVE_IMPL(jniHandle, dstAddress, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, byteLength)\
uint64_t srcArray = (uint64_t)(*jniHandle)->GetPrimitiveArrayCritical(jniHandle, srcAddress, NULL);\
if(!srcArray) {\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstAddress, srcArray + srcOffset, byteLength);\
(*jniHandle)->ReleasePrimitiveArrayCritical(jniHandle, srcAddress, (void*)srcArray, JNI_ABORT);
#define UNSAFE_MEMCPY_BUFFER_TO_NATIVE_IMPL(jniHandle, dstAddress, srcAddress, srcOffset, byteLength)\
uint64_t srcBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, srcAddress);\
if(!srcBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstAddress, srcBuffer + srcOffset, byteLength);
#define UNSAFE_MEMCPY_NATIVE_TO_BUFFER_IMPL(jniHandle, dstAddress, dstOffset, srcAddress, byteLength)\
uint64_t dstBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, dstAddress);\
if(!dstBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstBuffer + dstOffset, srcAddress, byteLength);
#define UNSAFE_MEMCPY_BUFFER_TO_BUFFER_IMPL(jniHandle, dstAddress, dstOffset, srcAddress, srcOffset, byteLength)\
uint64_t dstBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, dstAddress);\
if(!dstBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
uint64_t srcBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, srcAddress);\
if(!srcBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstBuffer + dstOffset, srcBuffer + srcOffset, byteLength);
#define UNSAFE_MEMCPY_ARRAY_TO_BUFFER_IMPL(jniHandle, dstAddress, dstOffset, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, byteLength)\
uint64_t dstBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, dstAddress);\
if(!dstBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
uint64_t srcArray = (uint64_t)(*jniHandle)->GetPrimitiveArrayCritical(jniHandle, srcAddress, NULL);\
if(!srcArray) {\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstBuffer + dstOffset, srcArray + srcOffset, byteLength);\
(*jniHandle)->ReleasePrimitiveArrayCritical(jniHandle, srcAddress, (void*)srcArray, JNI_ABORT);
#define UNSAFE_MEMCPY_NATIVE_TO_ARRAY_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, byteLength)\
uint64_t dstArray = (uint64_t)(*jniHandle)->GetPrimitiveArrayCritical(jniHandle, dstAddress, NULL);\
if(!dstArray) {\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstArray + dstOffset, srcAddress, byteLength);\
(*jniHandle)->ReleasePrimitiveArrayCritical(jniHandle, dstAddress, (void*)dstArray, JNI_COMMIT);
#define UNSAFE_MEMCPY_BUFFER_TO_ARRAY_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, srcOffset, byteLength)\
uint64_t srcBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, srcAddress);\
if(!srcBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
uint64_t dstArray = (uint64_t)(*jniHandle)->GetPrimitiveArrayCritical(jniHandle, dstAddress, NULL);\
if(!dstArray) {\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstArray + dstOffset, srcBuffer + srcOffset, byteLength);\
(*jniHandle)->ReleasePrimitiveArrayCritical(jniHandle, dstAddress, (void*)dstArray, JNI_COMMIT);
#define UNSAFE_MEMCPY_ARRAY_TO_ARRAY_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, byteLength)\
uint64_t srcArray = (uint64_t)(*jniHandle)->GetPrimitiveArrayCritical(jniHandle, srcAddress, NULL);\
if(!srcArray) {\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
uint64_t dstArray = (uint64_t)(*jniHandle)->GetPrimitiveArrayCritical(jniHandle, dstAddress, NULL);\
if(!dstArray) {\
(*jniHandle)->ReleasePrimitiveArrayCritical(jniHandle, srcAddress, (void*)srcArray, JNI_ABORT);\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
UNSAFE_MEMCPY_IMPL(dstArray + dstOffset, srcArray + srcOffset, byteLength);\
(*jniHandle)->ReleasePrimitiveArrayCritical(jniHandle, dstAddress, (void*)dstArray, JNI_COMMIT);\
(*jniHandle)->ReleasePrimitiveArrayCritical(jniHandle, srcAddress, (void*)srcArray, JNI_ABORT);
// =============== ALIGNED SRC VERSIONS ===============
#define UNSAFE_MEMCPY_ARRAY_ALIGN_TO_NATIVE_IMPL(jniHandle, dstAddress, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, length, srcGetRegionFunction)\
(*jniHandle)->srcGetRegionFunction(jniHandle, srcAddress, srcOffset, length, (srcType*)dstAddress);
#define UNSAFE_MEMCPY_ARRAY_ALIGN_TO_BUFFER_IMPL(jniHandle, dstAddress, dstOffset, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, length, srcGetRegionFunction)\
uint64_t dstBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, dstAddress);\
if(!dstBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
(*jniHandle)->srcGetRegionFunction(jniHandle, srcAddress, srcOffset, length, (srcType*)(dstBuffer + dstOffset));
#define UNSAFE_MEMCPY_ARRAY_ALIGN_TO_ARRAY_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, length, srcGetRegionFunction)\
uint64_t dstArray = (uint64_t)(*jniHandle)->dstGetElements(jniHandle, dstAddress, NULL);\
if(!dstArray) {\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
(*jniHandle)->srcGetRegionFunction(jniHandle, srcAddress, srcOffset, length, (srcType*)(dstArray + dstOffset));\
(*jniHandle)->dstReleaseElements(jniHandle, dstAddress, (dstType*)dstArray, JNI_COMMIT);\
// =============== ALIGNED DST VERSIONS ===============
#define UNSAFE_MEMCPY_NATIVE_TO_ARRAY_ALIGN_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, length, dstSetRegionFunction)\
(*jniHandle)->dstSetRegionFunction(jniHandle, dstAddress, dstOffset, length, (const dstType*)srcAddress);
#define UNSAFE_MEMCPY_BUFFER_TO_ARRAY_ALIGN_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, srcOffset, length, dstSetRegionFunction)\
uint64_t srcBuffer = (uint64_t)(*jniHandle)->GetDirectBufferAddress(jniHandle, srcAddress);\
if(!srcBuffer) {\
unsafeThrowNotDirectBuffer(jniHandle);\
return;\
}\
(*jniHandle)->dstSetRegionFunction(jniHandle, dstAddress, dstOffset, length, (const dstType*)(srcBuffer + srcOffset));
#define UNSAFE_MEMCPY_ARRAY_TO_ARRAY_ALIGN_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, length, dstSetRegionFunction)\
uint64_t srcArray = (uint64_t)(*jniHandle)->srcGetElements(jniHandle, srcAddress, NULL);\
if(!srcArray) {\
unsafeThrowOutOfMemory(jniHandle);\
return;\
}\
(*jniHandle)->dstSetRegionFunction(jniHandle, dstAddress, dstOffset, length, (const dstType*)(srcArray + srcOffset));\
(*jniHandle)->srcReleaseElements(jniHandle, srcAddress, (void*)srcArray, JNI_ABORT);
// =============== FULLY ALIGNED VERSIONS ===============
#define UNSAFE_MEMCPY_ARRAY_ALIGN_TO_ARRAY_ALIGN_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, srcOffset, srcType, srcGetElements, srcReleaseElements, length, srcGetRegionFunction, dstSetRegionFunction)\
UNSAFE_MEMCPY_ARRAY_TO_ARRAY_ALIGN_IMPL(jniHandle, dstAddress, dstOffset, dstType, dstGetElements, dstReleaseElements, srcAddress, (srcOffset * (jsize)sizeof(srcType)), srcType, srcGetElements, srcReleaseElements, length, dstSetRegionFunction)