1#include "NIOBuffer.h"
2#include "GraphicsJNI.h"
3
4// enable this to dump each time we ref/unref a global java object (buffer)
5//
6//#define TRACE_GLOBAL_REFS
7
8//#define TRACE_ARRAY_LOCKS
9
10static jclass gNIOAccess_classID;
11static jmethodID gNIOAccess_getBasePointer;
12static jmethodID gNIOAccess_getBaseArray;
13static jmethodID gNIOAccess_getBaseArrayOffset;
14static jmethodID gNIOAccess_getRemainingBytes;
15
16void NIOBuffer::RegisterJNI(JNIEnv* env) {
17    if (0 != gNIOAccess_classID) {
18        return; // already called
19    }
20
21    jclass c = env->FindClass("java/nio/NIOAccess");
22    gNIOAccess_classID = (jclass)env->NewGlobalRef(c);
23
24    gNIOAccess_getBasePointer = env->GetStaticMethodID(gNIOAccess_classID,
25                                    "getBasePointer", "(Ljava/nio/Buffer;)J");
26    gNIOAccess_getBaseArray = env->GetStaticMethodID(gNIOAccess_classID,
27                    "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
28    gNIOAccess_getBaseArrayOffset = env->GetStaticMethodID(gNIOAccess_classID,
29                                "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
30    gNIOAccess_getRemainingBytes = env->GetStaticMethodID(gNIOAccess_classID,
31                                "getRemainingBytes", "(Ljava/nio/Buffer;)I");
32}
33
34///////////////////////////////////////////////////////////////////////////////
35
36#ifdef TRACE_GLOBAL_REFS
37    static int gGlobalRefs;
38#endif
39
40#ifdef TRACE_ARRAY_LOCKS
41    static int gLockCount;
42#endif
43
44NIOBuffer::NIOBuffer(JNIEnv* env, jobject buffer) {
45    fBuffer = env->NewGlobalRef(buffer);
46#ifdef TRACE_GLOBAL_REFS
47    SkDebugf("------------ newglobalref bbuffer %X %d\n", buffer, gGlobalRefs++);
48#endif
49    fLockedPtr = NULL;
50    fLockedArray = NULL;
51}
52
53NIOBuffer::~NIOBuffer() {
54    // free() needs to have already been called
55    if (NULL != fBuffer) {
56        SkDebugf("----- leaked fBuffer in NIOBuffer");
57        sk_throw();
58    }
59}
60
61void NIOBuffer::free(JNIEnv* env) {
62
63    if (NULL != fLockedPtr) {
64        SkDebugf("======= free: array still locked %x %p\n", fLockedArray, fLockedPtr);
65    }
66
67
68    if (NULL != fBuffer) {
69#ifdef TRACE_GLOBAL_REFS
70        SkDebugf("----------- deleteglobalref buffer %X %d\n", fBuffer, --gGlobalRefs);
71#endif
72        env->DeleteGlobalRef(fBuffer);
73        fBuffer = NULL;
74    }
75}
76
77void* NIOBuffer::lock(JNIEnv* env, int* remaining) {
78    if (NULL != fLockedPtr) {
79        SkDebugf("======= lock: array still locked %x %p\n", fLockedArray, fLockedPtr);
80    }
81
82    fLockedPtr = NULL;
83    fLockedArray = NULL;
84
85    if (NULL != remaining) {
86        *remaining = env->CallStaticIntMethod(gNIOAccess_classID,
87                                              gNIOAccess_getRemainingBytes,
88                                              fBuffer);
89        if (GraphicsJNI::hasException(env)) {
90            return NULL;
91        }
92    }
93
94    jlong pointer = env->CallStaticLongMethod(gNIOAccess_classID,
95                                              gNIOAccess_getBasePointer,
96                                              fBuffer);
97    if (GraphicsJNI::hasException(env)) {
98        return NULL;
99    }
100    if (0 != pointer) {
101        return reinterpret_cast<void*>(pointer);
102    }
103
104    fLockedArray = (jbyteArray)env->CallStaticObjectMethod(gNIOAccess_classID,
105                                                        gNIOAccess_getBaseArray,
106                                                        fBuffer);
107    if (GraphicsJNI::hasException(env) || NULL == fLockedArray) {
108        return NULL;
109    }
110    jint offset = env->CallStaticIntMethod(gNIOAccess_classID,
111                                           gNIOAccess_getBaseArrayOffset,
112                                           fBuffer);
113    fLockedPtr = env->GetByteArrayElements(fLockedArray, NULL);
114    if (GraphicsJNI::hasException(env)) {
115        SkDebugf("------------ failed to lockarray %x\n", fLockedArray);
116        return NULL;
117    }
118#ifdef TRACE_ARRAY_LOCKS
119    SkDebugf("------------ lockarray %x %p %d\n",
120             fLockedArray, fLockedPtr, gLockCount++);
121#endif
122    if (NULL == fLockedPtr) {
123        offset = 0;
124    }
125    return (char*)fLockedPtr + offset;
126}
127
128void NIOBuffer::unlock(JNIEnv* env, bool dataChanged) {
129    if (NULL != fLockedPtr) {
130#ifdef TRACE_ARRAY_LOCKS
131        SkDebugf("------------ unlockarray %x %p %d\n",
132                 fLockedArray, fLockedPtr, --gLockCount);
133#endif
134        env->ReleaseByteArrayElements(fLockedArray, (jbyte*)fLockedPtr,
135                                      dataChanged ? 0 : JNI_ABORT);
136
137        fLockedPtr = NULL;
138        fLockedArray = NULL;
139    } else {
140        SkDebugf("============= unlock called with null ptr %x\n", fLockedArray);
141    }
142}
143
144