1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <nativehelper/JNIPlatformHelp.h>
18
19 #include <stddef.h>
20
21 #include "JniConstants.h"
22
GetBufferPosition(JNIEnv * env,jobject nioBuffer)23 static int GetBufferPosition(JNIEnv* env, jobject nioBuffer) {
24 return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_position(env));
25 }
26
GetBufferLimit(JNIEnv * env,jobject nioBuffer)27 static int GetBufferLimit(JNIEnv* env, jobject nioBuffer) {
28 return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_limit(env));
29 }
30
GetBufferElementSizeShift(JNIEnv * env,jobject nioBuffer)31 static int GetBufferElementSizeShift(JNIEnv* env, jobject nioBuffer) {
32 jclass byteBufferClass = JniConstants_NioByteBufferClass(env);
33 jclass shortBufferClass = JniConstants_NioShortBufferClass(env);
34 jclass charBufferClass = JniConstants_NioCharBufferClass(env);
35 jclass intBufferClass = JniConstants_NioIntBufferClass(env);
36 jclass floatBufferClass = JniConstants_NioFloatBufferClass(env);
37 jclass longBufferClass = JniConstants_NioLongBufferClass(env);
38 jclass doubleBufferClass = JniConstants_NioDoubleBufferClass(env);
39
40 // Check the type of the Buffer
41 if ((*env)->IsInstanceOf(env, nioBuffer, byteBufferClass)) {
42 return 0;
43 } else if ((*env)->IsInstanceOf(env, nioBuffer, shortBufferClass) ||
44 (*env)->IsInstanceOf(env, nioBuffer, charBufferClass)) {
45 return 1;
46 } else if ((*env)->IsInstanceOf(env, nioBuffer, intBufferClass) ||
47 (*env)->IsInstanceOf(env, nioBuffer, floatBufferClass)) {
48 return 2;
49 } else if ((*env)->IsInstanceOf(env, nioBuffer, longBufferClass) ||
50 (*env)->IsInstanceOf(env, nioBuffer, doubleBufferClass)) {
51 return 3;
52 }
53 return 0;
54 }
55
jniGetNioBufferBaseArray(JNIEnv * env,jobject nioBuffer)56 jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
57 jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env);
58 jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod);
59 if (hasArray) {
60 jmethodID arrayMethod = JniConstants_NioBuffer_array(env);
61 return (*env)->CallObjectMethod(env, nioBuffer, arrayMethod);
62 } else {
63 return NULL;
64 }
65 }
66
jniGetNioBufferBaseArrayOffset(JNIEnv * env,jobject nioBuffer)67 int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
68 jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env);
69 jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod);
70 if (hasArray) {
71 jmethodID arrayOffsetMethod = JniConstants_NioBuffer_arrayOffset(env);
72 jint arrayOffset = (*env)->CallIntMethod(env, nioBuffer, arrayOffsetMethod);
73 const int position = GetBufferPosition(env, nioBuffer);
74 jint elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
75 return (arrayOffset + position) << elementSizeShift;
76 } else {
77 return 0;
78 }
79 }
80
jniGetNioBufferPointer(JNIEnv * env,jobject nioBuffer)81 jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
82 // in Java 11, the address field of a HeapByteBuffer contains a non-zero value despite
83 // HeapByteBuffer being a non-direct buffer. In that case, this should still return 0.
84 jmethodID isDirectMethod = JniConstants_NioBuffer_isDirect(env);
85 jboolean isDirect = (*env)->CallBooleanMethod(env, nioBuffer, isDirectMethod);
86 if (isDirect == JNI_FALSE) {
87 return 0L;
88 }
89 jlong baseAddress = (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
90 if (baseAddress != 0) {
91 const int position = GetBufferPosition(env, nioBuffer);
92 const int shift = GetBufferElementSizeShift(env, nioBuffer);
93 baseAddress += position << shift;
94 }
95 return baseAddress;
96 }
97
jniGetNioBufferFields(JNIEnv * env,jobject nioBuffer,jint * position,jint * limit,jint * elementSizeShift)98 jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
99 jint* position, jint* limit, jint* elementSizeShift) {
100 *position = GetBufferPosition(env, nioBuffer);
101 *limit = GetBufferLimit(env, nioBuffer);
102 *elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
103 return (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
104 }
105