xref: /aosp_15_r20/external/fbjni/cxx/fbjni/detail/CoreClasses-inl.h (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
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 <stdlib.h>
20 #include <string.h>
21 #include <type_traits>
22 
23 #include "Common.h"
24 #include "Exceptions.h"
25 #include "Meta.h"
26 #include "MetaConvert.h"
27 
28 namespace facebook {
29 namespace jni {
30 
31 // jobject
32 // /////////////////////////////////////////////////////////////////////////////////////////
33 
isSameObject(alias_ref<JObject> lhs,alias_ref<JObject> rhs)34 inline bool isSameObject(
35     alias_ref<JObject> lhs,
36     alias_ref<JObject> rhs) noexcept {
37   return Environment::current()->IsSameObject(lhs.get(), rhs.get()) !=
38       JNI_FALSE;
39 }
40 
getClass()41 inline local_ref<JClass> JObject::getClass() const noexcept {
42   return adopt_local(Environment::current()->GetObjectClass(self()));
43 }
44 
isInstanceOf(alias_ref<JClass> cls)45 inline bool JObject::isInstanceOf(alias_ref<JClass> cls) const noexcept {
46   return Environment::current()->IsInstanceOf(self(), cls.get()) != JNI_FALSE;
47 }
48 
49 template <typename T>
getFieldValue(JField<T> field)50 inline T JObject::getFieldValue(JField<T> field) const noexcept {
51   return field.get(self());
52 }
53 
54 template <typename T>
getFieldValue(JField<T * > field)55 inline local_ref<T*> JObject::getFieldValue(JField<T*> field) const noexcept {
56   return adopt_local(field.get(self()));
57 }
58 
59 template <typename T>
setFieldValue(JField<T> field,T value)60 inline void JObject::setFieldValue(JField<T> field, T value) noexcept {
61   field.set(self(), value);
62 }
63 
64 template <typename T, typename>
setFieldValue(JField<T> field,alias_ref<T> value)65 inline void JObject::setFieldValue(
66     JField<T> field,
67     alias_ref<T> value) noexcept {
68   setFieldValue(field, value.get());
69 }
70 
toString()71 inline std::string JObject::toString() const {
72   static const auto method =
73       findClassLocal("java/lang/Object")->getMethod<jstring()>("toString");
74 
75   return method(self())->toStdString();
76 }
77 
78 // Class is here instead of CoreClasses.h because we need
79 // alias_ref to be complete.
80 class MonitorLock {
81  public:
82   inline MonitorLock() noexcept;
83   inline MonitorLock(alias_ref<JObject> object) noexcept;
84   inline ~MonitorLock() noexcept;
85 
86   inline MonitorLock(MonitorLock&& other) noexcept;
87   inline MonitorLock& operator=(MonitorLock&& other) noexcept;
88 
89   inline MonitorLock(const MonitorLock&) = delete;
90   inline MonitorLock& operator=(const MonitorLock&) = delete;
91 
92  private:
93   inline void reset() noexcept;
94   alias_ref<JObject> owned_;
95 };
96 
MonitorLock()97 MonitorLock::MonitorLock() noexcept : owned_(nullptr) {}
98 
MonitorLock(alias_ref<JObject> object)99 MonitorLock::MonitorLock(alias_ref<JObject> object) noexcept : owned_(object) {
100   Environment::current()->MonitorEnter(object.get());
101 }
102 
reset()103 void MonitorLock::reset() noexcept {
104   if (owned_) {
105     Environment::current()->MonitorExit(owned_.get());
106     if (Environment::current()->ExceptionCheck()) {
107       abort(); // Lock mismatch
108     }
109     owned_ = nullptr;
110   }
111 }
112 
~MonitorLock()113 MonitorLock::~MonitorLock() noexcept {
114   reset();
115 }
116 
MonitorLock(MonitorLock && other)117 MonitorLock::MonitorLock(MonitorLock&& other) noexcept : owned_(other.owned_) {
118   other.owned_ = nullptr;
119 }
120 
121 MonitorLock& MonitorLock::operator=(MonitorLock&& other) noexcept {
122   reset();
123   owned_ = other.owned_;
124   other.owned_ = nullptr;
125   return *this;
126 }
127 
lock()128 inline MonitorLock JObject::lock() const noexcept {
129   return MonitorLock(this_);
130 }
131 
self()132 inline jobject JObject::self() const noexcept {
133   return this_;
134 }
135 
swap(JObject & a,JObject & b)136 inline void swap(JObject& a, JObject& b) noexcept {
137   using std::swap;
138   swap(a.this_, b.this_);
139 }
140 
141 // JavaClass
142 // ///////////////////////////////////////////////////////////////////////////////////////
143 
144 namespace detail {
145 template <typename JC, typename... Args>
newInstance(Args...args)146 static local_ref<JC> newInstance(Args... args) {
147   static auto cls = JC::javaClassStatic();
148   static const auto constructor =
149       cls->template getConstructor<typename JC::javaobject(Args...)>();
150   return cls->newObject(constructor, args...);
151 }
152 } // namespace detail
153 
154 template <typename T, typename B, typename J>
155 auto JavaClass<T, B, J>::self() const noexcept -> javaobject {
156   return static_cast<javaobject>(JObject::self());
157 }
158 
159 // jclass
160 // //////////////////////////////////////////////////////////////////////////////////////////
161 
getSuperclass()162 inline local_ref<JClass> JClass::getSuperclass() const noexcept {
163   return adopt_local(Environment::current()->GetSuperclass(self()));
164 }
165 
registerNatives(std::initializer_list<JNINativeMethod> methods)166 inline void JClass::registerNatives(
167     std::initializer_list<JNINativeMethod> methods) {
168   const auto env = Environment::current();
169   auto result = env->RegisterNatives(
170       self(), methods.begin(), static_cast<int>(methods.size()));
171   FACEBOOK_JNI_THROW_EXCEPTION_IF(result != JNI_OK);
172 }
173 
isAssignableFrom(alias_ref<JClass> cls)174 inline bool JClass::isAssignableFrom(alias_ref<JClass> cls) const noexcept {
175   const auto env = Environment::current();
176   // Ths method has behavior compatible with the
177   // java.lang.Class#isAssignableFrom method.  The order of the
178   // arguments to the JNI IsAssignableFrom C function is "opposite"
179   // from what some might expect, which makes this code look a little
180   // odd, but it is correct.
181   const auto result = env->IsAssignableFrom(cls.get(), self());
182   return result;
183 }
184 
185 template <typename F>
getConstructor()186 inline JConstructor<F> JClass::getConstructor() const {
187   return getConstructor<F>(
188       jmethod_traits_from_cxx<F>::kConstructorDescriptor.c_str());
189 }
190 
191 template <typename F>
getConstructor(const char * descriptor)192 inline JConstructor<F> JClass::getConstructor(const char* descriptor) const {
193   constexpr auto constructor_method_name = "<init>";
194   return getMethod<F>(constructor_method_name, descriptor);
195 }
196 
197 template <typename F>
getMethod(const char * name)198 inline JMethod<F> JClass::getMethod(const char* name) const {
199   return getMethod<F>(name, jmethod_traits_from_cxx<F>::kDescriptor.c_str());
200 }
201 
202 template <typename F>
getMethod(const char * name,const char * descriptor)203 inline JMethod<F> JClass::getMethod(const char* name, const char* descriptor)
204     const {
205   const auto env = Environment::current();
206   const auto method = env->GetMethodID(self(), name, descriptor);
207   FACEBOOK_JNI_THROW_EXCEPTION_IF(!method);
208   return JMethod<F>{method};
209 }
210 
211 template <typename F>
getStaticMethod(const char * name)212 inline JStaticMethod<F> JClass::getStaticMethod(const char* name) const {
213   return getStaticMethod<F>(
214       name, jmethod_traits_from_cxx<F>::kDescriptor.c_str());
215 }
216 
217 template <typename F>
getStaticMethod(const char * name,const char * descriptor)218 inline JStaticMethod<F> JClass::getStaticMethod(
219     const char* name,
220     const char* descriptor) const {
221   const auto env = Environment::current();
222   const auto method = env->GetStaticMethodID(self(), name, descriptor);
223   FACEBOOK_JNI_THROW_EXCEPTION_IF(!method);
224   return JStaticMethod<F>{method};
225 }
226 
227 template <typename F>
getNonvirtualMethod(const char * name)228 inline JNonvirtualMethod<F> JClass::getNonvirtualMethod(
229     const char* name) const {
230   return getNonvirtualMethod<F>(
231       name, jmethod_traits_from_cxx<F>::kDescriptor.c_str());
232 }
233 
234 template <typename F>
getNonvirtualMethod(const char * name,const char * descriptor)235 inline JNonvirtualMethod<F> JClass::getNonvirtualMethod(
236     const char* name,
237     const char* descriptor) const {
238   const auto env = Environment::current();
239   const auto method = env->GetMethodID(self(), name, descriptor);
240   FACEBOOK_JNI_THROW_EXCEPTION_IF(!method);
241   return JNonvirtualMethod<F>{method};
242 }
243 
244 template <typename T>
getField(const char * name)245 inline JField<PrimitiveOrJniType<T>> JClass::getField(const char* name) const {
246   return getField<T>(name, jtype_traits<T>::kDescriptor.c_str());
247 }
248 
249 template <typename T>
getField(const char * name,const char * descriptor)250 inline JField<PrimitiveOrJniType<T>> JClass::getField(
251     const char* name,
252     const char* descriptor) const {
253   const auto env = Environment::current();
254   auto field = env->GetFieldID(self(), name, descriptor);
255   FACEBOOK_JNI_THROW_EXCEPTION_IF(!field);
256   return JField<PrimitiveOrJniType<T>>{field};
257 }
258 
259 template <typename T>
getStaticField(const char * name)260 inline JStaticField<PrimitiveOrJniType<T>> JClass::getStaticField(
261     const char* name) const {
262   return getStaticField<T>(name, jtype_traits<T>::kDescriptor.c_str());
263 }
264 
265 template <typename T>
getStaticField(const char * name,const char * descriptor)266 inline JStaticField<PrimitiveOrJniType<T>> JClass::getStaticField(
267     const char* name,
268     const char* descriptor) const {
269   const auto env = Environment::current();
270   auto field = env->GetStaticFieldID(self(), name, descriptor);
271   FACEBOOK_JNI_THROW_EXCEPTION_IF(!field);
272   return JStaticField<PrimitiveOrJniType<T>>{field};
273 }
274 
275 template <typename T>
getStaticFieldValue(JStaticField<T> field)276 inline T JClass::getStaticFieldValue(JStaticField<T> field) const noexcept {
277   return field.get(self());
278 }
279 
280 template <typename T>
getStaticFieldValue(JStaticField<T * > field)281 inline local_ref<T*> JClass::getStaticFieldValue(
282     JStaticField<T*> field) noexcept {
283   return adopt_local(field.get(self()));
284 }
285 
286 template <typename T>
setStaticFieldValue(JStaticField<T> field,T value)287 inline void JClass::setStaticFieldValue(
288     JStaticField<T> field,
289     T value) noexcept {
290   field.set(self(), value);
291 }
292 
293 template <typename T, typename>
setStaticFieldValue(JStaticField<T> field,alias_ref<T> value)294 inline void JClass::setStaticFieldValue(
295     JStaticField<T> field,
296     alias_ref<T> value) noexcept {
297   setStaticFieldValue(field, value.get());
298 }
299 
300 template <typename R, typename... Args>
newObject(JConstructor<R (Args...)> constructor,Args...args)301 inline local_ref<R> JClass::newObject(
302     JConstructor<R(Args...)> constructor,
303     Args... args) const {
304   const auto env = Environment::current();
305   auto object = env->NewObject(
306       self(),
307       constructor.getId(),
308       detail::callToJni(
309           detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
310   FACEBOOK_JNI_THROW_EXCEPTION_IF(!object);
311   return adopt_local(static_cast<R>(object));
312 }
313 
self()314 inline jclass JClass::self() const noexcept {
315   return static_cast<jclass>(JObject::self());
316 }
317 
registerNatives(const char * name,std::initializer_list<JNINativeMethod> methods)318 inline void registerNatives(
319     const char* name,
320     std::initializer_list<JNINativeMethod> methods) {
321   findClassLocal(name)->registerNatives(methods);
322 }
323 
324 inline auto JClass::getCanonicalName() -> local_ref<JString> {
325   static auto meth =
326       javaClassStatic()->getMethod<JString::javaobject()>("getCanonicalName");
327   return meth(self());
328 }
329 
330 // jstring
331 // /////////////////////////////////////////////////////////////////////////////////////////
332 
make_jstring(const std::string & utf8)333 inline local_ref<JString> make_jstring(const std::string& utf8) {
334   return make_jstring(utf8.c_str());
335 }
336 
337 namespace detail {
338 // convert to std::string from jstring
339 template <>
340 struct Convert<std::string> {
341   typedef jstring jniType;
342   static std::string fromJni(jniType t) {
343     return wrap_alias(t)->toStdString();
344   }
345   static jniType toJniRet(const std::string& t) {
346     return make_jstring(t).release();
347   }
348   static local_ref<JString> toCall(const std::string& t) {
349     return make_jstring(t);
350   }
351 };
352 
353 // convert return from const char*
354 template <>
355 struct Convert<const char*> {
356   typedef jstring jniType;
357   // no automatic synthesis of const char*.  (It can't be freed.)
358   static jniType toJniRet(const char* t) {
359     return make_jstring(t).release();
360   }
361   static local_ref<JString> toCall(const char* t) {
362     return make_jstring(t);
363   }
364 };
365 } // namespace detail
366 
367 // jtypeArray
368 // //////////////////////////////////////////////////////////////////////////////////////
369 
370 namespace detail {
371 inline size_t JArray::size() const noexcept {
372   const auto env = Environment::current();
373   return env->GetArrayLength(self());
374 }
375 } // namespace detail
376 
377 namespace detail {
378 template <typename Target>
379 inline ElementProxy<Target>::ElementProxy(Target* target, size_t idx)
380     : target_{target}, idx_{idx} {}
381 
382 template <typename Target>
383 inline ElementProxy<Target>& ElementProxy<Target>::operator=(const T& o) {
384   target_->setElement(idx_, o);
385   return *this;
386 }
387 
388 template <typename Target>
389 inline ElementProxy<Target>& ElementProxy<Target>::operator=(
390     alias_ref<typename Target::javaentry>& o) {
391   target_->setElement(idx_, o.get());
392   return *this;
393 }
394 
395 template <typename Target>
396 inline ElementProxy<Target>& ElementProxy<Target>::operator=(
397     alias_ref<typename Target::javaentry>&& o) {
398   target_->setElement(idx_, o.get());
399   return *this;
400 }
401 
402 template <typename Target>
403 inline ElementProxy<Target>& ElementProxy<Target>::operator=(
404     const ElementProxy<Target>& o) {
405   auto src = o.target_->getElement(o.idx_);
406   target_->setElement(idx_, src.get());
407   return *this;
408 }
409 
410 template <typename Target>
411 inline ElementProxy<Target>::ElementProxy::operator const local_ref<
412     typename Target::javaentry>() const {
413   return target_->getElement(idx_);
414 }
415 
416 template <typename Target>
417 inline ElementProxy<Target>::ElementProxy::operator local_ref<
418     typename Target::javaentry>() {
419   return target_->getElement(idx_);
420 }
421 } // namespace detail
422 
423 template <typename T>
424 auto JArrayClass<T>::newArray(size_t count) -> local_ref<javaobject> {
425   static const auto elementClass =
426       findClassStatic(jtype_traits<T>::kBaseName.c_str());
427   const auto env = Environment::current();
428   auto rawArray = env->NewObjectArray(
429       static_cast<jsize>(count), elementClass.get(), nullptr);
430   FACEBOOK_JNI_THROW_EXCEPTION_IF(!rawArray);
431   return adopt_local(static_cast<javaobject>(rawArray));
432 }
433 
434 template <typename T>
435 inline void JArrayClass<T>::setElement(size_t idx, T value) {
436   const auto env = Environment::current();
437   env->SetObjectArrayElement(
438       this->self(),
439       static_cast<jsize>(idx),
440       detail::toPlainJniReference(value));
441 }
442 
443 template <typename T>
444 inline local_ref<T> JArrayClass<T>::getElement(size_t idx) {
445   const auto env = Environment::current();
446   auto rawElement =
447       env->GetObjectArrayElement(this->self(), static_cast<jsize>(idx));
448   return adopt_local(static_cast<JniType<T>>(rawElement));
449 }
450 
451 template <typename T>
452 inline detail::ElementProxy<JArrayClass<T>> JArrayClass<T>::operator[](
453     size_t idx) {
454   return detail::ElementProxy<JArrayClass<T>>(this, idx);
455 }
456 
457 template <typename T>
458 local_ref<typename JArrayClass<T>::javaobject> adopt_local_array(
459     jobjectArray ref) {
460   return adopt_local(static_cast<typename JArrayClass<T>::javaobject>(ref));
461 }
462 
463 // jarray
464 // /////////////////////////////////////////////////////////////////////////////////////////
465 
466 template <typename JArrayType>
467 auto JPrimitiveArray<JArrayType>::getRegion(jsize start, jsize length)
468     -> std::unique_ptr<T[]> {
469   auto buf = std::unique_ptr<T[]>{new T[length]};
470   getRegion(start, length, buf.get());
471   return buf;
472 }
473 
474 template <typename JArrayType>
475 auto JPrimitiveArray<JArrayType>::pin()
476     -> PinnedPrimitiveArray<T, PinnedArrayAlloc<T>> {
477   return PinnedPrimitiveArray<T, PinnedArrayAlloc<T>>{this->self(), 0, 0};
478 }
479 
480 template <typename JArrayType>
481 auto JPrimitiveArray<JArrayType>::pinRegion(jsize start, jsize length)
482     -> PinnedPrimitiveArray<T, PinnedRegionAlloc<T>> {
483   return PinnedPrimitiveArray<T, PinnedRegionAlloc<T>>{
484       this->self(), start, length};
485 }
486 
487 template <typename JArrayType>
488 auto JPrimitiveArray<JArrayType>::pinCritical()
489     -> PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>> {
490   return PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>>{this->self(), 0, 0};
491 }
492 
493 template <typename T>
494 class PinnedArrayAlloc {
495  public:
496   static void allocate(
497       alias_ref<typename jtype_traits<T>::array_type> array,
498       jsize start,
499       jsize length,
500       T** elements,
501       size_t* size,
502       jboolean* isCopy) {
503     (void)start;
504     (void)length;
505     *elements = array->getElements(isCopy);
506     *size = array->size();
507   }
508   static void release(
509       alias_ref<typename jtype_traits<T>::array_type> array,
510       T* elements,
511       jint start,
512       jint size,
513       jint mode) {
514     (void)start;
515     (void)size;
516     array->releaseElements(elements, mode);
517   }
518 };
519 
520 template <typename T>
521 class PinnedCriticalAlloc {
522  public:
523   static void allocate(
524       alias_ref<typename jtype_traits<T>::array_type> array,
525       jsize start,
526       jsize length,
527       T** elements,
528       size_t* size,
529       jboolean* isCopy) {
530     (void)start;
531     (void)length;
532     const auto env = Environment::current();
533     *elements =
534         static_cast<T*>(env->GetPrimitiveArrayCritical(array.get(), isCopy));
535     FACEBOOK_JNI_THROW_EXCEPTION_IF(!elements);
536     *size = array->size();
537   }
538   static void release(
539       alias_ref<typename jtype_traits<T>::array_type> array,
540       T* elements,
541       jint start,
542       jint size,
543       jint mode) {
544     (void)start;
545     (void)size;
546     const auto env = Environment::current();
547     env->ReleasePrimitiveArrayCritical(array.get(), elements, mode);
548   }
549 };
550 
551 template <typename T>
552 class PinnedRegionAlloc {
553  public:
554   static void allocate(
555       alias_ref<typename jtype_traits<T>::array_type> array,
556       jsize start,
557       jsize length,
558       T** elements,
559       size_t* size,
560       jboolean* isCopy) {
561     auto buf = array->getRegion(start, length);
562     FACEBOOK_JNI_THROW_EXCEPTION_IF(!buf);
563     *elements = buf.release();
564     *size = length;
565     *isCopy = true;
566   }
567   static void release(
568       alias_ref<typename jtype_traits<T>::array_type> array,
569       T* elements,
570       jint start,
571       jint size,
572       jint mode) {
573     std::unique_ptr<T[]> holder;
574     if (mode == 0 || mode == JNI_ABORT) {
575       holder.reset(elements);
576     }
577     if (mode == 0 || mode == JNI_COMMIT) {
578       array->setRegion(start, size, elements);
579     }
580   }
581 };
582 
583 // PinnedPrimitiveArray
584 // ///////////////////////////////////////////////////////////////////////////
585 
586 template <typename T, typename Alloc>
587 PinnedPrimitiveArray<T, Alloc>::PinnedPrimitiveArray(PinnedPrimitiveArray&& o) {
588   *this = std::move(o);
589 }
590 
591 template <typename T, typename Alloc>
592 PinnedPrimitiveArray<T, Alloc>& PinnedPrimitiveArray<T, Alloc>::operator=(
593     PinnedPrimitiveArray&& o) {
594   if (array_) {
595     release();
596   }
597   array_ = std::move(o.array_);
598   elements_ = o.elements_;
599   isCopy_ = o.isCopy_;
600   size_ = o.size_;
601   start_ = o.start_;
602   o.clear();
603   return *this;
604 }
605 
606 template <typename T, typename Alloc>
607 T* PinnedPrimitiveArray<T, Alloc>::get() {
608   return elements_;
609 }
610 
611 template <typename T, typename Alloc>
612 inline void PinnedPrimitiveArray<T, Alloc>::release() {
613   releaseImpl(0);
614   clear();
615 }
616 
617 template <typename T, typename Alloc>
618 inline void PinnedPrimitiveArray<T, Alloc>::commit() {
619   releaseImpl(JNI_COMMIT);
620 }
621 
622 template <typename T, typename Alloc>
623 inline void PinnedPrimitiveArray<T, Alloc>::abort() {
624   releaseImpl(JNI_ABORT);
625   clear();
626 }
627 
628 template <typename T, typename Alloc>
629 inline void PinnedPrimitiveArray<T, Alloc>::releaseImpl(jint mode) {
630   FACEBOOK_JNI_THROW_EXCEPTION_IF(array_.get() == nullptr);
631   Alloc::release(
632       array_,
633       elements_,
634       static_cast<jint>(start_),
635       static_cast<jint>(size_),
636       mode);
637 }
638 
639 template <typename T, typename Alloc>
640 inline void PinnedPrimitiveArray<T, Alloc>::clear() noexcept {
641   array_ = nullptr;
642   elements_ = nullptr;
643   isCopy_ = false;
644   start_ = 0;
645   size_ = 0;
646 }
647 
648 template <typename T, typename Alloc>
649 inline T& PinnedPrimitiveArray<T, Alloc>::operator[](size_t index) {
650   FACEBOOK_JNI_THROW_EXCEPTION_IF(elements_ == nullptr);
651   return elements_[index];
652 }
653 
654 template <typename T, typename Alloc>
655 inline bool PinnedPrimitiveArray<T, Alloc>::isCopy() const noexcept {
656   return isCopy_ == JNI_TRUE;
657 }
658 
659 template <typename T, typename Alloc>
660 inline size_t PinnedPrimitiveArray<T, Alloc>::size() const noexcept {
661   return size_;
662 }
663 
664 template <typename T, typename Alloc>
665 inline PinnedPrimitiveArray<T, Alloc>::~PinnedPrimitiveArray() noexcept {
666   if (elements_) {
667     release();
668   }
669 }
670 
671 template <typename T, typename Alloc>
672 inline PinnedPrimitiveArray<T, Alloc>::PinnedPrimitiveArray(
673     alias_ref<typename jtype_traits<T>::array_type> array,
674     jint start,
675     jint length) {
676   array_ = array;
677   start_ = start;
678   Alloc::allocate(array, start, length, &elements_, &size_, &isCopy_);
679 }
680 
681 template <typename T, typename Base, typename JType>
682 inline alias_ref<JClass> JavaClass<T, Base, JType>::javaClassStatic() {
683   static auto cls =
684       findClassStatic(jtype_traits<typename T::javaobject>::kBaseName.c_str());
685   return cls;
686 }
687 
688 template <typename T, typename Base, typename JType>
689 inline local_ref<JClass> JavaClass<T, Base, JType>::javaClassLocal() {
690   std::string className(
691       jtype_traits<typename T::javaobject>::kBaseName.c_str());
692   return findClassLocal(className.c_str());
693 }
694 
695 } // namespace jni
696 } // namespace facebook
697