1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_jni_Refs_h__
8 #define mozilla_jni_Refs_h__
14 #include "mozilla/fallible.h"
15 #include "mozilla/jni/Utils.h"
16 #include "mozilla/jni/TypeAdapter.h"
17 #include "nsError.h" // for nsresult
24 // Wrapped object reference (e.g. jobject, jclass, etc...)
25 template <class Cls
, typename JNIType
>
27 // Represents a calling context for JNI methods.
28 template <class Cls
, typename JNIType
>
30 // Wrapped local reference that inherits from Ref.
33 // Wrapped global reference that inherits from Ref.
36 // Wrapped weak reference that inherits from Ref.
39 // Wrapped dangling reference that's owned by someone else.
43 // Class to hold the native types of a method's arguments.
44 // For example, if a method has signature (ILjava/lang/String;)V,
45 // its arguments class would be jni::Args<int32_t, jni::String::Param>
46 template <typename
...>
51 // Base class for Ref and its specializations.
52 template <class Cls
, typename Type
>
54 template <class C
, typename T
>
57 using Self
= Ref
<Cls
, Type
>;
58 using bool_type
= void (Self::*)() const;
59 void non_null_reference() const {}
61 // A Cls-derivative that allows copying
62 // (e.g. when acting as a return value).
63 struct CopyableCtx
: public Context
<Cls
, Type
> {
64 CopyableCtx(JNIEnv
* env
, Type instance
)
65 : Context
<Cls
, Type
>(env
, instance
) {}
67 CopyableCtx(const CopyableCtx
& cls
)
68 : Context
<Cls
, Type
>(cls
.Env(), cls
.Get()) {}
71 // Private copy constructor so that there's no danger of assigning a
72 // temporary LocalRef/GlobalRef to a Ref, and potentially use the Ref
73 // after the source had been freed.
74 Ref(const Ref
&) = default;
77 static JNIEnv
* FindEnv() {
78 return Cls::callingThread
== CallingThread::GECKO
? GetGeckoThreadEnv()
84 // Protected jobject constructor because outside code should be using
85 // Ref::From. Using Ref::From makes it very easy to see which code is using
86 // raw JNI types for future refactoring.
87 explicit Ref(Type instance
) : mInstance(instance
) {}
93 friend class Ref
<Cls
, Type
>;
98 explicit AutoLock(Type aInstance
)
99 : mEnv(FindEnv()), mInstance(mEnv
->NewLocalRef(aInstance
)) {
100 mEnv
->MonitorEnter(mInstance
);
101 MOZ_CATCH_JNI_EXCEPTION(mEnv
);
105 AutoLock(AutoLock
&& aOther
)
106 : mEnv(aOther
.mEnv
), mInstance(aOther
.mInstance
) {
107 aOther
.mInstance
= nullptr;
110 ~AutoLock() { Unlock(); }
114 mEnv
->MonitorExit(mInstance
);
115 mEnv
->DeleteLocalRef(mInstance
);
116 MOZ_CATCH_JNI_EXCEPTION(mEnv
);
122 // Construct a Ref form a raw JNI reference.
123 static Ref
<Cls
, Type
> From(JNIType obj
) { return Ref
<Cls
, Type
>(obj
); }
125 // Construct a Ref form a generic object reference.
126 static Ref
<Cls
, Type
> From(const Ref
<Object
, jobject
>& obj
) {
127 return Ref
<Cls
, Type
>(JNIType(obj
.Get()));
130 MOZ_IMPLICIT
Ref(decltype(nullptr)) : mInstance(nullptr) {}
132 // Get the raw JNI reference.
133 JNIType
Get() const { return mInstance
; }
136 bool IsInstanceOf() const {
137 return FindEnv()->IsInstanceOf(mInstance
, typename
T::Context().ClassRef());
141 typename
T::Ref
Cast() const {
143 MOZ_RELEASE_ASSERT(FindEnv()->IsAssignableFrom(
144 Context
<Cls
, Type
>().ClassRef(), typename
T::Context().ClassRef()));
146 return T::Ref::From(*this);
149 AutoLock
Lock() const { return AutoLock(mInstance
); }
151 bool operator==(const Ref
& other
) const {
152 // Treat two references of the same object as being the same.
153 return mInstance
== other
.mInstance
||
154 JNI_FALSE
!= FindEnv()->IsSameObject(mInstance
, other
.mInstance
);
157 bool operator!=(const Ref
& other
) const { return !operator==(other
); }
159 bool operator==(decltype(nullptr)) const { return !mInstance
; }
161 bool operator!=(decltype(nullptr)) const { return !!mInstance
; }
163 CopyableCtx
operator->() const { return CopyableCtx(FindEnv(), mInstance
); }
165 CopyableCtx
operator*() const { return operator->(); }
167 // Any ref can be cast to an object ref.
168 operator Ref
<Object
, jobject
>() const {
169 return Ref
<Object
, jobject
>(mInstance
);
172 // Null checking (e.g. !!ref) using the safe-bool idiom.
173 operator bool_type() const {
174 return mInstance
? &Self::non_null_reference
: nullptr;
177 // We don't allow implicit conversion to jobject because that can lead
178 // to easy mistakes such as assigning a temporary LocalRef to a jobject,
179 // and using the jobject after the LocalRef has been freed.
181 // We don't allow explicit conversion, to make outside code use Ref::Get.
182 // Using Ref::Get makes it very easy to see which code is using raw JNI
183 // types to make future refactoring easier.
185 // operator JNIType() const = delete;
188 // Represents a calling context for JNI methods.
189 template <class Cls
, typename Type
>
190 class Context
: public Ref
<Cls
, Type
> {
191 using Ref
= jni::Ref
<Cls
, Type
>;
193 static jclass sClassRef
; // global reference
199 Context() : Ref(nullptr), mEnv(Ref::FindEnv()) {}
201 Context(JNIEnv
* env
, Type instance
) : Ref(instance
), mEnv(env
) {}
203 jclass
ClassRef() const {
205 const jclass cls
= GetClassRef(mEnv
, Cls::name
);
206 sClassRef
= jclass(mEnv
->NewGlobalRef(cls
));
207 mEnv
->DeleteLocalRef(cls
);
212 JNIEnv
* Env() const { return mEnv
; }
215 bool IsInstanceOf() const {
216 return mEnv
->IsInstanceOf(Ref::mInstance
,
217 typename
T::Context(mEnv
, nullptr).ClassRef());
220 bool operator==(const Ref
& other
) const {
221 // Treat two references of the same object as being the same.
222 return Ref::mInstance
== other
.Get() ||
223 JNI_FALSE
!= mEnv
->IsSameObject(Ref::mInstance
, other
.Get());
226 bool operator!=(const Ref
& other
) const { return !operator==(other
); }
228 bool operator==(decltype(nullptr)) const { return !Ref::mInstance
; }
230 bool operator!=(decltype(nullptr)) const { return !!Ref::mInstance
; }
232 Cls
operator->() const {
233 MOZ_ASSERT(Ref::mInstance
, "Null jobject");
237 const Context
<Cls
, Type
>& operator*() const { return *this; }
240 template <class C
, typename T
>
241 jclass Context
<C
, T
>::sClassRef
;
243 template <class Cls
, typename Type
= jobject
>
246 const jni::Context
<Cls
, Type
>& mCtx
;
248 jclass
ClassRef() const { return mCtx
.ClassRef(); }
249 JNIEnv
* Env() const { return mCtx
.Env(); }
250 Type
Instance() const { return mCtx
.Get(); }
253 using Ref
= jni::Ref
<Cls
, Type
>;
254 using Context
= jni::Context
<Cls
, Type
>;
255 using LocalRef
= jni::LocalRef
<Cls
>;
256 using GlobalRef
= jni::GlobalRef
<Cls
>;
257 using WeakRef
= jni::WeakRef
<Cls
>;
258 using Param
= const Ref
&;
260 static const CallingThread callingThread
= CallingThread::ANY
;
261 static const char name
[];
263 explicit ObjectBase(const Context
& ctx
) : mCtx(ctx
) {}
265 Cls
* operator->() { return static_cast<Cls
*>(this); }
268 // Binding for a plain jobject.
269 class Object
: public ObjectBase
<Object
, jobject
> {
271 explicit Object(const Context
& ctx
) : ObjectBase
<Object
, jobject
>(ctx
) {}
274 // Binding for a built-in object reference other than jobject.
275 template <typename T
>
276 class TypedObject
: public ObjectBase
<TypedObject
<T
>, T
> {
278 explicit TypedObject(const Context
<TypedObject
<T
>, T
>& ctx
)
279 : ObjectBase
<TypedObject
<T
>, T
>(ctx
) {}
282 // Binding for a boxed primitive object.
283 template <typename T
>
284 class BoxedObject
: public ObjectBase
<BoxedObject
<T
>, jobject
> {
286 explicit BoxedObject(const Context
<BoxedObject
<T
>, jobject
>& ctx
)
287 : ObjectBase
<BoxedObject
<T
>, jobject
>(ctx
) {}
291 const char ObjectBase
<Object
, jobject
>::name
[];
293 const char ObjectBase
<TypedObject
<jstring
>, jstring
>::name
[];
295 const char ObjectBase
<TypedObject
<jclass
>, jclass
>::name
[];
297 const char ObjectBase
<TypedObject
<jthrowable
>, jthrowable
>::name
[];
299 const char ObjectBase
<BoxedObject
<jboolean
>, jobject
>::name
[];
301 const char ObjectBase
<BoxedObject
<jbyte
>, jobject
>::name
[];
303 const char ObjectBase
<BoxedObject
<jchar
>, jobject
>::name
[];
305 const char ObjectBase
<BoxedObject
<jshort
>, jobject
>::name
[];
307 const char ObjectBase
<BoxedObject
<jint
>, jobject
>::name
[];
309 const char ObjectBase
<BoxedObject
<jlong
>, jobject
>::name
[];
311 const char ObjectBase
<BoxedObject
<jfloat
>, jobject
>::name
[];
313 const char ObjectBase
<BoxedObject
<jdouble
>, jobject
>::name
[];
315 const char ObjectBase
<TypedObject
<jbooleanArray
>, jbooleanArray
>::name
[];
317 const char ObjectBase
<TypedObject
<jbyteArray
>, jbyteArray
>::name
[];
319 const char ObjectBase
<TypedObject
<jcharArray
>, jcharArray
>::name
[];
321 const char ObjectBase
<TypedObject
<jshortArray
>, jshortArray
>::name
[];
323 const char ObjectBase
<TypedObject
<jintArray
>, jintArray
>::name
[];
325 const char ObjectBase
<TypedObject
<jlongArray
>, jlongArray
>::name
[];
327 const char ObjectBase
<TypedObject
<jfloatArray
>, jfloatArray
>::name
[];
329 const char ObjectBase
<TypedObject
<jdoubleArray
>, jdoubleArray
>::name
[];
331 const char ObjectBase
<TypedObject
<jobjectArray
>, jobjectArray
>::name
[];
333 // Define bindings for built-in types.
334 using String
= TypedObject
<jstring
>;
335 using Class
= TypedObject
<jclass
>;
336 using Throwable
= TypedObject
<jthrowable
>;
338 using Boolean
= BoxedObject
<jboolean
>;
339 using Byte
= BoxedObject
<jbyte
>;
340 using Character
= BoxedObject
<jchar
>;
341 using Short
= BoxedObject
<jshort
>;
342 using Integer
= BoxedObject
<jint
>;
343 using Long
= BoxedObject
<jlong
>;
344 using Float
= BoxedObject
<jfloat
>;
345 using Double
= BoxedObject
<jdouble
>;
347 using BooleanArray
= TypedObject
<jbooleanArray
>;
348 using ByteArray
= TypedObject
<jbyteArray
>;
349 using CharArray
= TypedObject
<jcharArray
>;
350 using ShortArray
= TypedObject
<jshortArray
>;
351 using IntArray
= TypedObject
<jintArray
>;
352 using LongArray
= TypedObject
<jlongArray
>;
353 using FloatArray
= TypedObject
<jfloatArray
>;
354 using DoubleArray
= TypedObject
<jdoubleArray
>;
355 using ObjectArray
= TypedObject
<jobjectArray
>;
359 // See explanation in LocalRef.
361 struct GenericObject
{
365 struct GenericObject
<Object
> {
367 using Ref
= jni::Ref
<Type
, jobject
>;
368 using Context
= jni::Context
<Type
, jobject
>;
372 struct GenericLocalRef
{
374 struct Type
: jni::Object
{};
377 struct GenericLocalRef
<Object
> {
379 using Type
= jni::LocalRef
<C
>;
382 } // namespace detail
385 class LocalRef
: public Cls::Context
{
387 friend class LocalRef
;
389 using Ctx
= typename
Cls::Context
;
390 using Ref
= typename
Cls::Ref
;
391 using JNIType
= typename
Ref::JNIType
;
393 // In order to be able to convert LocalRef<Object> to LocalRef<Cls>, we
394 // need constructors and copy assignment operators that take in a
395 // LocalRef<Object> argument. However, if Cls *is* Object, we would have
396 // duplicated constructors and operators with LocalRef<Object> arguments. To
397 // avoid this conflict, we use GenericObject, which is defined as Object for
398 // LocalRef<non-Object> and defined as a dummy class for LocalRef<Object>.
399 using GenericObject
= typename
detail::GenericObject
<Cls
>::Type
;
401 // Similarly, GenericLocalRef is useed to convert LocalRef<Cls> to,
402 // LocalRef<Object>. It's defined as LocalRef<C> for Cls == Object,
403 // and defined as a dummy template class for Cls != Object.
405 using GenericLocalRef
=
406 typename
detail::GenericLocalRef
<Cls
>::template Type
<C
>;
408 static JNIType
NewLocalRef(JNIEnv
* env
, JNIType obj
) {
409 return JNIType(obj
? env
->NewLocalRef(obj
) : nullptr);
412 LocalRef(JNIEnv
* env
, JNIType instance
) : Ctx(env
, instance
) {}
414 LocalRef
& swap(LocalRef
& other
) {
415 auto instance
= other
.mInstance
;
416 other
.mInstance
= Ctx::mInstance
;
417 Ctx::mInstance
= instance
;
422 // Construct a LocalRef from a raw JNI local reference. Unlike Ref::From,
423 // LocalRef::Adopt returns a LocalRef that will delete the local reference
424 // when going out of scope.
425 static LocalRef
Adopt(JNIType instance
) {
426 return LocalRef(Ref::FindEnv(), instance
);
429 static LocalRef
Adopt(JNIEnv
* env
, JNIType instance
) {
430 return LocalRef(env
, instance
);
434 LocalRef(const LocalRef
<Cls
>& ref
)
435 : Ctx(ref
.mEnv
, NewLocalRef(ref
.mEnv
, ref
.mInstance
)) {}
438 LocalRef(LocalRef
<Cls
>&& ref
) : Ctx(ref
.mEnv
, ref
.mInstance
) {
439 ref
.mInstance
= nullptr;
442 explicit LocalRef(JNIEnv
* env
= Ref::FindEnv()) : Ctx(env
, nullptr) {}
444 // Construct a LocalRef from any Ref,
445 // which means creating a new local reference.
446 MOZ_IMPLICIT
LocalRef(const Ref
& ref
) : Ctx(Ref::FindEnv(), nullptr) {
447 Ctx::mInstance
= NewLocalRef(Ctx::mEnv
, ref
.Get());
450 LocalRef(JNIEnv
* env
, const Ref
& ref
)
451 : Ctx(env
, NewLocalRef(env
, ref
.Get())) {}
453 // Move a LocalRef<Object> into a LocalRef<Cls> without
454 // creating/deleting local references.
455 MOZ_IMPLICIT
LocalRef(LocalRef
<GenericObject
>&& ref
)
456 : Ctx(ref
.mEnv
, JNIType(ref
.mInstance
)) {
457 ref
.mInstance
= nullptr;
461 MOZ_IMPLICIT
LocalRef(GenericLocalRef
<C
>&& ref
)
462 : Ctx(ref
.mEnv
, ref
.mInstance
) {
463 ref
.mInstance
= nullptr;
466 // Implicitly converts nullptr to LocalRef.
467 MOZ_IMPLICIT
LocalRef(decltype(nullptr)) : Ctx(Ref::FindEnv(), nullptr) {}
470 if (Ctx::mInstance
) {
471 Ctx::mEnv
->DeleteLocalRef(Ctx::mInstance
);
472 Ctx::mInstance
= nullptr;
476 // Get the raw JNI reference that can be used as a return value.
477 // Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref.
478 typename
Ref::JNIType
Forget() {
479 const auto obj
= Ctx::Get();
480 Ctx::mInstance
= nullptr;
484 LocalRef
<Cls
>& operator=(LocalRef
<Cls
> ref
) & { return swap(ref
); }
486 LocalRef
<Cls
>& operator=(const Ref
& ref
) & {
487 LocalRef
<Cls
> newRef(Ctx::mEnv
, ref
);
491 LocalRef
<Cls
>& operator=(LocalRef
<GenericObject
>&& ref
) & {
492 LocalRef
<Cls
> newRef(std::move(ref
));
497 LocalRef
<Cls
>& operator=(GenericLocalRef
<C
>&& ref
) & {
498 LocalRef
<Cls
> newRef(std::move(ref
));
502 LocalRef
<Cls
>& operator=(decltype(nullptr)) & {
503 LocalRef
<Cls
> newRef(Ctx::mEnv
, nullptr);
509 class GlobalRef
: public Cls::Ref
{
510 using Ref
= typename
Cls::Ref
;
511 using JNIType
= typename
Ref::JNIType
;
513 static JNIType
NewGlobalRef(JNIEnv
* env
, JNIType instance
) {
514 return JNIType(instance
? env
->NewGlobalRef(instance
) : nullptr);
517 GlobalRef
& swap(GlobalRef
& other
) {
518 auto instance
= other
.mInstance
;
519 other
.mInstance
= Ref::mInstance
;
520 Ref::mInstance
= instance
;
525 GlobalRef() : Ref(nullptr) {}
528 GlobalRef(const GlobalRef
& ref
)
529 : Ref(NewGlobalRef(GetEnvForThread(), ref
.mInstance
)) {}
532 GlobalRef(GlobalRef
&& ref
) : Ref(ref
.mInstance
) { ref
.mInstance
= nullptr; }
534 MOZ_IMPLICIT
GlobalRef(const Ref
& ref
)
535 : Ref(NewGlobalRef(GetEnvForThread(), ref
.Get())) {}
537 GlobalRef(JNIEnv
* env
, const Ref
& ref
) : Ref(NewGlobalRef(env
, ref
.Get())) {}
539 MOZ_IMPLICIT
GlobalRef(const LocalRef
<Cls
>& ref
)
540 : Ref(NewGlobalRef(ref
.Env(), ref
.Get())) {}
542 // Implicitly converts nullptr to GlobalRef.
543 MOZ_IMPLICIT
GlobalRef(decltype(nullptr)) : Ref(nullptr) {}
546 if (Ref::mInstance
) {
547 Clear(GetEnvForThread());
551 // Get the raw JNI reference that can be used as a return value.
552 // Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref.
553 typename
Ref::JNIType
Forget() {
554 const auto obj
= Ref::Get();
555 Ref::mInstance
= nullptr;
559 void Clear(JNIEnv
* env
) {
560 if (Ref::mInstance
) {
561 env
->DeleteGlobalRef(Ref::mInstance
);
562 Ref::mInstance
= nullptr;
566 GlobalRef
<Cls
>& operator=(GlobalRef
<Cls
> ref
) & { return swap(ref
); }
568 GlobalRef
<Cls
>& operator=(const Ref
& ref
) & {
569 GlobalRef
<Cls
> newRef(ref
);
573 GlobalRef
<Cls
>& operator=(const LocalRef
<Cls
>& ref
) & {
574 GlobalRef
<Cls
> newRef(ref
);
578 GlobalRef
<Cls
>& operator=(decltype(nullptr)) & {
579 GlobalRef
<Cls
> newRef(nullptr);
585 class WeakRef
: public Ref
<Cls
, jweak
> {
586 using Ref
= Ref
<Cls
, jweak
>;
587 using JNIType
= typename
Ref::JNIType
;
589 static JNIType
NewWeakRef(JNIEnv
* env
, JNIType instance
) {
590 return JNIType(instance
? env
->NewWeakGlobalRef(instance
) : nullptr);
593 WeakRef
& swap(WeakRef
& other
) {
594 auto instance
= other
.mInstance
;
595 other
.mInstance
= Ref::mInstance
;
596 Ref::mInstance
= instance
;
601 WeakRef() : Ref(nullptr) {}
604 WeakRef(const WeakRef
& ref
)
605 : Ref(NewWeakRef(GetEnvForThread(), ref
.mInstance
)) {}
608 WeakRef(WeakRef
&& ref
) : Ref(ref
.mInstance
) { ref
.mInstance
= nullptr; }
610 MOZ_IMPLICIT
WeakRef(const Ref
& ref
)
611 : Ref(NewWeakRef(GetEnvForThread(), ref
.Get())) {}
613 WeakRef(JNIEnv
* env
, const Ref
& ref
) : Ref(NewWeakRef(env
, ref
.Get())) {}
615 MOZ_IMPLICIT
WeakRef(const LocalRef
<Cls
>& ref
)
616 : Ref(NewWeakRef(ref
.Env(), ref
.Get())) {}
618 // Implicitly converts nullptr to WeakRef.
619 MOZ_IMPLICIT
WeakRef(decltype(nullptr)) : Ref(nullptr) {}
622 if (Ref::mInstance
) {
623 Clear(GetEnvForThread());
627 // Get the raw JNI reference that can be used as a return value.
628 // Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref.
629 typename
Ref::JNIType
Forget() {
630 const auto obj
= Ref::Get();
631 Ref::mInstance
= nullptr;
635 void Clear(JNIEnv
* env
) {
636 if (Ref::mInstance
) {
637 env
->DeleteWeakGlobalRef(Ref::mInstance
);
638 Ref::mInstance
= nullptr;
642 WeakRef
<Cls
>& operator=(WeakRef
<Cls
> ref
) & { return swap(ref
); }
644 WeakRef
<Cls
>& operator=(const Ref
& ref
) & {
645 WeakRef
<Cls
> newRef(ref
);
649 WeakRef
<Cls
>& operator=(const LocalRef
<Cls
>& ref
) & {
650 WeakRef
<Cls
> newRef(ref
);
654 WeakRef
<Cls
>& operator=(decltype(nullptr)) & {
655 WeakRef
<Cls
> newRef(nullptr);
659 void operator->() const = delete;
660 void operator*() const = delete;
664 class DependentRef
: public Cls::Ref
{
665 using Ref
= typename
Cls::Ref
;
668 explicit DependentRef(typename
Ref::JNIType instance
) : Ref(instance
) {}
670 DependentRef(const DependentRef
& ref
) : Ref(ref
.Get()) {}
676 class TypedObject
<jstring
> : public ObjectBase
<TypedObject
<jstring
>, jstring
> {
677 using Base
= ObjectBase
<TypedObject
<jstring
>, jstring
>;
680 using Param
= const StringParam
&;
682 explicit TypedObject(const Context
& ctx
) : Base(ctx
) {}
684 size_t Length() const {
685 const size_t ret
= Base::Env()->GetStringLength(Base::Instance());
686 MOZ_CATCH_JNI_EXCEPTION(Base::Env());
690 nsString
ToString() const {
691 const jchar
* const str
=
692 Base::Env()->GetStringChars(Base::Instance(), nullptr);
693 const jsize len
= Base::Env()->GetStringLength(Base::Instance());
695 nsString
result(reinterpret_cast<const char16_t
*>(str
), len
);
696 Base::Env()->ReleaseStringChars(Base::Instance(), str
);
700 nsCString
ToCString() const { return NS_ConvertUTF16toUTF8(ToString()); }
702 // Convert jstring to a nsString.
703 operator nsString() const { return ToString(); }
705 // Convert jstring to a nsCString.
706 operator nsCString() const { return ToCString(); }
709 // Define a custom parameter type for String,
710 // which accepts both String::Ref and nsAString/nsACString
711 class StringParam
: public String::Ref
{
712 using Ref
= String::Ref
;
715 // Not null if we should delete ref on destruction.
718 static jstring
GetString(JNIEnv
* env
, const nsAString
& str
) {
719 const jstring result
= env
->NewString(
720 reinterpret_cast<const jchar
*>(str
.BeginReading()), str
.Length());
722 NS_ABORT_OOM(str
.Length() * sizeof(char16_t
));
724 MOZ_CATCH_JNI_EXCEPTION(env
);
728 static jstring
GetString(JNIEnv
* env
, const nsAString
& str
,
730 const jstring result
= env
->NewString(
731 reinterpret_cast<const jchar
*>(str
.BeginReading()), str
.Length());
732 if (env
->ExceptionCheck()) {
734 env
->ExceptionDescribe();
736 env
->ExceptionClear();
741 static jstring
GetString(JNIEnv
* env
, const nsACString
& str
,
742 const fallible_t
& aFallible
) {
744 if (!CopyUTF8toUTF16(str
, utf16
, aFallible
)) {
747 return GetString(env
, utf16
, aFallible
);
751 MOZ_IMPLICIT
StringParam(decltype(nullptr)) : Ref(nullptr), mEnv(nullptr) {}
753 MOZ_IMPLICIT
StringParam(const Ref
& ref
) : Ref(ref
.Get()), mEnv(nullptr) {}
755 MOZ_IMPLICIT
StringParam(const nsAString
& str
, JNIEnv
* env
= Ref::FindEnv())
756 : Ref(GetString(env
, str
)), mEnv(env
) {}
758 MOZ_IMPLICIT
StringParam(const nsAString
& str
, JNIEnv
* env
,
759 const fallible_t
& aFallible
)
760 : Ref(GetString(env
, str
, aFallible
)), mEnv(env
) {}
762 MOZ_IMPLICIT
StringParam(const nsLiteralString
& str
,
763 JNIEnv
* env
= Ref::FindEnv())
764 : Ref(GetString(env
, str
)), mEnv(env
) {}
766 MOZ_IMPLICIT
StringParam(const char16_t
* str
, JNIEnv
* env
= Ref::FindEnv())
767 : Ref(GetString(env
, nsDependentString(str
))), mEnv(env
) {}
769 MOZ_IMPLICIT
StringParam(const nsACString
& str
, JNIEnv
* env
= Ref::FindEnv())
770 : Ref(GetString(env
, NS_ConvertUTF8toUTF16(str
))), mEnv(env
) {}
772 MOZ_IMPLICIT
StringParam(const nsACString
& str
, JNIEnv
* env
,
773 const fallible_t
& aFallible
)
774 : Ref(GetString(env
, str
, aFallible
)), mEnv(env
) {}
776 MOZ_IMPLICIT
StringParam(const nsLiteralCString
& str
,
777 JNIEnv
* env
= Ref::FindEnv())
778 : Ref(GetString(env
, NS_ConvertUTF8toUTF16(str
))), mEnv(env
) {}
780 MOZ_IMPLICIT
StringParam(const char* str
, JNIEnv
* env
= Ref::FindEnv())
781 : Ref(GetString(env
, NS_ConvertUTF8toUTF16(str
))), mEnv(env
) {}
783 StringParam(StringParam
&& other
) : Ref(other
.Get()), mEnv(other
.mEnv
) {
784 other
.mInstance
= nullptr;
789 mEnv
->DeleteLocalRef(Get());
793 operator String::LocalRef() const {
794 // We can't return our existing ref because the returned
795 // LocalRef could be freed first, so we need a new local ref.
796 return String::LocalRef(mEnv
? mEnv
: Ref::FindEnv(), *this);
801 template <typename T
>
805 // Ref specialization for arrays.
806 template <typename JNIType
, class ElementType
>
807 class ArrayRefBase
: public ObjectBase
<TypedObject
<JNIType
>, JNIType
> {
809 using Base
= ObjectBase
<TypedObject
<JNIType
>, JNIType
>;
812 explicit ArrayRefBase(const Context
<TypedObject
<JNIType
>, JNIType
>& ctx
)
815 static typename
Base::LocalRef
New(const ElementType
* data
, size_t length
) {
816 using JNIElemType
= typename
detail::TypeAdapter
<ElementType
>::JNIType
;
817 static_assert(sizeof(ElementType
) == sizeof(JNIElemType
),
818 "Size of native type must match size of JNI type");
819 JNIEnv
* const jenv
= mozilla::jni::GetEnvForThread();
820 auto result
= (jenv
->*detail::TypeAdapter
<ElementType
>::NewArray
)(length
);
821 MOZ_CATCH_JNI_EXCEPTION(jenv
);
822 (jenv
->*detail::TypeAdapter
<ElementType
>::SetArray
)(
823 result
, jsize(0), length
, reinterpret_cast<const JNIElemType
*>(data
));
824 MOZ_CATCH_JNI_EXCEPTION(jenv
);
825 return Base::LocalRef::Adopt(jenv
, result
);
828 static typename
Base::LocalRef
New(const ElementType
* data
, size_t length
,
830 using JNIElemType
= typename
detail::TypeAdapter
<ElementType
>::JNIType
;
831 static_assert(sizeof(ElementType
) == sizeof(JNIElemType
),
832 "Size of native type must match size of JNI type");
833 JNIEnv
* const jenv
= mozilla::jni::GetEnvForThread();
834 auto result
= (jenv
->*detail::TypeAdapter
<ElementType
>::NewArray
)(length
);
835 if (jenv
->ExceptionCheck()) {
836 if (!IsOOMException(jenv
)) {
837 // This exception isn't excepted due not to OOM. This is unrecoverable
839 MOZ_CATCH_JNI_EXCEPTION(jenv
);
842 jenv
->ExceptionDescribe();
844 jenv
->ExceptionClear();
845 return Base::LocalRef::Adopt(jenv
, nullptr);
847 (jenv
->*detail::TypeAdapter
<ElementType
>::SetArray
)(
848 result
, jsize(0), length
, reinterpret_cast<const JNIElemType
*>(data
));
849 if (jenv
->ExceptionCheck()) {
850 if (!IsOOMException(jenv
)) {
851 // This exception isn't excepted due not to OOM. This is unrecoverable
853 MOZ_CATCH_JNI_EXCEPTION(jenv
);
856 jenv
->ExceptionDescribe();
858 jenv
->ExceptionClear();
859 jenv
->DeleteLocalRef(result
);
860 return Base::LocalRef::Adopt(jenv
, nullptr);
862 return Base::LocalRef::Adopt(jenv
, result
);
865 size_t Length() const {
866 const size_t ret
= Base::Env()->GetArrayLength(Base::Instance());
867 MOZ_CATCH_JNI_EXCEPTION(Base::Env());
871 ElementType
GetElement(size_t index
) const {
872 using JNIElemType
= typename
detail::TypeAdapter
<ElementType
>::JNIType
;
873 static_assert(sizeof(ElementType
) == sizeof(JNIElemType
),
874 "Size of native type must match size of JNI type");
877 (Base::Env()->*detail::TypeAdapter
<ElementType
>::GetArray
)(
878 Base::Instance(), jsize(index
), 1,
879 reinterpret_cast<JNIElemType
*>(&ret
));
880 MOZ_CATCH_JNI_EXCEPTION(Base::Env());
884 nsTArray
<ElementType
> GetElements() const {
885 using JNIElemType
= typename
detail::TypeAdapter
<ElementType
>::JNIType
;
886 static_assert(sizeof(ElementType
) == sizeof(JNIElemType
),
887 "Size of native type must match size of JNI type");
889 const size_t len
= size_t(Base::Env()->GetArrayLength(Base::Instance()));
891 nsTArray
<ElementType
> array(len
);
892 array
.SetLength(len
);
893 CopyTo(array
.Elements(), len
);
897 // returns number of elements copied
898 size_t CopyTo(ElementType
* buffer
, size_t size
) const {
899 using JNIElemType
= typename
detail::TypeAdapter
<ElementType
>::JNIType
;
900 static_assert(sizeof(ElementType
) == sizeof(JNIElemType
),
901 "Size of native type must match size of JNI type");
903 const size_t len
= size_t(Base::Env()->GetArrayLength(Base::Instance()));
904 const size_t amountToCopy
= (len
> size
? size
: len
);
905 (Base::Env()->*detail::TypeAdapter
<ElementType
>::GetArray
)(
906 Base::Instance(), 0, jsize(amountToCopy
),
907 reinterpret_cast<JNIElemType
*>(buffer
));
911 ElementType
operator[](size_t index
) const { return GetElement(index
); }
913 operator nsTArray
<ElementType
>() const { return GetElements(); }
916 #define DEFINE_PRIMITIVE_ARRAY_REF_HEADER(JNIType, ElementType) \
918 class TypedObject<JNIType> : public ArrayRefBase<JNIType, ElementType> { \
920 explicit TypedObject(const Context& ctx) \
921 : ArrayRefBase<JNIType, ElementType>(ctx) {} \
922 static typename Base::LocalRef From(const nsTArray<ElementType>& aArray) { \
923 return New(aArray.Elements(), aArray.Length()); \
926 #define DEFINE_PRIMITIVE_ARRAY_REF_FOOTER }
928 #define DEFINE_PRIMITIVE_ARRAY_REF_FROM_IMPLICIT_CONVERSION(ElementType, \
930 static typename Base::LocalRef From( \
931 const nsTArray<ConvertFromType>& aArray) { \
932 return New(reinterpret_cast<const ElementType*>(aArray.Elements()), \
936 #define DEFINE_PRIMITIVE_ARRAY_REF(JNIType, ElementType) \
937 DEFINE_PRIMITIVE_ARRAY_REF_HEADER(JNIType, ElementType) \
938 DEFINE_PRIMITIVE_ARRAY_REF_FOOTER
940 #define DEFINE_PRIMITIVE_ARRAY_REF_WITH_IMPLICIT_CONVERSION( \
941 JNIType, ElementType, ConvertFromType) \
942 DEFINE_PRIMITIVE_ARRAY_REF_HEADER(JNIType, ElementType) \
943 DEFINE_PRIMITIVE_ARRAY_REF_FROM_IMPLICIT_CONVERSION(ElementType, \
945 DEFINE_PRIMITIVE_ARRAY_REF_FOOTER
947 DEFINE_PRIMITIVE_ARRAY_REF(jbooleanArray
, bool);
948 DEFINE_PRIMITIVE_ARRAY_REF_WITH_IMPLICIT_CONVERSION(jbyteArray
, int8_t,
950 DEFINE_PRIMITIVE_ARRAY_REF(jcharArray
, char16_t
);
951 DEFINE_PRIMITIVE_ARRAY_REF_WITH_IMPLICIT_CONVERSION(jshortArray
, int16_t,
953 DEFINE_PRIMITIVE_ARRAY_REF_WITH_IMPLICIT_CONVERSION(jintArray
, int32_t,
955 DEFINE_PRIMITIVE_ARRAY_REF(jfloatArray
, float);
956 DEFINE_PRIMITIVE_ARRAY_REF_WITH_IMPLICIT_CONVERSION(jlongArray
, int64_t,
958 DEFINE_PRIMITIVE_ARRAY_REF(jdoubleArray
, double);
960 #undef DEFINE_PRIMITIVE_ARRAY_REF
961 #undef DEFINE_PRIMITIVE_ARRAY_REF_WITH_IMPLICIT_CONVERSION
962 #undef DEFINE_PRIMITIVE_ARRAY_HEADER
963 #undef DEFINE_PRIMITIVE_ARRAY_FROM_IMPLICIT_CONVERSION
964 #undef DEFINE_PRIMITIVE_ARRAY_FOOTER
966 class ByteBuffer
: public ObjectBase
<ByteBuffer
, jobject
> {
968 explicit ByteBuffer(const Context
& ctx
)
969 : ObjectBase
<ByteBuffer
, jobject
>(ctx
) {}
971 static LocalRef
New(void* data
, size_t capacity
) {
972 JNIEnv
* const env
= GetEnvForThread();
974 LocalRef::Adopt(env
, env
->NewDirectByteBuffer(data
, jlong(capacity
)));
975 MOZ_CATCH_JNI_EXCEPTION(env
);
980 void* const ret
= Env()->GetDirectBufferAddress(Instance());
981 MOZ_CATCH_JNI_EXCEPTION(Env());
986 const size_t ret
= size_t(Env()->GetDirectBufferCapacity(Instance()));
987 MOZ_CATCH_JNI_EXCEPTION(Env());
993 const char ObjectBase
<ByteBuffer
, jobject
>::name
[];
996 class TypedObject
<jobjectArray
>
997 : public ObjectBase
<TypedObject
<jobjectArray
>, jobjectArray
> {
998 using Base
= ObjectBase
<TypedObject
<jobjectArray
>, jobjectArray
>;
1001 template <class Cls
= Object
>
1002 static Base::LocalRef
New(size_t length
,
1003 typename
Cls::Param initialElement
= nullptr) {
1004 JNIEnv
* const env
= GetEnvForThread();
1005 jobjectArray array
= env
->NewObjectArray(
1006 jsize(length
), typename
Cls::Context(env
, nullptr).ClassRef(),
1007 initialElement
.Get());
1008 MOZ_CATCH_JNI_EXCEPTION(env
);
1009 return Base::LocalRef::Adopt(env
, array
);
1012 explicit TypedObject(const Context
& ctx
) : Base(ctx
) {}
1014 size_t Length() const {
1015 const size_t ret
= Base::Env()->GetArrayLength(Base::Instance());
1016 MOZ_CATCH_JNI_EXCEPTION(Base::Env());
1020 Object::LocalRef
GetElement(size_t index
) const {
1021 auto ret
= Object::LocalRef::Adopt(
1023 Base::Env()->GetObjectArrayElement(Base::Instance(), jsize(index
)));
1024 MOZ_CATCH_JNI_EXCEPTION(Base::Env());
1028 nsTArray
<Object::LocalRef
> GetElements() const {
1029 const jsize len
= size_t(Base::Env()->GetArrayLength(Base::Instance()));
1031 nsTArray
<Object::LocalRef
> array((size_t(len
)));
1032 for (jsize i
= 0; i
< len
; i
++) {
1033 array
.AppendElement(Object::LocalRef::Adopt(
1035 Base::Env()->GetObjectArrayElement(Base::Instance(), i
)));
1036 MOZ_CATCH_JNI_EXCEPTION(Base::Env());
1041 Object::LocalRef
operator[](size_t index
) const { return GetElement(index
); }
1043 operator nsTArray
<Object::LocalRef
>() const { return GetElements(); }
1045 void SetElement(size_t index
, Object::Param element
) const {
1046 Base::Env()->SetObjectArrayElement(Base::Instance(), jsize(index
),
1048 MOZ_CATCH_JNI_EXCEPTION(Base::Env());
1052 // Support conversion from LocalRef<T>* to LocalRef<Object>*:
1053 // LocalRef<Foo> foo;
1054 // Foo::GetFoo(&foo); // error because parameter type is LocalRef<Object>*.
1055 // Foo::GetFoo(ReturnTo(&foo)); // OK because ReturnTo converts the argument.
1056 template <class Cls
>
1057 class ReturnToLocal
{
1059 LocalRef
<Cls
>* const localRef
;
1060 LocalRef
<Object
> objRef
;
1063 explicit ReturnToLocal(LocalRef
<Cls
>* ref
) : localRef(ref
) {}
1064 operator LocalRef
<Object
>*() { return &objRef
; }
1068 *localRef
= std::move(objRef
);
1073 template <class Cls
>
1074 ReturnToLocal
<Cls
> ReturnTo(LocalRef
<Cls
>* ref
) {
1075 return ReturnToLocal
<Cls
>(ref
);
1078 // Support conversion from GlobalRef<T>* to LocalRef<Object/T>*:
1079 // GlobalRef<Foo> foo;
1080 // Foo::GetFoo(&foo); // error because parameter type is LocalRef<Foo>*.
1081 // Foo::GetFoo(ReturnTo(&foo)); // OK because ReturnTo converts the argument.
1082 template <class Cls
>
1083 class ReturnToGlobal
{
1085 GlobalRef
<Cls
>* const globalRef
;
1086 LocalRef
<Object
> objRef
;
1087 LocalRef
<Cls
> clsRef
;
1090 explicit ReturnToGlobal(GlobalRef
<Cls
>* ref
) : globalRef(ref
) {}
1091 operator LocalRef
<Object
>*() { return &objRef
; }
1092 operator LocalRef
<Cls
>*() { return &clsRef
; }
1096 *globalRef
= (clsRef
= std::move(objRef
));
1097 } else if (clsRef
) {
1098 *globalRef
= clsRef
;
1103 template <class Cls
>
1104 ReturnToGlobal
<Cls
> ReturnTo(GlobalRef
<Cls
>* ref
) {
1105 return ReturnToGlobal
<Cls
>(ref
);
1108 // Make a LocalRef<T> from any other Ref<T>
1109 template <typename Cls
, typename JNIType
>
1110 LocalRef
<Cls
> ToLocalRef(const Ref
<Cls
, JNIType
>& aRef
) {
1111 return LocalRef
<Cls
>(aRef
);
1115 } // namespace mozilla
1117 #endif // mozilla_jni_Refs_h__