AVPKit
JNIMemoryManager.cpp
1 /*******************************************************************************
2  * Copyright (c) 2024, 2026, Olivier Ayache. All rights reserved.
3  *
4  * This file is part of AVPKit.
5  *
6  * AVPKit is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * AVPKit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with AVPKit. If not, see <http://www.gnu.org/licenses/>.
18  *******************************************************************************/
19 
20 /*
21  * JNIMemoryManagement.cpp
22  *
23  * Created on: Aug 27, 2008
24  * Author: aclarke
25  */
26 #include "JNIMemoryManager.h"
27 // for std::bad_alloc
28 #include <stdexcept>
29 
30 #include <new>
31 
32 // For free/malloc
33 #include <cstdlib>
34 #include <cstring>
35 #include <climits>
36 
37 //#define VSJNI_MEMMANAGER_DEBUG 1
38 #ifdef VSJNI_MEMMANAGER_DEBUG
39 #include <cstdio>
40 #endif
41 
42 #include <com/avpkit/ferry/config.h>
43 // AUTOCONF will sometimes replace malloc with rpl_malloc; we don't want
44 // that.
45 #ifdef malloc
46 #undef malloc
47 #endif
48 
49 #include "Ferry.h"
50 #include "RefCounted.h"
51 
52 static void *
53 VSJNI_malloc(jobject obj, size_t requested_size);
54 static void
55 VSJNI_free(void * mem);
56 static void *
57 VSJNI_alignMemory(void *);
58 static void *
59 VSJNI_unalignMemory(void*);
60 static size_t VSJNI_ALIGNMENT_BOUNDARY = 16; // Must be power of two
61 
65 enum VSJNIMemoryModel
66 {
67  JAVA_STANDARD_HEAP = 0,
68  JAVA_DIRECT_BUFFERS = 1,
69  JAVA_DIRECT_BUFFERS_WITH_STANDARD_HEAP_NOTIFICATION = 2,
70  NATIVE_BUFFERS = 3,
71  NATIVE_BUFFERS_WITH_STANDARD_HEAP_NOTIFICATION = 4,
72 };
73 
74 static enum VSJNIMemoryModel sVSJNI_IsMirroringNativeMemoryInJVM =
75 #ifdef VSJNI_USE_JVM_FOR_MEMMANAGEMENT
76  JAVA_STANDARD_HEAP;
77 #else
78 NATIVE_BUFFERS;
79 #endif
80 
81 namespace com
82 {
83 namespace avpkit
84 {
85 namespace ferry
86 {
87 
88 void *
89 JNIMemoryManager::malloc(size_t requested_size)
90 {
91  return JNIMemoryManager::malloc(0, requested_size);
92 }
93 
94 void *
95 JNIMemoryManager::malloc(void* obj, size_t requested_size)
96 {
97  void * retval = VSJNI_malloc(static_cast<jobject> (obj), requested_size);
98  return retval;
99 }
100 
101 void
103 {
104  VSJNI_free(mem);
105 }
106 
107 }
108 }
109 }
110 
111 static JavaVM* sCachedJVM = 0;
112 #ifdef VSJNI_USE_JVM_FOR_MEMMANAGEMENT
113 static JNIEnv*
114 VSJNI_getEnv();
115 static jclass sByteBufferReferenceClass = 0;
116 static jmethodID sByteBufferAllocateDirectMethod = 0;
117 static jclass sJNIMemoryAllocatorClass = 0;
118 static jmethodID sJNIMemoryAllocatorMallocMethod = 0;
119 static jmethodID sJNIMemoryAllocatorFreeMethod = 0;
120 #endif // VSJNI_USE_JVM_FOR_MEMMANAGEMENT
121 /*
122  * This method is called by the JNIHelper when it loads up and
123  * BEFORE it tries to allocate memory.
124  *
125  * WARNING: DO NOT CALL JNIHELPER METHODS HERE DIRECTLY; THEY
126  * RELY ON CREATING A JNIHELPER OBJECT WHICH USES NEW!
127  */
128 void
129 VSJNI_MemoryManagerInit(JavaVM* aJVM)
130 {
131  sCachedJVM = aJVM;
132 
133 #ifdef VSJNI_USE_JVM_FOR_MEMMANAGEMENT
137  try
138  {
139  // Now, let's cache the commonly used classes.
140  JNIEnv *env = VSJNI_getEnv();
141  if (!env)
142  throw std::runtime_error("could not find environment");
143 
144  jclass cls = env->FindClass("java/nio/ByteBuffer");
145  if (!cls)
146  throw std::runtime_error("could not find java.nio.ByteBuffer class");
147 
148  sByteBufferReferenceClass = (jclass) env->NewWeakGlobalRef(cls);
149  if (!sByteBufferReferenceClass)
150  throw std::runtime_error("could not get weak reference for class");
151 
152  sByteBufferAllocateDirectMethod = env->GetStaticMethodID(cls,
153  "allocateDirect", "(I)Ljava/nio/ByteBuffer;");
154  if (!sByteBufferAllocateDirectMethod)
155  throw std::runtime_error(
156  "could not find allocateDirect(int) method in java.nio.ByteBuffer");
157  env->DeleteLocalRef(cls);
158  if (env->ExceptionCheck())
159  throw std::runtime_error("got exception in jni");
160 
161  cls = env->FindClass("com/avpkit/ferry/JNIMemoryAllocator");
162  if (!cls)
163  throw std::runtime_error(
164  "could not find com.avpkit.ferry.JNIMemoryAllocatorclass");
165 
166  sJNIMemoryAllocatorClass = (jclass) env->NewWeakGlobalRef(cls);
167  if (!sJNIMemoryAllocatorClass)
168  throw std::runtime_error("could not get weak reference for class");
169 
170  sJNIMemoryAllocatorMallocMethod = env->GetMethodID(cls, "malloc", "(I)[B");
171  if (!sJNIMemoryAllocatorMallocMethod)
172  throw std::runtime_error(
173  "could not find malloc(int) method in com.avpkit.ferry.JNIMemoryAllocator");
174  sJNIMemoryAllocatorFreeMethod = env->GetMethodID(cls, "free", "([B)V");
175  if (!sJNIMemoryAllocatorFreeMethod)
176  throw std::runtime_error(
177  "could not find free(byte[]) method in com.avpkit.ferry.JNIMemoryAllocator");
178  }
179  catch (std::exception e)
180  {
181  // DON'T HAVE JAVA do memory management.
182  sCachedJVM = 0;
183 #ifdef VSJNI_MEMMANAGER_DEBUG
184  fprintf(stderr,
185  "got exception initializing jvm; using stdlib for memory allocation\n");
186 #endif
187  }
188 #else
189 #endif // VSJNI_USE_JVM_FOR_MEMMANGEMENT
190 }
191 
192 #ifdef VSJNI_USE_JVM_FOR_MEMMANAGEMENT
193 static JNIEnv*
194 VSJNI_getEnv()
195 {
196  JNIEnv * env = 0;
197  if (sCachedJVM)
198  {
199  jint retval = sCachedJVM->GetEnv((void**) (void*) &env, JNI_VERSION_1_2);
200  if (retval == JNI_EDETACHED)
201  throw std::runtime_error("not attached to JVM");
202 
203  if (retval == JNI_EVERSION)
204  throw std::runtime_error("Java v1.2 not supported");
205 
206  }
207  return env;
208 }
209 
210 struct VSJNI_AllocationHeader
211 {
217  jobject mRef;
222  jobject mAllocator;
226  enum VSJNIMemoryModel mModel;
227 };
228 
229 static void *
230 VS_JNI_malloc_native(JNIEnv *env, jobject obj, size_t requested_size,
231  bool notifyJavaHeap)
232 {
233  void *retval = 0;
234  void *buffer = 0;
235 
236  if (notifyJavaHeap && env){
237  jbyteArray bytearray= 0;
238  if (obj)
239  {
240  // We allocate a byte array for the actual memory
241  bytearray = static_cast<jbyteArray> (env->CallObjectMethod(obj,
242  sJNIMemoryAllocatorMallocMethod, requested_size
243  + sizeof(VSJNI_AllocationHeader) + VSJNI_ALIGNMENT_BOUNDARY));
244  }
245  else
246  {
247  // We allocate a byte array for the actual memory
248  bytearray = env->NewByteArray(requested_size
249  + sizeof(VSJNI_AllocationHeader) + VSJNI_ALIGNMENT_BOUNDARY);
250  }
251  if (!bytearray)
252  throw std::bad_alloc();
253  if (obj) {
254  // Tell the allocator we're done
255  // We're relying on the fact that the WeakReference passed in
256  // is always outlived
257  // by the allocator object (knock on wood)
258  env->CallVoidMethod(obj,
259  sJNIMemoryAllocatorFreeMethod, bytearray);
260  if (env->ExceptionCheck()) {
261  env->DeleteLocalRef(bytearray);
262  throw std::runtime_error("got java exception");
263  }
264  }
265  env->DeleteLocalRef(bytearray);
266  if (env->ExceptionCheck())
267  throw std::bad_alloc();
268  }
269 
270  // We're not in a JVM, so use malloc/free instead
271  buffer = requested_size > 0 ? malloc((size_t) requested_size + sizeof(VSJNI_AllocationHeader)
272  + VSJNI_ALIGNMENT_BOUNDARY) : 0;
273  VSJNI_AllocationHeader *header = (VSJNI_AllocationHeader*) buffer;
274  if (!header)
275  throw std::bad_alloc();
276  // initialize the header to 0; that way later on delete we can tell
277  // if this was JVMed or Malloced.
278  memset(header, 0, sizeof(VSJNI_AllocationHeader));
279  header->mModel = NATIVE_BUFFERS;
280 
281  retval = (void*) ((char*) header + sizeof(VSJNI_AllocationHeader));
282  return retval;
283 }
284 
285 static void *
286 VS_JNI_malloc_javaDirectBufferBacked(JNIEnv *env, jobject obj,
287  size_t requested_size,
288  bool notifyJavaHeap)
289 {
290  void *retval = 0;
291  void *buffer = 0;
292  // We allocate a byte array for the actual memory
293  jlong size = requested_size + sizeof(VSJNI_AllocationHeader)
294  + VSJNI_ALIGNMENT_BOUNDARY;
295 
296  if (env->ExceptionCheck()) {
297  throw std::bad_alloc();
298  }
299 
300  // First, let's exert some pressure on the non-direct java heap
301  if (notifyJavaHeap){
302  jbyteArray bytearray= 0;
303  if (obj)
304  {
305  // We allocate a byte array for the actual memory
306  bytearray = static_cast<jbyteArray> (env->CallObjectMethod(obj,
307  sJNIMemoryAllocatorMallocMethod, requested_size
308  + sizeof(VSJNI_AllocationHeader) + VSJNI_ALIGNMENT_BOUNDARY));
309  }
310  else
311  {
312  // We allocate a byte array for the actual memory
313  bytearray = env->NewByteArray(requested_size
314  + sizeof(VSJNI_AllocationHeader) + VSJNI_ALIGNMENT_BOUNDARY);
315  }
316  if (!bytearray)
317  throw std::bad_alloc();
318  if (obj) {
319  // Tell the allocator we're done
320  // We're relying on the fact that the WeakReference passed in
321  // is always outlived
322  // by the allocator object (knock on wood)
323  env->CallVoidMethod(obj,
324  sJNIMemoryAllocatorFreeMethod, bytearray);
325  if (env->ExceptionCheck()) {
326  env->DeleteLocalRef(bytearray);
327  throw std::runtime_error("got java exception");
328  }
329  }
330  env->DeleteLocalRef(bytearray);
331  if (env->ExceptionCheck())
332  throw std::bad_alloc();
333  }
334  jclass cls = static_cast<jclass>(env->NewLocalRef(sByteBufferReferenceClass));
335  if (!cls)
336  {
337  throw std::bad_alloc();
338  }
339  jobject bytearray = env->CallStaticObjectMethod(sByteBufferReferenceClass,
340  sByteBufferAllocateDirectMethod, (jint)size);
341  env->DeleteLocalRef(cls);
342  // if JVM didn't like that, return bad_alloc(); when we return all the way back to
343  // JVM the Exception in Java will still exist; even if someone else catches
344  // std::bad_alloc()
345  if (!bytearray || env->ExceptionCheck()) {
346  throw std::bad_alloc();
347  }
348 
349  jlong availableCapacity = env->GetDirectBufferCapacity(bytearray);
350  if (env->ExceptionCheck()) {
351  throw std::bad_alloc();
352  }
353  if (availableCapacity < size) {
354  throw std::bad_alloc();
355  }
356 
357  buffer = env->GetDirectBufferAddress(bytearray);
358  if (!buffer || env->ExceptionCheck()) {
359  throw std::bad_alloc();
360  }
361 
362  // We're going to take up the first few (usually 4 on 32bit
363  // and 8 on 64 bit machines)
364  // bytes of this for our header, so be aware if you use this
365  // for really small objects
366  // that the overhead is QUITE high.
367  VSJNI_AllocationHeader* header = (VSJNI_AllocationHeader*) buffer;
368  memset(header, 0, sizeof(VSJNI_AllocationHeader));
369 
370  // And tell the JVM that it can't cleanup the bytearray yet; we've got
371  // things to do and places to go.
372  header->mRef = static_cast<jobject> (env->NewGlobalRef(bytearray));
373  if (!header->mRef || env->ExceptionCheck()) {
374  throw std::bad_alloc();
375  }
376  header->mModel = JAVA_DIRECT_BUFFERS;
377 
378  // But be nice and delete the local ref we had since we now have a
379  // stronger reference.
380  env->DeleteLocalRef(bytearray);
381  if (env->ExceptionCheck()) {
382  env->DeleteLocalRef(header->mRef);
383  throw std::bad_alloc();
384  }
385  // Finally, return the buffer, but skip past our header
386  retval = (void*) ((char*) buffer + sizeof(VSJNI_AllocationHeader));
387  return retval;
388 }
389 
390 static void *
391 VS_JNI_malloc_javaByteBacked(JNIEnv* env, jobject obj, size_t requested_size)
392 {
393  void* retval = 0;
394  void* buffer = 0;
395  // make sure we don't already have a pending exception
396  if (env->ExceptionCheck())
397  throw std::bad_alloc();
398 
399  jbyteArray bytearray = 0;
400  if (obj)
401  {
402  // We allocate a byte array for the actual memory
403  bytearray = static_cast<jbyteArray> (env->CallObjectMethod(obj,
404  sJNIMemoryAllocatorMallocMethod, requested_size
405  + sizeof(VSJNI_AllocationHeader) + VSJNI_ALIGNMENT_BOUNDARY));
406  }
407  else
408  {
409  // We allocate a byte array for the actual memory
410  bytearray = env->NewByteArray(requested_size
411  + sizeof(VSJNI_AllocationHeader) + VSJNI_ALIGNMENT_BOUNDARY);
412  }
413 
414  // if JVM didn't like that, return bad_alloc(); when we
415  // return all the way back to
416  // JVM the Exception in Java will still exist; even if someone else catches
417  // std::bad_alloc()
418  if (!bytearray)
419  throw std::bad_alloc();
420  if (env->ExceptionCheck())
421  throw std::bad_alloc();
422 
423  // Now this is the actual memory pointed to by the java byte array
424  // I use a void* buffer here so I can peak more easily in a debugger
425  buffer = (void*) (env->GetByteArrayElements(bytearray, 0));
426  if (env->ExceptionCheck())
427  throw std::bad_alloc();
428 
429  // Technically this should never occur (i.e. if buffer is null
430  // then a Java exception should have occurred). still, we'll
431  // be doubly safe for fun
432  if (!buffer)
433  throw std::bad_alloc();
434 
435  VSJNI_AllocationHeader* header = (VSJNI_AllocationHeader*) buffer;
436  memset(header, 0, sizeof(VSJNI_AllocationHeader));
437 
438  // And tell the JVM that it can't cleanup the bytearray yet; we've got
439  // things to do and places to go.
440  header->mRef = env->NewGlobalRef(bytearray);
441  if (!header->mRef)
442  throw std::bad_alloc();
443  header->mAllocator = 0;
444  if (obj)
445  {
446  header->mAllocator = env->NewGlobalRef(obj);
447  if (!header->mAllocator)
448  throw std::bad_alloc();
449  }
450  header->mModel = JAVA_STANDARD_HEAP;
451 
452  // But be nice and delete the local ref we had since we now have a
453  // stronger reference.
454  env->DeleteLocalRef(bytearray);
455  if (env->ExceptionCheck())
456  throw std::bad_alloc();
457 
458  // Finally, return the buffer, but skip past our header
459  retval = (void*) ((char*) buffer + sizeof(VSJNI_AllocationHeader));
460  return retval;
461 }
462 
463 static void *
464 VSJNI_malloc(jobject obj, size_t requested_size)
465 {
466  try
467  {
468  void* retval = 0;
469  JNIEnv* env = 0;
470 
471  if ((size_t) requested_size > INT_MAX - VSJNI_ALIGNMENT_BOUNDARY)
472  // we need 16 byte clearance; and only support up to 4GBs. Sorry folks, if
473  // you need more than 4GB of contiguous memory, it's not us.
474  return 0;
475 
476  (void) obj;
477  env = VSJNI_getEnv();
478  enum VSJNIMemoryModel model = sVSJNI_IsMirroringNativeMemoryInJVM;
479  if (!env)
480  model = NATIVE_BUFFERS;
481  switch (model)
482  {
483  case JAVA_STANDARD_HEAP:
484  retval = VS_JNI_malloc_javaByteBacked(env, obj, requested_size);
485  break;
486  case JAVA_DIRECT_BUFFERS:
487  retval = VS_JNI_malloc_javaDirectBufferBacked(env, obj, requested_size,
488  false);
489  break;
490  case JAVA_DIRECT_BUFFERS_WITH_STANDARD_HEAP_NOTIFICATION:
491  retval = VS_JNI_malloc_javaDirectBufferBacked(env, obj, requested_size,
492  true);
493  break;
494  case NATIVE_BUFFERS:
495  retval = VS_JNI_malloc_native(env, obj, requested_size, false);
496  break;
497  case NATIVE_BUFFERS_WITH_STANDARD_HEAP_NOTIFICATION:
498  retval = VS_JNI_malloc_native(env, obj, requested_size, true);
499  break;
500  default:
501  throw std::bad_alloc();
502  break;
503  }
504 #ifdef VSJNI_MEMMANAGER_DEBUG
505  fprintf (stderr, "alloc: returned %p(%lld) size (%ld); model: %d\n",
506  retval,
507  (int64_t) retval,
508  (size_t)requested_size,
509  model);
510 #endif
511  // Now, align on VSJNI_ALIGNMENT_BOUNDARY byte boundary;
512  // on Posix system we could have used memalign for the malloc,
513  // but that doesn't work
514  // for Java allocations, so we do this hack for everyone.
515  return VSJNI_alignMemory(retval);
516  }
517  catch (std::bad_alloc & e)
518  {
519 #ifdef VSJNI_MEMMANAGER_DEBUG
520  fprintf (stderr, "alloc: bad_alloc of size %ld\n",
521  (size_t)requested_size);
522 #endif
523  return 0;
524  }
525 }
526 
534 static void
535 VSJNI_free(void * mem)
536 {
537  void *buffer = 0;
538  if (mem)
539  {
540  // realign back to original boundary
541  mem = VSJNI_unalignMemory(mem);
542 
543  // Find the actual start of the memory
544  buffer = (void*) ((char*) mem - sizeof(VSJNI_AllocationHeader));
545 
546  // Get our header
547  VSJNI_AllocationHeader *header = (VSJNI_AllocationHeader*) buffer;
548  enum VSJNIMemoryModel model = header->mModel;
549  JNIEnv* env = VSJNI_getEnv();
550  switch(model)
551  {
552  case JAVA_STANDARD_HEAP:
553  {
554  if (!env)
555  // just leak; doesn't make any sense that we're here.
556  return;
557  if (env->ExceptionCheck())
558  throw std::runtime_error("got java exception");
559 
560  if (header->mAllocator)
561  {
562  // Tell the allocator we're done
563  // We're relying on the fact that the WeakReference passed in
564  // is always outlived
565  // by the allocator object (knock on wood)
566  env->CallVoidMethod(header->mAllocator,
567  sJNIMemoryAllocatorFreeMethod, header->mRef);
568  if (env->ExceptionCheck())
569  throw std::runtime_error("got java exception");
570  env->DeleteGlobalRef(header->mAllocator);
571  if (env->ExceptionCheck())
572  throw std::runtime_error("got java exception");
573  }
574 
575  // Get a local copy so that when we delete the global
576  // ref, the gc thread won't free the underlying memory
577  if (header->mRef)
578  {
579  jbyteArray array = static_cast<jbyteArray> (env->NewLocalRef(
580  header->mRef));
581  if (env->ExceptionCheck())
582  throw std::runtime_error("got java exception");
583  if (!array)
584  throw std::runtime_error("got java exception");
585 
586  // delete the global ref, so that when we return the
587  // jvm can gc
588  env->DeleteGlobalRef(header->mRef);
589  header->mRef = 0;
590  if (env->ExceptionCheck())
591  throw std::runtime_error("got java exception");
592 
593  // Tell the JVM to release the elements of raw memory
594  env->ReleaseByteArrayElements(array, (jbyte*) buffer, JNI_ABORT);
595  if (env->ExceptionCheck())
596  throw std::runtime_error("got java exception");
597 
598  // and we should be careful to delete our local ref because
599  // we don't know how deep we are in native calls, or when
600  // we'll actually return to the jvm
601  env->DeleteLocalRef(array);
602  if (env->ExceptionCheck())
603  throw std::runtime_error("got java exception");
604  }
605  }
606  break;
607  case JAVA_DIRECT_BUFFERS:
609  case JAVA_DIRECT_BUFFERS_WITH_STANDARD_HEAP_NOTIFICATION:
610  {
611  if (!env)
612  return;
613  // delete the global ref, so that when we return the
614  // jvm can gc
615  jobject ref = header->mRef;
616  header->mRef = 0;
617  if (ref != 0)
618  env->DeleteGlobalRef(ref);
619  }
620  break;
621  case NATIVE_BUFFERS:
623  case NATIVE_BUFFERS_WITH_STANDARD_HEAP_NOTIFICATION:
624  {
625  free(buffer);
626  }
627  break;
628  default:
629  fprintf(stderr, "ERROR: Should never get here\n");
631  break;
632  }
633 #ifdef VSJNI_MEMMANAGER_DEBUG
634  printf("free: orig %p (%lld) adjusted %p (%lld); model %d\n",
635  mem,
636  (int64_t) mem,
637  buffer,
638  (int64_t)buffer,
639  model);
640 #endif
641  }
642 }
643 
644 #else
645 static void *VSJNI_malloc(jobject, size_t requested_size)
646 {
647  void* retval = 0;
648 
649  if (
650  (sizeof(size_t) == 4 && (size_t)requested_size > INT_MAX - VSJNI_ALIGNMENT_BOUNDARY) ||
651  ((int64_t)requested_size > LLONG_MAX - VSJNI_ALIGNMENT_BOUNDARY))
652  // we need 16 byte clearance; ok, for 64-bit machines if you're
653  // asking for 9-Tera-Whatevers of memory, you'll fail anyway,
654  // but we try to be complete.
655  return 0;
656  retval = malloc(requested_size + VSJNI_ALIGNMENT_BOUNDARY);
657  if (!retval)
658  return 0;
659 
660  return VSJNI_alignMemory(retval);
661 }
662 static void
663 VSJNI_free(void * mem)
664 {
665  // realign back to original boundary
666  if (mem)
667  {
668  mem = VSJNI_unalignMemory(mem);
669  free(mem);
670  }
671 }
672 #endif // USE_JVM_FOR_MEM_MANAGEMENT
673 static void*
674 VSJNI_alignMemory(void* aInput)
675 {
676  void* retval = aInput;
677  retval = aInput;
678  size_t alignDiff = ((-(size_t) retval - 1) & (VSJNI_ALIGNMENT_BOUNDARY - 1)) + 1;
679  retval = (char*) retval + alignDiff;
680  ((char*) retval)[-1] = (char) alignDiff;
681 #ifdef VSJNI_MEMMANAGER_DEBUG
682  printf ("align: orig(%p:%lld) new(%p:%lld) align(%d)\n",
683  aInput, (int64_t)aInput,
684  retval, (int64_t) retval,
685  alignDiff);
686 #endif
687 
688  return retval;
689 }
690 
697 static void*
698 VSJNI_unalignMemory(void *aInput)
699 {
700  size_t alignDiff = ((char*) aInput)[-1];
701  void * retval = (void*) (((char*) aInput) - alignDiff);
702 #ifdef VSJNI_MEMMANAGER_DEBUG
703  printf ("unalign: orig(%p:%lld) new(%p:%lld) align(%d)\n",
704  aInput, (int64_t)aInput,
705  retval, (int64_t) retval,
706  alignDiff);
707 #endif
708  return retval;
709 }
710 
717 #ifdef VSJNI_OVERRIDE_CPP_NEW_AND_DELETE
718 VS_API_FERRY void *
719 operator new (size_t requested_size)
720 {
721  return VSJNI_malloc(0, requested_size);
722 }
723 
724 VS_API_FERRY void
725 operator delete (void *mem)
726 {
727  VSJNI_free(mem);
728 }
729 #endif // VSJNI_OVERRIDE_CPP_NEW_AND_DELETE
733 extern "C"
734 {
735 VS_API_EXPORT void JNICALL
736 Java_com_avpkit_ferry_JNIMemoryAllocator_setAllocator(JNIEnv *, jclass,
737  jlong aNativeObj, jobject aMemMgr)
738 {
739  // assume that the native object is a RefCounted
741  *(com::avpkit::ferry::RefCounted**) &aNativeObj;
742  obj->setJavaAllocator(aMemMgr);
743 }
744 
745 VS_API_EXPORT jobject JNICALL
746 Java_com_avpkit_ferry_JNIMemoryAllocator_getAllocator(JNIEnv *env, jclass,
747  jlong aNativeObj)
748 {
749  // assume that the native object is a RefCounted
751  *(com::avpkit::ferry::RefCounted**) &aNativeObj;
752  jobject result = (jobject) obj->getJavaAllocator();
753  if (result)
754  result = env->NewLocalRef(result);
755  return result;
756 }
757 
758 VS_API_EXPORT jint JNICALL
759 Java_com_avpkit_ferry_FerryJNI_getMemoryModel(JNIEnv *, jclass)
760 {
761  return (jint) sVSJNI_IsMirroringNativeMemoryInJVM;
762 }
763 
764 VS_API_EXPORT void JNICALL
765 Java_com_avpkit_ferry_FerryJNI_setMemoryModel(JNIEnv *, jclass, jint value)
766 {
767 #ifdef VSJNI_USE_JVM_FOR_MEMMANAGEMENT
768  sVSJNI_IsMirroringNativeMemoryInJVM = (enum VSJNIMemoryModel) value;
769 #endif
770 }
771 
772 }
static void free(void *mem)
Free memory previously allocated by malloc(void*, size_t).
static void * malloc(size_t requested_size)
Create a malloced block of AT LEAST site_t bounds long.
Parent of all Ferry objects – it mains reference counts in native code.
Definition: RefCounted.h:85
void * getJavaAllocator()
This method is public but not part of the standard API.
Definition: RefCounted.cpp:57
void setJavaAllocator(void *allocator)
This method is public but not part of the standard API.
Definition: RefCounted.cpp:46
WARNING: Do not use logging in this class, and do not set any static file variables to values other t...