1 /* 2 * Copyright (c) 2019, 2019 Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <jni.h> 28 29 #if !defined(_WIN32) && !defined(_WIN64) 30 31 JNIEXPORT jint JNICALL 32 Java_TestJNIArrays_GetFlattenedArrayElementSizeWrapper(JNIEnv* env, jobject receiver, jarray array) { 33 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 34 return (jint)elm_sz; 35 } 36 37 JNIEXPORT jclass JNICALL 38 Java_TestJNIArrays_GetFlattenedArrayElementClassWrapper(JNIEnv* env, jobject receiver, jarray array) { 39 jclass elm_class = (*env)->GetFlattenedArrayElementClass(env, array); 40 return elm_class; 41 } 42 43 JNIEXPORT jint JNICALL 44 Java_TestJNIArrays_GetFieldOffsetInFlattenedLayoutWrapper(JNIEnv* env, jobject receiver, jclass clazz, jstring name, jstring signature, jboolean expectFlattened) { 45 jboolean flattened; 46 const char *name_ptr = (*env)->GetStringUTFChars(env, name, NULL); 47 const char *signature_ptr = (*env)->GetStringUTFChars(env, signature, NULL); 48 int offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, name_ptr,signature_ptr, &flattened); 49 (*env)->ReleaseStringUTFChars(env, name, name_ptr); 50 (*env)->ReleaseStringUTFChars(env, signature, signature_ptr); 51 if ((*env)->ExceptionCheck(env)) { 52 return -1; 53 } 54 if (flattened != expectFlattened) { 55 jclass RE = (*env)->FindClass(env, "java/lang/RuntimeException"); 56 (*env)->ThrowNew(env, RE, "Flattening mismatch"); 57 return -1; 58 } 59 return offset; 60 } 61 62 JNIEXPORT jlong JNICALL 63 Java_TestJNIArrays_GetFlattenedArrayElementsWrapper(JNIEnv* env, jobject receiver, jarray array) { 64 jboolean isCopy; 65 void* addr = (*env)->GetFlattenedArrayElements(env, array, &isCopy); 66 return (jlong)addr; 67 } 68 69 JNIEXPORT void JNICALL 70 Java_TestJNIArrays_ReleaseFlattenedArrayElementsWrapper(JNIEnv* env, jobject receiver, jarray array, jlong addr, jint mode) { 71 (*env)->ReleaseFlattenedArrayElements(env, array, (void*)addr, mode); 72 } 73 74 JNIEXPORT jint JNICALL 75 Java_TestJNIArrays_getIntFieldAtIndex(JNIEnv* env, jobject receiver, jarray array, jint index, jstring name, jstring signature) { 76 jint array_length = (*env)->GetArrayLength(env, array); 77 if (index < 0 || index >= array_length) { 78 jclass AIOOBE = (*env)->FindClass(env, "java.lang.ArrayIndexOutOfBoundsException"); 79 (*env)->ThrowNew(env, AIOOBE, "Bad index"); 80 return -1; 81 } 82 jobject element = (*env)->GetObjectArrayElement(env, array, index); 83 // should add protection against null element here (could happen if array is not a flattened array 84 jclass element_class = (*env)->GetObjectClass(env, element); 85 const char *name_ptr = (*env)->GetStringUTFChars(env, name, NULL); 86 const char *signature_ptr = (*env)->GetStringUTFChars(env, signature, NULL); 87 jfieldID field_id = (*env)->GetFieldID(env, element_class, (const char*)name_ptr, (const char *)signature_ptr); 88 (*env)->ReleaseStringUTFChars(env, name, name_ptr); 89 (*env)->ReleaseStringUTFChars(env, signature, signature_ptr); 90 jint value = (*env)->GetIntField(env, element, field_id); 91 return value; 92 } 93 94 JNIEXPORT void JNICALL 95 Java_TestJNIArrays_printArrayInformation(JNIEnv* env, jobject receiver, jarray array) { 96 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 97 void* base = (*env)->GetFlattenedArrayElements(env, array, NULL); 98 (*env)->ReleaseFlattenedArrayElements(env, array, base, 0); 99 } 100 101 JNIEXPORT void JNICALL 102 Java_TestJNIArrays_initializeIntIntArrayBuffer(JNIEnv* env, jobject receiver, jarray array, int i0, int i1) { 103 int len = (*env)->GetArrayLength(env, array); 104 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 105 jclass clazz = (*env)->GetFlattenedArrayElementClass(env, array); 106 int i0_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "i0", "I", NULL); 107 int i1_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "i1", "I", NULL); 108 char* buffer = (char*)malloc(elm_sz); 109 if (buffer == NULL) { 110 jclass OOM = (*env)->FindClass(env, "java/lang/OutOfMemoryException"); 111 (*env)->ThrowNew(env, OOM, "Malloc failed"); 112 return; 113 } 114 *(int*)(buffer + i0_offset) = i0; 115 *(int*)(buffer + i1_offset) = i1; 116 void* base = (void*)(*env)->GetFlattenedArrayElements(env, array, NULL); 117 for (int i = 0; i < len; i++) { 118 memcpy((char*)base + i * elm_sz, buffer, elm_sz); 119 } 120 (*env)->ReleaseFlattenedArrayElements(env, array, base, 0); 121 free(buffer); 122 } 123 124 JNIEXPORT void JNICALL 125 Java_TestJNIArrays_initializeIntIntArrayFields(JNIEnv* env, jobject receiver, jarray array, int i0, int i1) { 126 int len = (*env)->GetArrayLength(env, array); 127 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 128 jclass clazz = (*env)->GetFlattenedArrayElementClass(env, array); 129 int i0_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "i0", "I", NULL); 130 int i1_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "i1", "I", NULL); 131 void* base = (void*)(*env)->GetFlattenedArrayElements(env, array, NULL); 132 char* elm_ptr = base; 133 for (int i = 0; i < len; i++) { 134 *(int*)(elm_ptr + i0_offset) = i0; 135 *(int*)(elm_ptr + i1_offset) = i1; 136 elm_ptr += elm_sz; 137 } 138 (*env)->ReleaseFlattenedArrayElements(env, array, base, 0); 139 } 140 141 struct IntInt_offsets { 142 int i0_offset; 143 int i1_offset; 144 }; 145 146 #ifdef __APPLE__ 147 static int compare_IntInt(void* offsets, const void* x, const void* y) { 148 #endif // __APPLE__ 149 #ifdef __linux__ 150 static int compare_IntInt(const void* x, const void* y, void* offsets) { 151 #endif // __linux__ 152 int i0_offset = ((struct IntInt_offsets*)offsets)->i0_offset; 153 int x_i0 = *(int*)((char*)x + i0_offset); 154 int y_i0 = *(int*)((char*)y + i0_offset); 155 if (x_i0 < y_i0) return -1; 156 if (x_i0 > y_i0) return 1; 157 int i1_offset = ((struct IntInt_offsets*)offsets)->i1_offset; 158 int x_i1 = *(int*)((char*)x + i1_offset); 159 int y_i1 = *(int*)((char*)y + i1_offset ); 160 if (x_i1 < y_i1) return -1; 161 if (x_i1 > y_i1) return 1; 162 return 0; 163 } 164 165 JNIEXPORT void JNICALL 166 Java_TestJNIArrays_sortIntIntArray(JNIEnv* env, jobject receiver, jarray array) { 167 int len = (*env)->GetArrayLength(env, array); 168 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 169 jclass clazz = (*env)->GetFlattenedArrayElementClass(env, array); 170 struct IntInt_offsets offsets; 171 offsets.i0_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "i0", "I", NULL); 172 offsets.i1_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "i1", "I", NULL); 173 void* base = (void*)(*env)->GetFlattenedArrayElements(env, array, NULL); 174 #ifdef __APPLE__ 175 qsort_r(base, len, elm_sz, (void*) &offsets, compare_IntInt); 176 #endif // __APPLE__ 177 #ifdef __linux__ 178 qsort_r(base, len, elm_sz, compare_IntInt, (void*) &offsets); 179 #endif // __linux__ 180 (*env)->ReleaseFlattenedArrayElements(env, array, base, 0); 181 } 182 183 184 JNIEXPORT void JNICALL 185 Java_TestJNIArrays_initializeContainerArray(JNIEnv* env, jobject receiver, jarray array, 186 jdouble d, jfloat f, jshort s, jbyte b) { 187 int len = (*env)->GetArrayLength(env, array); 188 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 189 jclass clazz = (*env)->GetFlattenedArrayElementClass(env, array); 190 int d_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "d", "D", NULL); 191 int b_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "b", "B", NULL); 192 jboolean flattened; 193 int c_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "c", "QTestJNIArrays$Containee;", &flattened); 194 if (!flattened) { 195 jclass RE = (*env)->FindClass(env, "java/lang/RuntimeException"); 196 (*env)->ThrowNew(env, RE, "Incompatible layout"); 197 return; 198 } 199 jclass clazz2 = (*env)->FindClass(env, "TestJNIArrays$Containee"); 200 int f_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz2, "f", "F", NULL); 201 int s_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz2, "s", "S", NULL); 202 f_offset += c_offset; 203 s_offset += c_offset; 204 void* base = (void*)(*env)->GetFlattenedArrayElements(env, array, NULL); 205 char* elm_ptr = base; 206 for (int i = 0; i < len; i++) { 207 *(jdouble*)(elm_ptr + d_offset) = d; 208 *(jfloat*)(elm_ptr + f_offset) = f; 209 *(jshort*)(elm_ptr + s_offset) = s; 210 *(jbyte*)(elm_ptr + b_offset) = b; 211 elm_ptr += elm_sz; 212 } 213 (*env)->ReleaseFlattenedArrayElements(env, array, base, 0); 214 } 215 216 217 JNIEXPORT void JNICALL 218 Java_TestJNIArrays_updateContainerArray(JNIEnv* env, jobject receiver, jarray array, 219 jfloat f, jshort s) { 220 int len = (*env)->GetArrayLength(env, array); 221 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 222 jclass clazz = (*env)->GetFlattenedArrayElementClass(env, array); 223 jboolean flattened; 224 int c_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "c", "QTestJNIArrays$Containee;", &flattened); 225 if (!flattened) { 226 jclass RE = (*env)->FindClass(env, "java/lang/RuntimeException"); 227 (*env)->ThrowNew(env, RE, "Incompatible layout"); 228 return; 229 } 230 jclass clazz2 = (*env)->FindClass(env, "TestJNIArrays$Containee"); 231 int f_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz2, "f", "F", NULL); 232 int s_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz2, "s", "S", NULL); 233 f_offset += c_offset; 234 s_offset += c_offset; 235 void* base = (void*)(*env)->GetFlattenedArrayElements(env, array, NULL); 236 char* elm_ptr = base; 237 for (int i = 0; i < len; i++) { 238 *(jfloat*)(elm_ptr + f_offset) = f; 239 *(jshort*)(elm_ptr + s_offset) = s; 240 elm_ptr += elm_sz; 241 } 242 (*env)->ReleaseFlattenedArrayElements(env, array, base, 0); 243 } 244 245 246 JNIEXPORT void JNICALL 247 Java_TestJNIArrays_initializeLongLongLongLongArray(JNIEnv* env, jobject receiver, jarray array, jlong l0, jlong l1, jlong l2, jlong l3) { 248 int len = (*env)->GetArrayLength(env, array); 249 jsize elm_sz = (*env)->GetFlattenedArrayElementSize(env, array); 250 jclass clazz = (*env)->GetFlattenedArrayElementClass(env, array); 251 int l0_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "l0", "J", NULL); 252 int l1_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "l1", "J", NULL); 253 int l2_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "l2", "J", NULL); 254 int l3_offset = (*env)->GetFieldOffsetInFlattenedLayout(env, clazz, "l3", "J", NULL); 255 void* base = (void*)(*env)->GetFlattenedArrayElements(env, array, NULL); 256 char* elm_ptr = base; 257 for (int i = 0; i < len; i++) { 258 *(jlong*)(elm_ptr + l0_offset) = l0; 259 *(jlong*)(elm_ptr + l1_offset) = l1; 260 *(jlong*)(elm_ptr + l2_offset) = l2; 261 *(jlong*)(elm_ptr + l3_offset) = l3; 262 elm_ptr += elm_sz; 263 } 264 (*env)->ReleaseFlattenedArrayElements(env, array, base, 0); 265 } 266 267 #endif // !defined(_WIN32) && !defined(_WIN64)