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)