1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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 #pragma once
18
19 #include <atomic>
20 #include <cassert>
21 #include <new>
22
23 #include <fbjni/detail/FbjniApi.h>
24 #include "Environment.h"
25
26 namespace facebook {
27 namespace jni {
28
29 /// @cond INTERNAL
30 namespace internal {
31
32 // Statistics mostly provided for test (only updated if FBJNI_DEBUG_REFS is
33 // defined)
34 struct ReferenceStats {
35 std::atomic_uint locals_created, globals_created, weaks_created,
36 locals_deleted, globals_deleted, weaks_deleted;
37
38 void reset() noexcept;
39 };
40
41 extern FBJNI_API ReferenceStats g_reference_stats;
42 } // namespace internal
43 /// @endcond
44
45 // LocalReferenceAllocator
46 // /////////////////////////////////////////////////////////////////////////
47
newReference(jobject original)48 inline jobject LocalReferenceAllocator::newReference(jobject original) const {
49 internal::dbglog("Local new: %p", original);
50 #ifdef FBJNI_DEBUG_REFS
51 ++internal::g_reference_stats.locals_created;
52 #endif
53 auto ref = Environment::current()->NewLocalRef(original);
54 FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
55 return ref;
56 }
57
deleteReference(jobject reference)58 inline void LocalReferenceAllocator::deleteReference(
59 jobject reference) const noexcept {
60 internal::dbglog("Local release: %p", reference);
61
62 if (reference) {
63 #ifdef FBJNI_DEBUG_REFS
64 ++internal::g_reference_stats.locals_deleted;
65 #endif
66 assert(verifyReference(reference));
67 Environment::current()->DeleteLocalRef(reference);
68 }
69 }
70
verifyReference(jobject reference)71 inline bool LocalReferenceAllocator::verifyReference(
72 jobject reference) const noexcept {
73 return isObjectRefType(reference, JNILocalRefType);
74 }
75
76 // GlobalReferenceAllocator
77 // ////////////////////////////////////////////////////////////////////////
78
newReference(jobject original)79 inline jobject GlobalReferenceAllocator::newReference(jobject original) const {
80 internal::dbglog("Global new: %p", original);
81 #ifdef FBJNI_DEBUG_REFS
82 ++internal::g_reference_stats.globals_created;
83 #endif
84 auto ref = Environment::current()->NewGlobalRef(original);
85 FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
86 return ref;
87 }
88
deleteReference(jobject reference)89 inline void GlobalReferenceAllocator::deleteReference(
90 jobject reference) const noexcept {
91 internal::dbglog("Global release: %p", reference);
92
93 if (reference) {
94 #ifdef FBJNI_DEBUG_REFS
95 ++internal::g_reference_stats.globals_deleted;
96 #endif
97 assert(verifyReference(reference));
98 Environment::current()->DeleteGlobalRef(reference);
99 }
100 }
101
verifyReference(jobject reference)102 inline bool GlobalReferenceAllocator::verifyReference(
103 jobject reference) const noexcept {
104 return isObjectRefType(reference, JNIGlobalRefType);
105 }
106
107 // WeakGlobalReferenceAllocator
108 // ////////////////////////////////////////////////////////////////////
109
newReference(jobject original)110 inline jobject WeakGlobalReferenceAllocator::newReference(
111 jobject original) const {
112 internal::dbglog("Weak global new: %p", original);
113 #ifdef FBJNI_DEBUG_REFS
114 ++internal::g_reference_stats.weaks_created;
115 #endif
116 auto ref = Environment::current()->NewWeakGlobalRef(original);
117 FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
118 return ref;
119 }
120
deleteReference(jobject reference)121 inline void WeakGlobalReferenceAllocator::deleteReference(
122 jobject reference) const noexcept {
123 internal::dbglog("Weak Global release: %p", reference);
124
125 if (reference) {
126 #ifdef FBJNI_DEBUG_REFS
127 ++internal::g_reference_stats.weaks_deleted;
128 #endif
129 assert(verifyReference(reference));
130 Environment::current()->DeleteWeakGlobalRef(reference);
131 }
132 }
133
verifyReference(jobject reference)134 inline bool WeakGlobalReferenceAllocator::verifyReference(
135 jobject reference) const noexcept {
136 return isObjectRefType(reference, JNIWeakGlobalRefType);
137 }
138
139 } // namespace jni
140 } // namespace facebook
141