check_jni.cc revision 9e937be874b4f76c50a05ec8f9d8e68ef2f9ae37
1/*
2 * Copyright (C) 2008 The Android Open Source Project
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#include "check_jni.h"
18
19#include <sys/mman.h>
20#include <zlib.h>
21
22#include <iomanip>
23
24#include <android-base/logging.h>
25#include <android-base/stringprintf.h>
26
27#include "art_field-inl.h"
28#include "art_method-inl.h"
29#include "base/macros.h"
30#include "base/to_str.h"
31#include "base/time_utils.h"
32#include "class_linker-inl.h"
33#include "class_linker.h"
34#include "dex/dex_file-inl.h"
35#include "gc/space/space.h"
36#include "java_vm_ext.h"
37#include "jni_internal.h"
38#include "mirror/class-inl.h"
39#include "mirror/object-inl.h"
40#include "mirror/object_array-inl.h"
41#include "mirror/string-inl.h"
42#include "mirror/throwable.h"
43#include "runtime.h"
44#include "scoped_thread_state_change-inl.h"
45#include "thread.h"
46#include "well_known_classes.h"
47
48namespace art {
49namespace {
50
51using android::base::StringAppendF;
52using android::base::StringPrintf;
53
54/*
55 * ===========================================================================
56 *      JNI function helpers
57 * ===========================================================================
58 */
59
60// Warn if a JNI critical is held for longer than 16ms.
61static constexpr uint64_t kCriticalWarnTimeUs = MsToUs(16);
62static_assert(kCriticalWarnTimeUs > 0, "No JNI critical warn time set");
63
64// True if primitives within specific ranges cause a fatal error,
65// otherwise just warn.
66static constexpr bool kBrokenPrimitivesAreFatal = kIsDebugBuild;
67
68// Flags passed into ScopedCheck.
69static constexpr uint16_t kFlag_Default = 0x0000;
70
71// Calling while in critical is not allowed.
72static constexpr uint16_t kFlag_CritBad = 0x0000;
73// Calling while in critical is allowed.
74static constexpr uint16_t kFlag_CritOkay = 0x0001;
75// This is a critical "get".
76static constexpr uint16_t kFlag_CritGet = 0x0002;
77// This is a critical "release".
78static constexpr uint16_t kFlag_CritRelease = 0x0003;
79// Bit mask to get "crit" value.
80static constexpr uint16_t kFlag_CritMask = 0x0003;
81
82// Raised exceptions are allowed.
83static constexpr uint16_t kFlag_ExcepOkay = 0x0004;
84
85// Are we in a non-critical release function?
86static constexpr uint16_t kFlag_Release = 0x0010;
87// Are our UTF parameters nullable?
88static constexpr uint16_t kFlag_NullableUtf = 0x0020;
89
90// Part of the invocation interface (JavaVM*).
91static constexpr uint16_t kFlag_Invocation = 0x0100;
92
93// Add this to a JNI function's flags if you want to trace every call.
94static constexpr uint16_t kFlag_ForceTrace = 0x8000;
95
96class VarArgs;
97/*
98 * Java primitive types:
99 * B - jbyte
100 * C - jchar
101 * D - jdouble
102 * F - jfloat
103 * I - jint
104 * J - jlong
105 * S - jshort
106 * Z - jboolean (shown as true and false)
107 * V - void
108 *
109 * Java reference types:
110 * L - jobject
111 * a - jarray
112 * c - jclass
113 * s - jstring
114 * t - jthrowable
115 *
116 * JNI types:
117 * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
118 * f - jfieldID
119 * i - JNI error value (JNI_OK, JNI_ERR, JNI_EDETACHED, JNI_EVERSION)
120 * m - jmethodID
121 * p - void*
122 * r - jint (for release mode arguments)
123 * u - const char* (Modified UTF-8)
124 * z - jsize (for lengths; use i if negative values are okay)
125 * v - JavaVM*
126 * w - jobjectRefType
127 * E - JNIEnv*
128 * . - no argument; just print "..." (used for varargs JNI calls)
129 *
130 */
131union JniValueType {
132  jarray a;
133  jboolean b;
134  jclass c;
135  jfieldID f;
136  jint i;
137  jmethodID m;
138  const void* p;  // Pointer.
139  jint r;  // Release mode.
140  jstring s;
141  jthrowable t;
142  const char* u;  // Modified UTF-8.
143  JavaVM* v;
144  jobjectRefType w;
145  jsize z;
146  jbyte B;
147  jchar C;
148  jdouble D;
149  JNIEnv* E;
150  jfloat F;
151  jint I;
152  jlong J;
153  jobject L;
154  jshort S;
155  const void* V;  // void
156  jboolean Z;
157  const VarArgs* va;
158};
159
160/*
161 * A structure containing all the information needed to validate varargs arguments.
162 *
163 * Note that actually getting the arguments from this structure mutates it so should only be done on
164 * owned copies.
165 */
166class VarArgs {
167 public:
168  VarArgs(jmethodID m, va_list var) : m_(m), type_(kTypeVaList), cnt_(0) {
169    va_copy(vargs_, var);
170  }
171
172  VarArgs(jmethodID m, const jvalue* vals) : m_(m), type_(kTypePtr), cnt_(0), ptr_(vals) {}
173
174  ~VarArgs() {
175    if (type_ == kTypeVaList) {
176      va_end(vargs_);
177    }
178  }
179
180  VarArgs(VarArgs&& other) {
181    m_ = other.m_;
182    cnt_ = other.cnt_;
183    type_ = other.type_;
184    if (other.type_ == kTypeVaList) {
185      va_copy(vargs_, other.vargs_);
186    } else {
187      ptr_ = other.ptr_;
188    }
189  }
190
191  // This method is const because we need to ensure that one only uses the GetValue method on an
192  // owned copy of the VarArgs. This is because getting the next argument from a va_list is a
193  // mutating operation. Therefore we pass around these VarArgs with the 'const' qualifier and when
194  // we want to use one we need to Clone() it.
195  VarArgs Clone() const {
196    if (type_ == kTypeVaList) {
197      // const_cast needed to make sure the compiler is okay with va_copy, which (being a macro) is
198      // messed up if the source argument is not the exact type 'va_list'.
199      return VarArgs(m_, cnt_, const_cast<VarArgs*>(this)->vargs_);
200    } else {
201      return VarArgs(m_, cnt_, ptr_);
202    }
203  }
204
205  jmethodID GetMethodID() const {
206    return m_;
207  }
208
209  JniValueType GetValue(char fmt) {
210    JniValueType o;
211    if (type_ == kTypeVaList) {
212      switch (fmt) {
213        // Assign a full int for va_list values as this is what is done in reflection.cc.
214        // TODO(b/73656264): avoid undefined behavior.
215        case 'Z': FALLTHROUGH_INTENDED;
216        case 'B': FALLTHROUGH_INTENDED;
217        case 'C': FALLTHROUGH_INTENDED;
218        case 'S': FALLTHROUGH_INTENDED;
219        case 'I': o.I = va_arg(vargs_, jint); break;
220        case 'J': o.J = va_arg(vargs_, jlong); break;
221        case 'F': o.F = static_cast<jfloat>(va_arg(vargs_, jdouble)); break;
222        case 'D': o.D = va_arg(vargs_, jdouble); break;
223        case 'L': o.L = va_arg(vargs_, jobject); break;
224        default:
225          LOG(FATAL) << "Illegal type format char " << fmt;
226          UNREACHABLE();
227      }
228    } else {
229      CHECK(type_ == kTypePtr);
230      jvalue v = ptr_[cnt_];
231      cnt_++;
232      switch (fmt) {
233        // Copy just the amount of the jvalue necessary, as done in
234        // reflection.cc, but extend to an int to be consistent with
235        // var args in CheckNonHeapValue.
236        // TODO(b/73656264): avoid undefined behavior.
237        case 'Z': o.I = v.z; break;
238        case 'B': o.I = v.b; break;
239        case 'C': o.I = v.c; break;
240        case 'S': o.I = v.s; break;
241        case 'I': o.I = v.i; break;
242        case 'J': o.J = v.j; break;
243        case 'F': o.F = v.f; break;
244        case 'D': o.D = v.d; break;
245        case 'L': o.L = v.l; break;
246        default:
247          LOG(FATAL) << "Illegal type format char " << fmt;
248          UNREACHABLE();
249      }
250    }
251    return o;
252  }
253
254 private:
255  VarArgs(jmethodID m, uint32_t cnt, va_list var) : m_(m), type_(kTypeVaList), cnt_(cnt) {
256    va_copy(vargs_, var);
257  }
258
259  VarArgs(jmethodID m, uint32_t cnt, const jvalue* vals) : m_(m), type_(kTypePtr), cnt_(cnt), ptr_(vals) {}
260
261  enum VarArgsType {
262    kTypeVaList,
263    kTypePtr,
264  };
265
266  jmethodID m_;
267  VarArgsType type_;
268  uint32_t cnt_;
269  union {
270    va_list vargs_;
271    const jvalue* ptr_;
272  };
273};
274
275class ScopedCheck {
276 public:
277  ScopedCheck(uint16_t flags, const char* functionName, bool has_method = true)
278      : function_name_(functionName), indent_(0), flags_(flags), has_method_(has_method) {
279  }
280
281  ~ScopedCheck() {}
282
283  // Checks that 'class_name' is a valid "fully-qualified" JNI class name, like "java/lang/Thread"
284  // or "[Ljava/lang/Object;". A ClassLoader can actually normalize class names a couple of
285  // times, so using "java.lang.Thread" instead of "java/lang/Thread" might work in some
286  // circumstances, but this is incorrect.
287  bool CheckClassName(const char* class_name) {
288    if ((class_name == nullptr) || !IsValidJniClassName(class_name)) {
289      AbortF("illegal class name '%s'\n"
290             "    (should be of the form 'package/Class', [Lpackage/Class;' or '[[B')",
291             class_name);
292      return false;
293    }
294    return true;
295  }
296
297  /*
298   * Verify that this instance field ID is valid for this object.
299   *
300   * Assumes "jobj" has already been validated.
301   */
302  bool CheckInstanceFieldID(ScopedObjectAccess& soa, jobject java_object, jfieldID fid)
303      REQUIRES_SHARED(Locks::mutator_lock_) {
304    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
305    if (o == nullptr) {
306      AbortF("field operation on NULL object: %p", java_object);
307      return false;
308    }
309    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o.Ptr())) {
310      Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
311      AbortF("field operation on invalid %s: %p",
312             GetIndirectRefKindString(IndirectReferenceTable::GetIndirectRefKind(java_object)),
313             java_object);
314      return false;
315    }
316
317    ArtField* f = CheckFieldID(fid);
318    if (f == nullptr) {
319      return false;
320    }
321    mirror::Class* c = o->GetClass();
322    if (c->FindInstanceField(f->GetName(), f->GetTypeDescriptor()) == nullptr) {
323      AbortF("jfieldID %s not valid for an object of class %s",
324             f->PrettyField().c_str(), o->PrettyTypeOf().c_str());
325      return false;
326    }
327    return true;
328  }
329
330  /*
331   * Verify that the pointer value is non-null.
332   */
333  bool CheckNonNull(const void* ptr) {
334    if (UNLIKELY(ptr == nullptr)) {
335      AbortF("non-nullable argument was NULL");
336      return false;
337    }
338    return true;
339  }
340
341  /*
342   * Verify that the method's return type matches the type of call.
343   * 'expectedType' will be "L" for all objects, including arrays.
344   */
345  bool CheckMethodAndSig(ScopedObjectAccess& soa, jobject jobj, jclass jc,
346                         jmethodID mid, Primitive::Type type, InvokeType invoke)
347      REQUIRES_SHARED(Locks::mutator_lock_) {
348    ArtMethod* m = CheckMethodID(mid);
349    if (m == nullptr) {
350      return false;
351    }
352    if (type != Primitive::GetType(m->GetShorty()[0])) {
353      AbortF("the return type of %s does not match %s", function_name_, m->PrettyMethod().c_str());
354      return false;
355    }
356    bool is_static = (invoke == kStatic);
357    if (is_static != m->IsStatic()) {
358      if (is_static) {
359        AbortF("calling non-static method %s with %s",
360               m->PrettyMethod().c_str(), function_name_);
361      } else {
362        AbortF("calling static method %s with %s",
363               m->PrettyMethod().c_str(), function_name_);
364      }
365      return false;
366    }
367    if (invoke != kVirtual) {
368      ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
369      if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
370        AbortF("can't call %s %s with class %s", invoke == kStatic ? "static" : "nonvirtual",
371            m->PrettyMethod().c_str(), mirror::Class::PrettyClass(c).c_str());
372        return false;
373      }
374    }
375    if (invoke != kStatic) {
376      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(jobj);
377      if (o == nullptr) {
378        AbortF("can't call %s on null object", m->PrettyMethod().c_str());
379        return false;
380      } else if (!o->InstanceOf(m->GetDeclaringClass())) {
381        AbortF("can't call %s on instance of %s", m->PrettyMethod().c_str(),
382               o->PrettyTypeOf().c_str());
383        return false;
384      }
385    }
386    return true;
387  }
388
389  /*
390   * Verify that this static field ID is valid for this class.
391   *
392   * Assumes "java_class" has already been validated.
393   */
394  bool CheckStaticFieldID(ScopedObjectAccess& soa, jclass java_class, jfieldID fid)
395      REQUIRES_SHARED(Locks::mutator_lock_) {
396    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
397    ArtField* f = CheckFieldID(fid);
398    if (f == nullptr) {
399      return false;
400    }
401    if (!f->GetDeclaringClass()->IsAssignableFrom(c)) {
402      AbortF("static jfieldID %p not valid for class %s", fid,
403             mirror::Class::PrettyClass(c).c_str());
404      return false;
405    }
406    return true;
407  }
408
409  /*
410   * Verify that "mid" is appropriate for "java_class".
411   *
412   * A mismatch isn't dangerous, because the jmethodID defines the class.  In
413   * fact, java_class is unused in the implementation.  It's best if we don't
414   * allow bad code in the system though.
415   *
416   * Instances of "java_class" must be instances of the method's declaring class.
417   */
418  bool CheckStaticMethod(ScopedObjectAccess& soa, jclass java_class, jmethodID mid)
419      REQUIRES_SHARED(Locks::mutator_lock_) {
420    ArtMethod* m = CheckMethodID(mid);
421    if (m == nullptr) {
422      return false;
423    }
424    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
425    if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
426      AbortF("can't call static %s on class %s", m->PrettyMethod().c_str(),
427             mirror::Class::PrettyClass(c).c_str());
428      return false;
429    }
430    return true;
431  }
432
433  /*
434   * Verify that "mid" is appropriate for "jobj".
435   *
436   * Make sure the object is an instance of the method's declaring class.
437   * (Note the mid might point to a declaration in an interface; this
438   * will be handled automatically by the instanceof check.)
439   */
440  bool CheckVirtualMethod(ScopedObjectAccess& soa, jobject java_object, jmethodID mid)
441      REQUIRES_SHARED(Locks::mutator_lock_) {
442    ArtMethod* m = CheckMethodID(mid);
443    if (m == nullptr) {
444      return false;
445    }
446    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
447    if (o == nullptr) {
448      AbortF("can't call %s on null object", m->PrettyMethod().c_str());
449      return false;
450    } else if (!o->InstanceOf(m->GetDeclaringClass())) {
451      AbortF("can't call %s on instance of %s", m->PrettyMethod().c_str(),
452             o->PrettyTypeOf().c_str());
453      return false;
454    }
455    return true;
456  }
457
458  /**
459   * The format string is a sequence of the following characters,
460   * and must be followed by arguments of the corresponding types
461   * in the same order.
462   *
463   * Java primitive types:
464   * B - jbyte
465   * C - jchar
466   * D - jdouble
467   * F - jfloat
468   * I - jint
469   * J - jlong
470   * S - jshort
471   * Z - jboolean (shown as true and false)
472   * V - void
473   *
474   * Java reference types:
475   * L - jobject
476   * a - jarray
477   * c - jclass
478   * s - jstring
479   *
480   * JNI types:
481   * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
482   * f - jfieldID
483   * m - jmethodID
484   * p - void*
485   * r - jint (for release mode arguments)
486   * u - const char* (Modified UTF-8)
487   * z - jsize (for lengths; use i if negative values are okay)
488   * v - JavaVM*
489   * E - JNIEnv*
490   * . - VarArgs* for Jni calls with variable length arguments
491   *
492   * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
493   */
494  bool Check(ScopedObjectAccess& soa, bool entry, const char* fmt, JniValueType* args)
495      REQUIRES_SHARED(Locks::mutator_lock_) {
496    ArtMethod* traceMethod = nullptr;
497    if (has_method_ && soa.Vm()->IsTracingEnabled()) {
498      // We need to guard some of the invocation interface's calls: a bad caller might
499      // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
500      Thread* self = Thread::Current();
501      if ((flags_ & kFlag_Invocation) == 0 || self != nullptr) {
502        traceMethod = self->GetCurrentMethod(nullptr);
503      }
504    }
505
506    if (((flags_ & kFlag_ForceTrace) != 0) ||
507        (traceMethod != nullptr && soa.Vm()->ShouldTrace(traceMethod))) {
508      std::string msg;
509      for (size_t i = 0; fmt[i] != '\0'; ++i) {
510        TracePossibleHeapValue(soa, entry, fmt[i], args[i], &msg);
511        if (fmt[i + 1] != '\0') {
512          StringAppendF(&msg, ", ");
513        }
514      }
515
516      if ((flags_ & kFlag_ForceTrace) != 0) {
517        LOG(INFO) << "JNI: call to " << function_name_ << "(" << msg << ")";
518      } else if (entry) {
519        if (has_method_) {
520          std::string methodName(ArtMethod::PrettyMethod(traceMethod, false));
521          LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
522          indent_ = methodName.size() + 1;
523        } else {
524          LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
525          indent_ = 0;
526        }
527      } else {
528        LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
529      }
530    }
531
532    // We always do the thorough checks on entry, and never on exit...
533    if (entry) {
534      for (size_t i = 0; fmt[i] != '\0'; ++i) {
535        if (!CheckPossibleHeapValue(soa, fmt[i], args[i])) {
536          return false;
537        }
538      }
539    }
540    return true;
541  }
542
543  bool CheckNonHeap(JavaVMExt* vm, bool entry, const char* fmt, JniValueType* args) {
544    bool should_trace = (flags_ & kFlag_ForceTrace) != 0;
545    if (!should_trace && vm != nullptr && vm->IsTracingEnabled()) {
546      // We need to guard some of the invocation interface's calls: a bad caller might
547      // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
548      Thread* self = Thread::Current();
549      if ((flags_ & kFlag_Invocation) == 0 || self != nullptr) {
550        ScopedObjectAccess soa(self);
551        ArtMethod* traceMethod = self->GetCurrentMethod(nullptr);
552        should_trace = (traceMethod != nullptr && vm->ShouldTrace(traceMethod));
553      }
554    }
555    if (should_trace) {
556      std::string msg;
557      for (size_t i = 0; fmt[i] != '\0'; ++i) {
558        TraceNonHeapValue(fmt[i], args[i], &msg);
559        if (fmt[i + 1] != '\0') {
560          StringAppendF(&msg, ", ");
561        }
562      }
563
564      if ((flags_ & kFlag_ForceTrace) != 0) {
565        LOG(INFO) << "JNI: call to " << function_name_ << "(" << msg << ")";
566      } else if (entry) {
567        if (has_method_) {
568          Thread* self = Thread::Current();
569          ScopedObjectAccess soa(self);
570          ArtMethod* traceMethod = self->GetCurrentMethod(nullptr);
571          std::string methodName(ArtMethod::PrettyMethod(traceMethod, false));
572          LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
573          indent_ = methodName.size() + 1;
574        } else {
575          LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
576          indent_ = 0;
577        }
578      } else {
579        LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
580      }
581    }
582
583    // We always do the thorough checks on entry, and never on exit...
584    if (entry) {
585      for (size_t i = 0; fmt[i] != '\0'; ++i) {
586        if (!CheckNonHeapValue(fmt[i], args[i])) {
587          return false;
588        }
589      }
590    }
591    return true;
592  }
593
594  bool CheckReflectedMethod(ScopedObjectAccess& soa, jobject jmethod)
595      REQUIRES_SHARED(Locks::mutator_lock_) {
596    ObjPtr<mirror::Object> method = soa.Decode<mirror::Object>(jmethod);
597    if (method == nullptr) {
598      AbortF("expected non-null method");
599      return false;
600    }
601    mirror::Class* c = method->GetClass();
602    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) != c &&
603        soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) != c) {
604      AbortF("expected java.lang.reflect.Method or "
605          "java.lang.reflect.Constructor but got object of type %s: %p",
606          method->PrettyTypeOf().c_str(), jmethod);
607      return false;
608    }
609    return true;
610  }
611
612  bool CheckConstructor(jmethodID mid) REQUIRES_SHARED(Locks::mutator_lock_) {
613    ArtMethod* method = jni::DecodeArtMethod(mid);
614    if (method == nullptr) {
615      AbortF("expected non-null constructor");
616      return false;
617    }
618    if (!method->IsConstructor() || method->IsStatic()) {
619      AbortF("expected a constructor but %s: %p", method->PrettyMethod().c_str(), mid);
620      return false;
621    }
622    return true;
623  }
624
625  bool CheckReflectedField(ScopedObjectAccess& soa, jobject jfield)
626      REQUIRES_SHARED(Locks::mutator_lock_) {
627    ObjPtr<mirror::Object> field = soa.Decode<mirror::Object>(jfield);
628    if (field == nullptr) {
629      AbortF("expected non-null java.lang.reflect.Field");
630      return false;
631    }
632    mirror::Class* c = field->GetClass();
633    if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Field) != c) {
634      AbortF("expected java.lang.reflect.Field but got object of type %s: %p",
635             field->PrettyTypeOf().c_str(), jfield);
636      return false;
637    }
638    return true;
639  }
640
641  bool CheckThrowable(ScopedObjectAccess& soa, jthrowable jobj)
642      REQUIRES_SHARED(Locks::mutator_lock_) {
643    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
644    if (!obj->GetClass()->IsThrowableClass()) {
645      AbortF("expected java.lang.Throwable but got object of type "
646             "%s: %p", obj->PrettyTypeOf().c_str(), obj.Ptr());
647      return false;
648    }
649    return true;
650  }
651
652  bool CheckThrowableClass(ScopedObjectAccess& soa, jclass jc)
653      REQUIRES_SHARED(Locks::mutator_lock_) {
654    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
655    if (!c->IsThrowableClass()) {
656      AbortF("expected java.lang.Throwable class but got object of "
657             "type %s: %p", c->PrettyDescriptor().c_str(), c.Ptr());
658      return false;
659    }
660    return true;
661  }
662
663  bool CheckReferenceKind(IndirectRefKind expected_kind, Thread* self, jobject obj) {
664    IndirectRefKind found_kind;
665    if (expected_kind == kLocal) {
666      found_kind = IndirectReferenceTable::GetIndirectRefKind(obj);
667      if (found_kind == kHandleScopeOrInvalid && self->HandleScopeContains(obj)) {
668        found_kind = kLocal;
669      }
670    } else {
671      found_kind = IndirectReferenceTable::GetIndirectRefKind(obj);
672    }
673    if (obj != nullptr && found_kind != expected_kind) {
674      AbortF("expected reference of kind %s but found %s: %p",
675             GetIndirectRefKindString(expected_kind),
676             GetIndirectRefKindString(IndirectReferenceTable::GetIndirectRefKind(obj)),
677             obj);
678      return false;
679    }
680    return true;
681  }
682
683  bool CheckInstantiableNonArray(ScopedObjectAccess& soa, jclass jc)
684      REQUIRES_SHARED(Locks::mutator_lock_) {
685    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
686    if (!c->IsInstantiableNonArray()) {
687      AbortF("can't make objects of type %s: %p", c->PrettyDescriptor().c_str(), c.Ptr());
688      return false;
689    }
690    return true;
691  }
692
693  bool CheckPrimitiveArrayType(ScopedObjectAccess& soa, jarray array, Primitive::Type type)
694      REQUIRES_SHARED(Locks::mutator_lock_) {
695    if (!CheckArray(soa, array)) {
696      return false;
697    }
698    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(array);
699    if (a->GetClass()->GetComponentType()->GetPrimitiveType() != type) {
700      AbortF("incompatible array type %s expected %s[]: %p",
701             a->GetClass()->PrettyDescriptor().c_str(), PrettyDescriptor(type).c_str(), array);
702      return false;
703    }
704    return true;
705  }
706
707  bool CheckFieldAccess(ScopedObjectAccess& soa, jobject obj, jfieldID fid, bool is_static,
708                        Primitive::Type type)
709      REQUIRES_SHARED(Locks::mutator_lock_) {
710    if (is_static && !CheckStaticFieldID(soa, down_cast<jclass>(obj), fid)) {
711      return false;
712    }
713    if (!is_static && !CheckInstanceFieldID(soa, obj, fid)) {
714      return false;
715    }
716    ArtField* field = jni::DecodeArtField(fid);
717    DCHECK(field != nullptr);  // Already checked by Check.
718    if (is_static != field->IsStatic()) {
719      AbortF("attempt to access %s field %s: %p",
720             field->IsStatic() ? "static" : "non-static", field->PrettyField().c_str(), fid);
721      return false;
722    }
723    if (type != field->GetTypeAsPrimitiveType()) {
724      AbortF("attempt to access field %s of type %s with the wrong type %s: %p",
725             field->PrettyField().c_str(),
726             PrettyDescriptor(field->GetTypeDescriptor()).c_str(),
727             PrettyDescriptor(type).c_str(), fid);
728      return false;
729    }
730    if (is_static) {
731      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
732      if (o == nullptr || !o->IsClass()) {
733        AbortF("attempt to access static field %s with a class argument of type %s: %p",
734               field->PrettyField().c_str(), o->PrettyTypeOf().c_str(), fid);
735        return false;
736      }
737      ObjPtr<mirror::Class> c = o->AsClass();
738      if (!field->GetDeclaringClass()->IsAssignableFrom(c)) {
739        AbortF("attempt to access static field %s with an incompatible class argument of %s: %p",
740               field->PrettyField().c_str(), mirror::Class::PrettyDescriptor(c).c_str(), fid);
741        return false;
742      }
743    } else {
744      ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
745      if (o == nullptr || !field->GetDeclaringClass()->IsAssignableFrom(o->GetClass())) {
746        AbortF("attempt to access field %s from an object argument of type %s: %p",
747               field->PrettyField().c_str(), o->PrettyTypeOf().c_str(), fid);
748        return false;
749      }
750    }
751    return true;
752  }
753
754 private:
755  enum InstanceKind {
756    kClass,
757    kDirectByteBuffer,
758    kObject,
759    kString,
760    kThrowable,
761  };
762
763  /*
764   * Verify that "jobj" is a valid non-null object reference, and points to
765   * an instance of expectedClass.
766   *
767   * Because we're looking at an object on the GC heap, we have to switch
768   * to "running" mode before doing the checks.
769   */
770  bool CheckInstance(ScopedObjectAccess& soa, InstanceKind kind, jobject java_object, bool null_ok)
771      REQUIRES_SHARED(Locks::mutator_lock_) {
772    const char* what = nullptr;
773    switch (kind) {
774    case kClass:
775      what = "jclass";
776      break;
777    case kDirectByteBuffer:
778      what = "direct ByteBuffer";
779      break;
780    case kObject:
781      what = "jobject";
782      break;
783    case kString:
784      what = "jstring";
785      break;
786    case kThrowable:
787      what = "jthrowable";
788      break;
789    default:
790      LOG(FATAL) << "Unknown kind " << static_cast<int>(kind);
791    }
792
793    if (java_object == nullptr) {
794      if (null_ok) {
795        return true;
796      } else {
797        AbortF("%s received NULL %s", function_name_, what);
798        return false;
799      }
800    }
801
802    ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(java_object);
803    if (obj == nullptr) {
804      // Either java_object is invalid or is a cleared weak.
805      IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
806      bool okay;
807      if (IndirectReferenceTable::GetIndirectRefKind(ref) != kWeakGlobal) {
808        okay = false;
809      } else {
810        obj = soa.Vm()->DecodeWeakGlobal(soa.Self(), ref);
811        okay = Runtime::Current()->IsClearedJniWeakGlobal(obj);
812      }
813      if (!okay) {
814        AbortF("%s is an invalid %s: %p (%p)",
815               what,
816               GetIndirectRefKindString(IndirectReferenceTable::GetIndirectRefKind(java_object)),
817               java_object,
818               obj.Ptr());
819        return false;
820      }
821    }
822
823    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(obj.Ptr())) {
824      Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
825      AbortF("%s is an invalid %s: %p (%p)",
826             what,
827             GetIndirectRefKindString(IndirectReferenceTable::GetIndirectRefKind(java_object)),
828             java_object,
829             obj.Ptr());
830      return false;
831    }
832
833    bool okay = true;
834    switch (kind) {
835    case kClass:
836      okay = obj->IsClass();
837      break;
838    case kDirectByteBuffer:
839      UNIMPLEMENTED(FATAL);
840      break;
841    case kString:
842      okay = obj->GetClass()->IsStringClass();
843      break;
844    case kThrowable:
845      okay = obj->GetClass()->IsThrowableClass();
846      break;
847    case kObject:
848      break;
849    }
850    if (!okay) {
851      AbortF("%s has wrong type: %s", what, mirror::Object::PrettyTypeOf(obj).c_str());
852      return false;
853    }
854
855    return true;
856  }
857
858  /*
859   * Verify that the "mode" argument passed to a primitive array Release
860   * function is one of the valid values.
861   */
862  bool CheckReleaseMode(jint mode) {
863    if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
864      AbortF("unknown value for release mode: %d", mode);
865      return false;
866    }
867    return true;
868  }
869
870  bool CheckPossibleHeapValue(ScopedObjectAccess& soa, char fmt, JniValueType arg)
871      REQUIRES_SHARED(Locks::mutator_lock_) {
872    switch (fmt) {
873      case 'a':  // jarray
874        return CheckArray(soa, arg.a);
875      case 'c':  // jclass
876        return CheckInstance(soa, kClass, arg.c, false);
877      case 'f':  // jfieldID
878        return CheckFieldID(arg.f) != nullptr;
879      case 'm':  // jmethodID
880        return CheckMethodID(arg.m) != nullptr;
881      case 'r':  // release int
882        return CheckReleaseMode(arg.r);
883      case 's':  // jstring
884        return CheckInstance(soa, kString, arg.s, false);
885      case 't':  // jthrowable
886        return CheckInstance(soa, kThrowable, arg.t, false);
887      case 'E':  // JNIEnv*
888        return CheckThread(arg.E);
889      case 'L':  // jobject
890        return CheckInstance(soa, kObject, arg.L, true);
891      case '.':  // A VarArgs list
892        return CheckVarArgs(soa, arg.va);
893      default:
894        return CheckNonHeapValue(fmt, arg);
895    }
896  }
897
898  bool CheckVarArgs(ScopedObjectAccess& soa, const VarArgs* args_p)
899      REQUIRES_SHARED(Locks::mutator_lock_) {
900    CHECK(args_p != nullptr);
901    VarArgs args(args_p->Clone());
902    ArtMethod* m = CheckMethodID(args.GetMethodID());
903    if (m == nullptr) {
904      return false;
905    }
906    uint32_t len = 0;
907    const char* shorty = m->GetShorty(&len);
908    // Skip the return type
909    CHECK_GE(len, 1u);
910    len--;
911    shorty++;
912    for (uint32_t i = 0; i < len; i++) {
913      if (!CheckPossibleHeapValue(soa, shorty[i], args.GetValue(shorty[i]))) {
914        return false;
915      }
916    }
917    return true;
918  }
919
920  bool CheckNonHeapValue(char fmt, JniValueType arg) {
921    switch (fmt) {
922      case 'p':  // TODO: pointer - null or readable?
923      case 'v':  // JavaVM*
924      case 'D':  // jdouble
925      case 'F':  // jfloat
926      case 'J':  // jlong
927      case 'I':  // jint
928        break;  // Ignored.
929      case 'b':  // jboolean, why two? Fall-through.
930      case 'Z':
931        return CheckBoolean(arg.I);
932      case 'B':  // jbyte
933        return CheckByte(arg.I);
934      case 'C':  // jchar
935        return CheckChar(arg.I);
936      case 'S':  // jshort
937        return CheckShort(arg.I);
938      case 'u':  // utf8
939        if ((flags_ & kFlag_Release) != 0) {
940          return CheckNonNull(arg.u);
941        } else {
942          bool nullable = ((flags_ & kFlag_NullableUtf) != 0);
943          return CheckUtfString(arg.u, nullable);
944        }
945      case 'w':  // jobjectRefType
946        switch (arg.w) {
947          case JNIInvalidRefType:
948          case JNILocalRefType:
949          case JNIGlobalRefType:
950          case JNIWeakGlobalRefType:
951            break;
952          default:
953            AbortF("Unknown reference type");
954            return false;
955        }
956        break;
957      case 'z':  // jsize
958        return CheckLengthPositive(arg.z);
959      default:
960        AbortF("unknown format specifier: '%c'", fmt);
961        return false;
962    }
963    return true;
964  }
965
966  void TracePossibleHeapValue(ScopedObjectAccess& soa, bool entry, char fmt, JniValueType arg,
967                              std::string* msg)
968      REQUIRES_SHARED(Locks::mutator_lock_) {
969    switch (fmt) {
970      case 'L':  // jobject fall-through.
971      case 'a':  // jarray fall-through.
972      case 's':  // jstring fall-through.
973      case 't':  // jthrowable fall-through.
974        if (arg.L == nullptr) {
975          *msg += "NULL";
976        } else {
977          StringAppendF(msg, "%p", arg.L);
978        }
979        break;
980      case 'c': {  // jclass
981        jclass jc = arg.c;
982        ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
983        if (c == nullptr) {
984          *msg += "NULL";
985        } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c.Ptr())) {
986          StringAppendF(msg, "INVALID POINTER:%p", jc);
987        } else if (!c->IsClass()) {
988          *msg += "INVALID NON-CLASS OBJECT OF TYPE:" + c->PrettyTypeOf();
989        } else {
990          *msg += c->PrettyClass();
991          if (!entry) {
992            StringAppendF(msg, " (%p)", jc);
993          }
994        }
995        break;
996      }
997      case 'f': {  // jfieldID
998        jfieldID fid = arg.f;
999        ArtField* f = jni::DecodeArtField(fid);
1000        *msg += ArtField::PrettyField(f);
1001        if (!entry) {
1002          StringAppendF(msg, " (%p)", fid);
1003        }
1004        break;
1005      }
1006      case 'm': {  // jmethodID
1007        jmethodID mid = arg.m;
1008        ArtMethod* m = jni::DecodeArtMethod(mid);
1009        *msg += ArtMethod::PrettyMethod(m);
1010        if (!entry) {
1011          StringAppendF(msg, " (%p)", mid);
1012        }
1013        break;
1014      }
1015      case '.': {
1016        const VarArgs* va = arg.va;
1017        VarArgs args(va->Clone());
1018        ArtMethod* m = jni::DecodeArtMethod(args.GetMethodID());
1019        uint32_t len;
1020        const char* shorty = m->GetShorty(&len);
1021        CHECK_GE(len, 1u);
1022        // Skip past return value.
1023        len--;
1024        shorty++;
1025        // Remove the previous ', ' from the message.
1026        msg->erase(msg->length() - 2);
1027        for (uint32_t i = 0; i < len; i++) {
1028          *msg += ", ";
1029          TracePossibleHeapValue(soa, entry, shorty[i], args.GetValue(shorty[i]), msg);
1030        }
1031        break;
1032      }
1033      default:
1034        TraceNonHeapValue(fmt, arg, msg);
1035        break;
1036    }
1037  }
1038
1039  void TraceNonHeapValue(char fmt, JniValueType arg, std::string* msg) {
1040    switch (fmt) {
1041      case 'B':  // jbyte
1042        if (arg.B >= 0 && arg.B < 10) {
1043          StringAppendF(msg, "%d", arg.B);
1044        } else {
1045          StringAppendF(msg, "%#x (%d)", arg.B, arg.B);
1046        }
1047        break;
1048      case 'C':  // jchar
1049        if (arg.C < 0x7f && arg.C >= ' ') {
1050          StringAppendF(msg, "U+%x ('%c')", arg.C, arg.C);
1051        } else {
1052          StringAppendF(msg, "U+%x", arg.C);
1053        }
1054        break;
1055      case 'F':  // jfloat
1056        StringAppendF(msg, "%g", arg.F);
1057        break;
1058      case 'D':  // jdouble
1059        StringAppendF(msg, "%g", arg.D);
1060        break;
1061      case 'S':  // jshort
1062        StringAppendF(msg, "%d", arg.S);
1063        break;
1064      case 'i':  // jint - fall-through.
1065      case 'I':  // jint
1066        StringAppendF(msg, "%d", arg.I);
1067        break;
1068      case 'J':  // jlong
1069        StringAppendF(msg, "%" PRId64, arg.J);
1070        break;
1071      case 'Z':  // jboolean
1072      case 'b':  // jboolean (JNI-style)
1073        *msg += arg.b == JNI_TRUE ? "true" : "false";
1074        break;
1075      case 'V':  // void
1076        DCHECK(arg.V == nullptr);
1077        *msg += "void";
1078        break;
1079      case 'v':  // JavaVM*
1080        StringAppendF(msg, "(JavaVM*)%p", arg.v);
1081        break;
1082      case 'E':
1083        StringAppendF(msg, "(JNIEnv*)%p", arg.E);
1084        break;
1085      case 'z':  // non-negative jsize
1086        // You might expect jsize to be size_t, but it's not; it's the same as jint.
1087        // We only treat this specially so we can do the non-negative check.
1088        // TODO: maybe this wasn't worth it?
1089        StringAppendF(msg, "%d", arg.z);
1090        break;
1091      case 'p':  // void* ("pointer")
1092        if (arg.p == nullptr) {
1093          *msg += "NULL";
1094        } else {
1095          StringAppendF(msg, "(void*) %p", arg.p);
1096        }
1097        break;
1098      case 'r': {  // jint (release mode)
1099        jint releaseMode = arg.r;
1100        if (releaseMode == 0) {
1101          *msg += "0";
1102        } else if (releaseMode == JNI_ABORT) {
1103          *msg += "JNI_ABORT";
1104        } else if (releaseMode == JNI_COMMIT) {
1105          *msg += "JNI_COMMIT";
1106        } else {
1107          StringAppendF(msg, "invalid release mode %d", releaseMode);
1108        }
1109        break;
1110      }
1111      case 'u':  // const char* (Modified UTF-8)
1112        if (arg.u == nullptr) {
1113          *msg += "NULL";
1114        } else {
1115          StringAppendF(msg, "\"%s\"", arg.u);
1116        }
1117        break;
1118      case 'w':  // jobjectRefType
1119        switch (arg.w) {
1120          case JNIInvalidRefType:
1121            *msg += "invalid reference type";
1122            break;
1123          case JNILocalRefType:
1124            *msg += "local ref type";
1125            break;
1126          case JNIGlobalRefType:
1127            *msg += "global ref type";
1128            break;
1129          case JNIWeakGlobalRefType:
1130            *msg += "weak global ref type";
1131            break;
1132          default:
1133            *msg += "unknown ref type";
1134            break;
1135        }
1136        break;
1137      default:
1138        LOG(FATAL) << function_name_ << ": unknown trace format specifier: '" << fmt << "'";
1139    }
1140  }
1141  /*
1142   * Verify that "array" is non-null and points to an Array object.
1143   *
1144   * Since we're dealing with objects, switch to "running" mode.
1145   */
1146  bool CheckArray(ScopedObjectAccess& soa, jarray java_array)
1147      REQUIRES_SHARED(Locks::mutator_lock_) {
1148    if (UNLIKELY(java_array == nullptr)) {
1149      AbortF("jarray was NULL");
1150      return false;
1151    }
1152
1153    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
1154    if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a.Ptr()))) {
1155      Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
1156      AbortF("jarray is an invalid %s: %p (%p)",
1157             GetIndirectRefKindString(IndirectReferenceTable::GetIndirectRefKind(java_array)),
1158             java_array,
1159             a.Ptr());
1160      return false;
1161    } else if (!a->IsArrayInstance()) {
1162      AbortF("jarray argument has non-array type: %s", a->PrettyTypeOf().c_str());
1163      return false;
1164    }
1165    return true;
1166  }
1167
1168  bool CheckBoolean(jint z) {
1169    if (z != JNI_TRUE && z != JNI_FALSE) {
1170      // Note, broken booleans are always fatal.
1171      AbortF("unexpected jboolean value: %d", z);
1172      return false;
1173    }
1174    return true;
1175  }
1176
1177  bool CheckByte(jint b) {
1178    if (b < std::numeric_limits<jbyte>::min() ||
1179        b > std::numeric_limits<jbyte>::max()) {
1180      if (kBrokenPrimitivesAreFatal) {
1181        AbortF("unexpected jbyte value: %d", b);
1182        return false;
1183      } else {
1184        LOG(WARNING) << "Unexpected jbyte value: " << b;
1185      }
1186    }
1187    return true;
1188  }
1189
1190  bool CheckShort(jint s) {
1191    if (s < std::numeric_limits<jshort>::min() ||
1192        s > std::numeric_limits<jshort>::max()) {
1193      if (kBrokenPrimitivesAreFatal) {
1194        AbortF("unexpected jshort value: %d", s);
1195        return false;
1196      } else {
1197        LOG(WARNING) << "Unexpected jshort value: " << s;
1198      }
1199    }
1200    return true;
1201  }
1202
1203  bool CheckChar(jint c) {
1204    if (c < std::numeric_limits<jchar>::min() ||
1205        c > std::numeric_limits<jchar>::max()) {
1206      if (kBrokenPrimitivesAreFatal) {
1207        AbortF("unexpected jchar value: %d", c);
1208        return false;
1209      } else {
1210        LOG(WARNING) << "Unexpected jchar value: " << c;
1211      }
1212    }
1213    return true;
1214  }
1215
1216  bool CheckLengthPositive(jsize length) {
1217    if (length < 0) {
1218      AbortF("negative jsize: %d", length);
1219      return false;
1220    }
1221    return true;
1222  }
1223
1224  ArtField* CheckFieldID(jfieldID fid) REQUIRES_SHARED(Locks::mutator_lock_) {
1225    if (fid == nullptr) {
1226      AbortF("jfieldID was NULL");
1227      return nullptr;
1228    }
1229    ArtField* f = jni::DecodeArtField(fid);
1230    // TODO: Better check here.
1231    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(f->GetDeclaringClass().Ptr())) {
1232      Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
1233      AbortF("invalid jfieldID: %p", fid);
1234      return nullptr;
1235    }
1236    return f;
1237  }
1238
1239  ArtMethod* CheckMethodID(jmethodID mid) REQUIRES_SHARED(Locks::mutator_lock_) {
1240    if (mid == nullptr) {
1241      AbortF("jmethodID was NULL");
1242      return nullptr;
1243    }
1244    ArtMethod* m = jni::DecodeArtMethod(mid);
1245    // TODO: Better check here.
1246    if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(m->GetDeclaringClass())) {
1247      Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
1248      AbortF("invalid jmethodID: %p", mid);
1249      return nullptr;
1250    }
1251    return m;
1252  }
1253
1254  bool CheckThread(JNIEnv* env) REQUIRES_SHARED(Locks::mutator_lock_) {
1255    Thread* self = Thread::Current();
1256    if (self == nullptr) {
1257      AbortF("a thread (tid %d) is making JNI calls without being attached", GetTid());
1258      return false;
1259    }
1260
1261    // Get the current thread's JNIEnv by going through our TLS pointer.
1262    JNIEnvExt* threadEnv = self->GetJniEnv();
1263
1264    // Verify that the current thread is (a) attached and (b) associated with
1265    // this particular instance of JNIEnv.
1266    if (env != threadEnv) {
1267      // Get the thread owning the JNIEnv that's being used.
1268      Thread* envThread = reinterpret_cast<JNIEnvExt*>(env)->GetSelf();
1269      AbortF("thread %s using JNIEnv* from thread %s",
1270             ToStr<Thread>(*self).c_str(), ToStr<Thread>(*envThread).c_str());
1271      return false;
1272    }
1273
1274    // Verify that, if this thread previously made a critical "get" call, we
1275    // do the corresponding "release" call before we try anything else.
1276    switch (flags_ & kFlag_CritMask) {
1277    case kFlag_CritOkay:    // okay to call this method
1278      break;
1279    case kFlag_CritBad:     // not okay to call
1280      if (threadEnv->GetCritical() > 0) {
1281        AbortF("thread %s using JNI after critical get",
1282               ToStr<Thread>(*self).c_str());
1283        return false;
1284      }
1285      break;
1286    case kFlag_CritGet:     // this is a "get" call
1287      // Don't check here; we allow nested gets.
1288      if (threadEnv->GetCritical() == 0) {
1289        threadEnv->SetCriticalStartUs(self->GetCpuMicroTime());
1290      }
1291      threadEnv->SetCritical(threadEnv->GetCritical() + 1);
1292      break;
1293    case kFlag_CritRelease:  // this is a "release" call
1294      if (threadEnv->GetCritical() == 0) {
1295        AbortF("thread %s called too many critical releases",
1296               ToStr<Thread>(*self).c_str());
1297        return false;
1298      } else if (threadEnv->GetCritical() == 1) {
1299        // Leaving the critical region, possibly warn about long critical regions.
1300        uint64_t critical_duration_us = self->GetCpuMicroTime() - threadEnv->GetCriticalStartUs();
1301        if (critical_duration_us > kCriticalWarnTimeUs) {
1302          LOG(WARNING) << "JNI critical lock held for "
1303                       << PrettyDuration(UsToNs(critical_duration_us)) << " on " << *self;
1304        }
1305      }
1306      threadEnv->SetCritical(threadEnv->GetCritical() - 1);
1307      break;
1308    default:
1309      LOG(FATAL) << "Bad flags (internal error): " << flags_;
1310    }
1311
1312    // Verify that, if an exception has been raised, the native code doesn't
1313    // make any JNI calls other than the Exception* methods.
1314    if ((flags_ & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
1315      mirror::Throwable* exception = self->GetException();
1316      AbortF("JNI %s called with pending exception %s",
1317             function_name_,
1318             exception->Dump().c_str());
1319      return false;
1320    }
1321    return true;
1322  }
1323
1324  // Verifies that "bytes" points to valid Modified UTF-8 data.
1325  bool CheckUtfString(const char* bytes, bool nullable) {
1326    if (bytes == nullptr) {
1327      if (!nullable) {
1328        AbortF("non-nullable const char* was NULL");
1329        return false;
1330      }
1331      return true;
1332    }
1333
1334    const char* errorKind = nullptr;
1335    const uint8_t* utf8 = CheckUtfBytes(bytes, &errorKind);
1336    if (errorKind != nullptr) {
1337      // This is an expensive loop that will resize often, but this isn't supposed to hit in
1338      // practice anyways.
1339      std::ostringstream oss;
1340      oss << std::hex;
1341      const uint8_t* tmp = reinterpret_cast<const uint8_t*>(bytes);
1342      while (*tmp != 0) {
1343        if (tmp == utf8) {
1344          oss << "<";
1345        }
1346        oss << "0x" << std::setfill('0') << std::setw(2) << static_cast<uint32_t>(*tmp);
1347        if (tmp == utf8) {
1348          oss << '>';
1349        }
1350        tmp++;
1351        if (*tmp != 0) {
1352          oss << ' ';
1353        }
1354      }
1355
1356      AbortF("input is not valid Modified UTF-8: illegal %s byte %#x\n"
1357          "    string: '%s'\n    input: '%s'", errorKind, *utf8, bytes, oss.str().c_str());
1358      return false;
1359    }
1360    return true;
1361  }
1362
1363  // Checks whether |bytes| is valid modified UTF-8. We also accept 4 byte UTF
1364  // sequences in place of encoded surrogate pairs.
1365  static const uint8_t* CheckUtfBytes(const char* bytes, const char** errorKind) {
1366    while (*bytes != '\0') {
1367      const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(bytes++);
1368      // Switch on the high four bits.
1369      switch (*utf8 >> 4) {
1370      case 0x00:
1371      case 0x01:
1372      case 0x02:
1373      case 0x03:
1374      case 0x04:
1375      case 0x05:
1376      case 0x06:
1377      case 0x07:
1378        // Bit pattern 0xxx. No need for any extra bytes.
1379        break;
1380      case 0x08:
1381      case 0x09:
1382      case 0x0a:
1383      case 0x0b:
1384         // Bit patterns 10xx, which are illegal start bytes.
1385        *errorKind = "start";
1386        return utf8;
1387      case 0x0f:
1388        // Bit pattern 1111, which might be the start of a 4 byte sequence.
1389        if ((*utf8 & 0x08) == 0) {
1390          // Bit pattern 1111 0xxx, which is the start of a 4 byte sequence.
1391          // We consume one continuation byte here, and fall through to consume two more.
1392          utf8 = reinterpret_cast<const uint8_t*>(bytes++);
1393          if ((*utf8 & 0xc0) != 0x80) {
1394            *errorKind = "continuation";
1395            return utf8;
1396          }
1397        } else {
1398          *errorKind = "start";
1399          return utf8;
1400        }
1401
1402        // Fall through to the cases below to consume two more continuation bytes.
1403        FALLTHROUGH_INTENDED;
1404      case 0x0e:
1405        // Bit pattern 1110, so there are two additional bytes.
1406        utf8 = reinterpret_cast<const uint8_t*>(bytes++);
1407        if ((*utf8 & 0xc0) != 0x80) {
1408          *errorKind = "continuation";
1409          return utf8;
1410        }
1411
1412        // Fall through to consume one more continuation byte.
1413        FALLTHROUGH_INTENDED;
1414      case 0x0c:
1415      case 0x0d:
1416        // Bit pattern 110x, so there is one additional byte.
1417        utf8 = reinterpret_cast<const uint8_t*>(bytes++);
1418        if ((*utf8 & 0xc0) != 0x80) {
1419          *errorKind = "continuation";
1420          return utf8;
1421        }
1422        break;
1423      }
1424    }
1425    return 0;
1426  }
1427
1428  void AbortF(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
1429    va_list args;
1430    va_start(args, fmt);
1431    Runtime::Current()->GetJavaVM()->JniAbortV(function_name_, fmt, args);
1432    va_end(args);
1433  }
1434
1435  // The name of the JNI function being checked.
1436  const char* const function_name_;
1437
1438  int indent_;
1439
1440  const uint16_t flags_;
1441
1442  const bool has_method_;
1443
1444  DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
1445};
1446
1447/*
1448 * ===========================================================================
1449 *      Guarded arrays
1450 * ===========================================================================
1451 */
1452
1453/* this gets tucked in at the start of the buffer; struct size must be even */
1454class GuardedCopy {
1455 public:
1456  /*
1457   * Create an over-sized buffer to hold the contents of "buf".  Copy it in,
1458   * filling in the area around it with guard data.
1459   */
1460  static void* Create(void* original_buf, size_t len, bool mod_okay) {
1461    const size_t new_len = LengthIncludingRedZones(len);
1462    uint8_t* const new_buf = DebugAlloc(new_len);
1463
1464    // If modification is not expected, grab a checksum.
1465    uLong adler = 0;
1466    if (!mod_okay) {
1467      adler = adler32(adler32(0L, Z_NULL, 0), reinterpret_cast<const Bytef*>(original_buf), len);
1468    }
1469
1470    GuardedCopy* copy = new (new_buf) GuardedCopy(original_buf, len, adler);
1471
1472    // Fill begin region with canary pattern.
1473    const size_t kStartCanaryLength = (GuardedCopy::kRedZoneSize / 2) - sizeof(GuardedCopy);
1474    for (size_t i = 0, j = 0; i < kStartCanaryLength; ++i) {
1475      const_cast<char*>(copy->StartRedZone())[i] = kCanary[j];
1476      if (kCanary[j] == '\0') {
1477        j = 0;
1478      } else {
1479        j++;
1480      }
1481    }
1482
1483    // Copy the data in; note "len" could be zero.
1484    memcpy(const_cast<uint8_t*>(copy->BufferWithinRedZones()), original_buf, len);
1485
1486    // Fill end region with canary pattern.
1487    for (size_t i = 0, j = 0; i < kEndCanaryLength; ++i) {
1488      const_cast<char*>(copy->EndRedZone())[i] = kCanary[j];
1489      if (kCanary[j] == '\0') {
1490        j = 0;
1491      } else {
1492        j++;
1493      }
1494    }
1495
1496    return const_cast<uint8_t*>(copy->BufferWithinRedZones());
1497  }
1498
1499  /*
1500   * Create a guarded copy of a primitive array.  Modifications to the copied
1501   * data are allowed.  Returns a pointer to the copied data.
1502   */
1503  static void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* is_copy,
1504                                   void* original_ptr) {
1505    ScopedObjectAccess soa(env);
1506
1507    ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
1508    size_t component_size = a->GetClass()->GetComponentSize();
1509    size_t byte_count = a->GetLength() * component_size;
1510    void* result = Create(original_ptr, byte_count, true);
1511    if (is_copy != nullptr) {
1512      *is_copy = JNI_TRUE;
1513    }
1514    return result;
1515  }
1516
1517  /*
1518   * Perform the array "release" operation, which may or may not copy data
1519   * back into the managed heap, and may or may not release the underlying storage.
1520   */
1521  static void* ReleaseGuardedPACopy(const char* function_name, JNIEnv* env,
1522                                    jarray java_array ATTRIBUTE_UNUSED, void* embedded_buf,
1523                                    int mode) {
1524    ScopedObjectAccess soa(env);
1525    if (!GuardedCopy::Check(function_name, embedded_buf, true)) {
1526      return nullptr;
1527    }
1528    GuardedCopy* const copy = FromEmbedded(embedded_buf);
1529    void* original_ptr = copy->original_ptr_;
1530    if (mode != JNI_ABORT) {
1531      memcpy(original_ptr, embedded_buf, copy->original_length_);
1532    }
1533    if (mode != JNI_COMMIT) {
1534      Destroy(embedded_buf);
1535    }
1536    return original_ptr;
1537  }
1538
1539
1540  /*
1541   * Free up the guard buffer, scrub it, and return the original pointer.
1542   */
1543  static void* Destroy(void* embedded_buf) {
1544    GuardedCopy* copy = FromEmbedded(embedded_buf);
1545    void* original_ptr = const_cast<void*>(copy->original_ptr_);
1546    size_t len = LengthIncludingRedZones(copy->original_length_);
1547    DebugFree(copy, len);
1548    return original_ptr;
1549  }
1550
1551  /*
1552   * Verify the guard area and, if "modOkay" is false, that the data itself
1553   * has not been altered.
1554   *
1555   * The caller has already checked that "dataBuf" is non-null.
1556   */
1557  static bool Check(const char* function_name, const void* embedded_buf, bool mod_okay) {
1558    const GuardedCopy* copy = FromEmbedded(embedded_buf);
1559    return copy->CheckHeader(function_name, mod_okay) && copy->CheckRedZones(function_name);
1560  }
1561
1562 private:
1563  GuardedCopy(void* original_buf, size_t len, uLong adler) :
1564    magic_(kGuardMagic), adler_(adler), original_ptr_(original_buf), original_length_(len) {
1565  }
1566
1567  static uint8_t* DebugAlloc(size_t len) {
1568    void* result = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1569    if (result == MAP_FAILED) {
1570      PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed";
1571    }
1572    return reinterpret_cast<uint8_t*>(result);
1573  }
1574
1575  static void DebugFree(void* buf, size_t len) {
1576    if (munmap(buf, len) != 0) {
1577      PLOG(FATAL) << "munmap(" << buf << ", " << len << ") failed";
1578    }
1579  }
1580
1581  static size_t LengthIncludingRedZones(size_t len) {
1582    return len + kRedZoneSize;
1583  }
1584
1585  // Get the GuardedCopy from the interior pointer.
1586  static GuardedCopy* FromEmbedded(void* embedded_buf) {
1587    return reinterpret_cast<GuardedCopy*>(
1588        reinterpret_cast<uint8_t*>(embedded_buf) - (kRedZoneSize / 2));
1589  }
1590
1591  static const GuardedCopy* FromEmbedded(const void* embedded_buf) {
1592    return reinterpret_cast<const GuardedCopy*>(
1593        reinterpret_cast<const uint8_t*>(embedded_buf) - (kRedZoneSize / 2));
1594  }
1595
1596  static void AbortF(const char* jni_function_name, const char* fmt, ...) {
1597    va_list args;
1598    va_start(args, fmt);
1599    Runtime::Current()->GetJavaVM()->JniAbortV(jni_function_name, fmt, args);
1600    va_end(args);
1601  }
1602
1603  bool CheckHeader(const char* function_name, bool mod_okay) const {
1604    static const uint32_t kMagicCmp = kGuardMagic;
1605
1606    // Before we do anything with "pExtra", check the magic number.  We
1607    // do the check with memcmp rather than "==" in case the pointer is
1608    // unaligned.  If it points to completely bogus memory we're going
1609    // to crash, but there's no easy way around that.
1610    if (UNLIKELY(memcmp(&magic_, &kMagicCmp, 4) != 0)) {
1611      uint8_t buf[4];
1612      memcpy(buf, &magic_, 4);
1613      AbortF(function_name,
1614             "guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
1615             buf[3], buf[2], buf[1], buf[0], this);  // Assumes little-endian.
1616      return false;
1617    }
1618
1619    // If modification is not expected, verify checksum. Strictly speaking this is wrong: if we
1620    // told the client that we made a copy, there's no reason they can't alter the buffer.
1621    if (!mod_okay) {
1622      uLong computed_adler =
1623          adler32(adler32(0L, Z_NULL, 0), BufferWithinRedZones(), original_length_);
1624      if (computed_adler != adler_) {
1625        AbortF(function_name, "buffer modified (0x%08lx vs 0x%08lx) at address %p",
1626               computed_adler, adler_, this);
1627        return false;
1628      }
1629    }
1630    return true;
1631  }
1632
1633  bool CheckRedZones(const char* function_name) const {
1634    // Check the begin red zone.
1635    const size_t kStartCanaryLength = (GuardedCopy::kRedZoneSize / 2) - sizeof(GuardedCopy);
1636    for (size_t i = 0, j = 0; i < kStartCanaryLength; ++i) {
1637      if (UNLIKELY(StartRedZone()[i] != kCanary[j])) {
1638        AbortF(function_name, "guard pattern before buffer disturbed at %p +%zd", this, i);
1639        return false;
1640      }
1641      if (kCanary[j] == '\0') {
1642        j = 0;
1643      } else {
1644        j++;
1645      }
1646    }
1647
1648    // Check end region.
1649    for (size_t i = 0, j = 0; i < kEndCanaryLength; ++i) {
1650      if (UNLIKELY(EndRedZone()[i] != kCanary[j])) {
1651        size_t offset_from_buffer_start =
1652            &(EndRedZone()[i]) - &(StartRedZone()[kStartCanaryLength]);
1653        AbortF(function_name, "guard pattern after buffer disturbed at %p +%zd", this,
1654               offset_from_buffer_start);
1655        return false;
1656      }
1657      if (kCanary[j] == '\0') {
1658        j = 0;
1659      } else {
1660        j++;
1661      }
1662    }
1663    return true;
1664  }
1665
1666  // Location that canary value will be written before the guarded region.
1667  const char* StartRedZone() const {
1668    const uint8_t* buf = reinterpret_cast<const uint8_t*>(this);
1669    return reinterpret_cast<const char*>(buf + sizeof(GuardedCopy));
1670  }
1671
1672  // Return the interior embedded buffer.
1673  const uint8_t* BufferWithinRedZones() const {
1674    const uint8_t* embedded_buf = reinterpret_cast<const uint8_t*>(this) + (kRedZoneSize / 2);
1675    return embedded_buf;
1676  }
1677
1678  // Location that canary value will be written after the guarded region.
1679  const char* EndRedZone() const {
1680    const uint8_t* buf = reinterpret_cast<const uint8_t*>(this);
1681    size_t buf_len = LengthIncludingRedZones(original_length_);
1682    return reinterpret_cast<const char*>(buf + (buf_len - (kRedZoneSize / 2)));
1683  }
1684
1685  static constexpr size_t kRedZoneSize = 512;
1686  static constexpr size_t kEndCanaryLength = kRedZoneSize / 2;
1687
1688  // Value written before and after the guarded array.
1689  static const char* const kCanary;
1690
1691  static constexpr uint32_t kGuardMagic = 0xffd5aa96;
1692
1693  const uint32_t magic_;
1694  const uLong adler_;
1695  void* const original_ptr_;
1696  const size_t original_length_;
1697};
1698const char* const GuardedCopy::kCanary = "JNI BUFFER RED ZONE";
1699
1700/*
1701 * ===========================================================================
1702 *      JNI functions
1703 * ===========================================================================
1704 */
1705
1706class CheckJNI {
1707 public:
1708  static jint GetVersion(JNIEnv* env) {
1709    ScopedObjectAccess soa(env);
1710    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1711    JniValueType args[1] = {{.E = env }};
1712    if (sc.Check(soa, true, "E", args)) {
1713      JniValueType result;
1714      result.I = baseEnv(env)->GetVersion(env);
1715      if (sc.Check(soa, false, "I", &result)) {
1716        return result.I;
1717      }
1718    }
1719    return JNI_ERR;
1720  }
1721
1722  static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
1723    ScopedObjectAccess soa(env);
1724    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1725    JniValueType args[2] = {{.E = env }, {.p = vm}};
1726    if (sc.Check(soa, true, "Ep", args)) {
1727      JniValueType result;
1728      result.i = baseEnv(env)->GetJavaVM(env, vm);
1729      if (sc.Check(soa, false, "i", &result)) {
1730        return result.i;
1731      }
1732    }
1733    return JNI_ERR;
1734  }
1735
1736  static jint RegisterNatives(JNIEnv* env, jclass c, const JNINativeMethod* methods, jint nMethods) {
1737    ScopedObjectAccess soa(env);
1738    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1739    JniValueType args[4] = {{.E = env }, {.c = c}, {.p = methods}, {.I = nMethods}};
1740    if (sc.Check(soa, true, "EcpI", args)) {
1741      JniValueType result;
1742      result.i = baseEnv(env)->RegisterNatives(env, c, methods, nMethods);
1743      if (sc.Check(soa, false, "i", &result)) {
1744        return result.i;
1745      }
1746    }
1747    return JNI_ERR;
1748  }
1749
1750  static jint UnregisterNatives(JNIEnv* env, jclass c) {
1751    ScopedObjectAccess soa(env);
1752    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1753    JniValueType args[2] = {{.E = env }, {.c = c}};
1754    if (sc.Check(soa, true, "Ec", args)) {
1755      JniValueType result;
1756      result.i = baseEnv(env)->UnregisterNatives(env, c);
1757      if (sc.Check(soa, false, "i", &result)) {
1758        return result.i;
1759      }
1760    }
1761    return JNI_ERR;
1762  }
1763
1764  static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
1765    // Note: we use "EL" here but "Ep" has been used in the past on the basis that we'd like to
1766    // know the object is invalid. The spec says that passing invalid objects or even ones that
1767    // are deleted isn't supported.
1768    ScopedObjectAccess soa(env);
1769    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1770    JniValueType args[2] = {{.E = env }, {.L = obj}};
1771    if (sc.Check(soa, true, "EL", args)) {
1772      JniValueType result;
1773      result.w = baseEnv(env)->GetObjectRefType(env, obj);
1774      if (sc.Check(soa, false, "w", &result)) {
1775        return result.w;
1776      }
1777    }
1778    return JNIInvalidRefType;
1779  }
1780
1781  static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf,
1782                            jsize bufLen) {
1783    ScopedObjectAccess soa(env);
1784    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1785    JniValueType args[5] = {{.E = env}, {.u = name}, {.L = loader}, {.p = buf}, {.z = bufLen}};
1786    if (sc.Check(soa, true, "EuLpz", args) && sc.CheckClassName(name)) {
1787      JniValueType result;
1788      result.c = baseEnv(env)->DefineClass(env, name, loader, buf, bufLen);
1789      if (sc.Check(soa, false, "c", &result)) {
1790        return result.c;
1791      }
1792    }
1793    return nullptr;
1794  }
1795
1796  static jclass FindClass(JNIEnv* env, const char* name) {
1797    ScopedObjectAccess soa(env);
1798    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1799    JniValueType args[2] = {{.E = env}, {.u = name}};
1800    if (sc.Check(soa, true, "Eu", args) && sc.CheckClassName(name)) {
1801      JniValueType result;
1802      result.c = baseEnv(env)->FindClass(env, name);
1803      if (sc.Check(soa, false, "c", &result)) {
1804        return result.c;
1805      }
1806    }
1807    return nullptr;
1808  }
1809
1810  static jclass GetSuperclass(JNIEnv* env, jclass c) {
1811    ScopedObjectAccess soa(env);
1812    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1813    JniValueType args[2] = {{.E = env}, {.c = c}};
1814    if (sc.Check(soa, true, "Ec", args)) {
1815      JniValueType result;
1816      result.c = baseEnv(env)->GetSuperclass(env, c);
1817      if (sc.Check(soa, false, "c", &result)) {
1818        return result.c;
1819      }
1820    }
1821    return nullptr;
1822  }
1823
1824  static jboolean IsAssignableFrom(JNIEnv* env, jclass c1, jclass c2) {
1825    ScopedObjectAccess soa(env);
1826    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1827    JniValueType args[3] = {{.E = env}, {.c = c1}, {.c = c2}};
1828    if (sc.Check(soa, true, "Ecc", args)) {
1829      JniValueType result;
1830      result.b = baseEnv(env)->IsAssignableFrom(env, c1, c2);
1831      if (sc.Check(soa, false, "b", &result)) {
1832        return result.b;
1833      }
1834    }
1835    return JNI_FALSE;
1836  }
1837
1838  static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
1839    ScopedObjectAccess soa(env);
1840    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1841    JniValueType args[2] = {{.E = env}, {.L = method}};
1842    if (sc.Check(soa, true, "EL", args) && sc.CheckReflectedMethod(soa, method)) {
1843      JniValueType result;
1844      result.m = baseEnv(env)->FromReflectedMethod(env, method);
1845      if (sc.Check(soa, false, "m", &result)) {
1846        return result.m;
1847      }
1848    }
1849    return nullptr;
1850  }
1851
1852  static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
1853    ScopedObjectAccess soa(env);
1854    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1855    JniValueType args[2] = {{.E = env}, {.L = field}};
1856    if (sc.Check(soa, true, "EL", args) && sc.CheckReflectedField(soa, field)) {
1857      JniValueType result;
1858      result.f = baseEnv(env)->FromReflectedField(env, field);
1859      if (sc.Check(soa, false, "f", &result)) {
1860        return result.f;
1861      }
1862    }
1863    return nullptr;
1864  }
1865
1866  static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
1867    ScopedObjectAccess soa(env);
1868    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1869    JniValueType args[4] = {{.E = env}, {.c = cls}, {.m = mid}, {.I = isStatic}};
1870    if (sc.Check(soa, true, "Ecmb", args)) {
1871      JniValueType result;
1872      result.L = baseEnv(env)->ToReflectedMethod(env, cls, mid, isStatic);
1873      if (sc.Check(soa, false, "L", &result) && (result.L != nullptr)) {
1874        DCHECK(sc.CheckReflectedMethod(soa, result.L));
1875        return result.L;
1876      }
1877    }
1878    return nullptr;
1879  }
1880
1881  static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
1882    ScopedObjectAccess soa(env);
1883    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1884    JniValueType args[4] = {{.E = env}, {.c = cls}, {.f = fid}, {.I = isStatic}};
1885    if (sc.Check(soa, true, "Ecfb", args)) {
1886      JniValueType result;
1887      result.L = baseEnv(env)->ToReflectedField(env, cls, fid, isStatic);
1888      if (sc.Check(soa, false, "L", &result) && (result.L != nullptr)) {
1889        DCHECK(sc.CheckReflectedField(soa, result.L));
1890        return result.L;
1891      }
1892    }
1893    return nullptr;
1894  }
1895
1896  static jint Throw(JNIEnv* env, jthrowable obj) {
1897    ScopedObjectAccess soa(env);
1898    ScopedCheck sc(kFlag_Default, __FUNCTION__);
1899    JniValueType args[2] = {{.E = env}, {.t = obj}};
1900    if (sc.Check(soa, true, "Et", args) && sc.CheckThrowable(soa, obj)) {
1901      JniValueType result;
1902      result.i = baseEnv(env)->Throw(env, obj);
1903      if (sc.Check(soa, false, "i", &result)) {
1904        return result.i;
1905      }
1906    }
1907    return JNI_ERR;
1908  }
1909
1910  static jint ThrowNew(JNIEnv* env, jclass c, const char* message) {
1911    ScopedObjectAccess soa(env);
1912    ScopedCheck sc(kFlag_NullableUtf, __FUNCTION__);
1913    JniValueType args[3] = {{.E = env}, {.c = c}, {.u = message}};
1914    if (sc.Check(soa, true, "Ecu", args) && sc.CheckThrowableClass(soa, c)) {
1915      JniValueType result;
1916      result.i = baseEnv(env)->ThrowNew(env, c, message);
1917      if (sc.Check(soa, false, "i", &result)) {
1918        return result.i;
1919      }
1920    }
1921    return JNI_ERR;
1922  }
1923
1924  static jthrowable ExceptionOccurred(JNIEnv* env) {
1925    ScopedObjectAccess soa(env);
1926    ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
1927    JniValueType args[1] = {{.E = env}};
1928    if (sc.Check(soa, true, "E", args)) {
1929      JniValueType result;
1930      result.t = baseEnv(env)->ExceptionOccurred(env);
1931      if (sc.Check(soa, false, "t", &result)) {
1932        return result.t;
1933      }
1934    }
1935    return nullptr;
1936  }
1937
1938  static void ExceptionDescribe(JNIEnv* env) {
1939    ScopedObjectAccess soa(env);
1940    ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
1941    JniValueType args[1] = {{.E = env}};
1942    if (sc.Check(soa, true, "E", args)) {
1943      JniValueType result;
1944      baseEnv(env)->ExceptionDescribe(env);
1945      result.V = nullptr;
1946      sc.Check(soa, false, "V", &result);
1947    }
1948  }
1949
1950  static void ExceptionClear(JNIEnv* env) {
1951    ScopedObjectAccess soa(env);
1952    ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
1953    JniValueType args[1] = {{.E = env}};
1954    if (sc.Check(soa, true, "E", args)) {
1955      JniValueType result;
1956      baseEnv(env)->ExceptionClear(env);
1957      result.V = nullptr;
1958      sc.Check(soa, false, "V", &result);
1959    }
1960  }
1961
1962  static jboolean ExceptionCheck(JNIEnv* env) {
1963    ScopedObjectAccess soa(env);
1964    ScopedCheck sc(kFlag_CritOkay | kFlag_ExcepOkay, __FUNCTION__);
1965    JniValueType args[1] = {{.E = env}};
1966    if (sc.Check(soa, true, "E", args)) {
1967      JniValueType result;
1968      result.b = baseEnv(env)->ExceptionCheck(env);
1969      if (sc.Check(soa, false, "b", &result)) {
1970        return result.b;
1971      }
1972    }
1973    return JNI_FALSE;
1974  }
1975
1976  static void FatalError(JNIEnv* env, const char* msg) {
1977    // The JNI specification doesn't say it's okay to call FatalError with a pending exception,
1978    // but you're about to abort anyway, and it's quite likely that you have a pending exception,
1979    // and it's not unimaginable that you don't know that you do. So we allow it.
1980    ScopedObjectAccess soa(env);
1981    ScopedCheck sc(kFlag_ExcepOkay | kFlag_NullableUtf, __FUNCTION__);
1982    JniValueType args[2] = {{.E = env}, {.u = msg}};
1983    if (sc.Check(soa, true, "Eu", args)) {
1984      JniValueType result;
1985      baseEnv(env)->FatalError(env, msg);
1986      // Unreachable.
1987      result.V = nullptr;
1988      sc.Check(soa, false, "V", &result);
1989    }
1990  }
1991
1992  static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1993    ScopedObjectAccess soa(env);
1994    ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
1995    JniValueType args[2] = {{.E = env}, {.I = capacity}};
1996    if (sc.Check(soa, true, "EI", args)) {
1997      JniValueType result;
1998      result.i = baseEnv(env)->PushLocalFrame(env, capacity);
1999      if (sc.Check(soa, false, "i", &result)) {
2000        return result.i;
2001      }
2002    }
2003    return JNI_ERR;
2004  }
2005
2006  static jobject PopLocalFrame(JNIEnv* env, jobject res) {
2007    ScopedObjectAccess soa(env);
2008    ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
2009    JniValueType args[2] = {{.E = env}, {.L = res}};
2010    if (sc.Check(soa, true, "EL", args)) {
2011      JniValueType result;
2012      result.L = baseEnv(env)->PopLocalFrame(env, res);
2013      sc.Check(soa, false, "L", &result);
2014      return result.L;
2015    }
2016    return nullptr;
2017  }
2018
2019  static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
2020    return NewRef(__FUNCTION__, env, obj, kGlobal);
2021  }
2022
2023  static jobject NewLocalRef(JNIEnv* env, jobject obj) {
2024    return NewRef(__FUNCTION__, env, obj, kLocal);
2025  }
2026
2027  static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
2028    return NewRef(__FUNCTION__, env, obj, kWeakGlobal);
2029  }
2030
2031  static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
2032    DeleteRef(__FUNCTION__, env, obj, kGlobal);
2033  }
2034
2035  static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
2036    DeleteRef(__FUNCTION__, env, obj, kWeakGlobal);
2037  }
2038
2039  static void DeleteLocalRef(JNIEnv* env, jobject obj) {
2040    DeleteRef(__FUNCTION__, env, obj, kLocal);
2041  }
2042
2043  static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
2044    ScopedObjectAccess soa(env);
2045    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2046    JniValueType args[2] = {{.E = env}, {.I = capacity}};
2047    if (sc.Check(soa, true, "EI", args)) {
2048      JniValueType result;
2049      result.i = baseEnv(env)->EnsureLocalCapacity(env, capacity);
2050      if (sc.Check(soa, false, "i", &result)) {
2051        return result.i;
2052      }
2053    }
2054    return JNI_ERR;
2055  }
2056
2057  static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
2058    ScopedObjectAccess soa(env);
2059    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2060    JniValueType args[3] = {{.E = env}, {.L = ref1}, {.L = ref2}};
2061    if (sc.Check(soa, true, "ELL", args)) {
2062      JniValueType result;
2063      result.b = baseEnv(env)->IsSameObject(env, ref1, ref2);
2064      if (sc.Check(soa, false, "b", &result)) {
2065        return result.b;
2066      }
2067    }
2068    return JNI_FALSE;
2069  }
2070
2071  static jobject AllocObject(JNIEnv* env, jclass c) {
2072    ScopedObjectAccess soa(env);
2073    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2074    JniValueType args[2] = {{.E = env}, {.c = c}};
2075    if (sc.Check(soa, true, "Ec", args) && sc.CheckInstantiableNonArray(soa, c)) {
2076      JniValueType result;
2077      result.L = baseEnv(env)->AllocObject(env, c);
2078      if (sc.Check(soa, false, "L", &result)) {
2079        return result.L;
2080      }
2081    }
2082    return nullptr;
2083  }
2084
2085  static jobject NewObjectV(JNIEnv* env, jclass c, jmethodID mid, va_list vargs) {
2086    ScopedObjectAccess soa(env);
2087    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2088    VarArgs rest(mid, vargs);
2089    JniValueType args[4] = {{.E = env}, {.c = c}, {.m = mid}, {.va = &rest}};
2090    if (sc.Check(soa, true, "Ecm.", args) && sc.CheckInstantiableNonArray(soa, c) &&
2091        sc.CheckConstructor(mid)) {
2092      JniValueType result;
2093      result.L = baseEnv(env)->NewObjectV(env, c, mid, vargs);
2094      if (sc.Check(soa, false, "L", &result)) {
2095        return result.L;
2096      }
2097    }
2098    return nullptr;
2099  }
2100
2101  static jobject NewObject(JNIEnv* env, jclass c, jmethodID mid, ...) {
2102    va_list args;
2103    va_start(args, mid);
2104    jobject result = NewObjectV(env, c, mid, args);
2105    va_end(args);
2106    return result;
2107  }
2108
2109  static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
2110    ScopedObjectAccess soa(env);
2111    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2112    VarArgs rest(mid, vargs);
2113    JniValueType args[4] = {{.E = env}, {.c = c}, {.m = mid}, {.va = &rest}};
2114    if (sc.Check(soa, true, "Ecm.", args) && sc.CheckInstantiableNonArray(soa, c) &&
2115        sc.CheckConstructor(mid)) {
2116      JniValueType result;
2117      result.L = baseEnv(env)->NewObjectA(env, c, mid, vargs);
2118      if (sc.Check(soa, false, "L", &result)) {
2119        return result.L;
2120      }
2121    }
2122    return nullptr;
2123  }
2124
2125  static jclass GetObjectClass(JNIEnv* env, jobject obj) {
2126    ScopedObjectAccess soa(env);
2127    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2128    JniValueType args[2] = {{.E = env}, {.L = obj}};
2129    if (sc.Check(soa, true, "EL", args)) {
2130      JniValueType result;
2131      result.c = baseEnv(env)->GetObjectClass(env, obj);
2132      if (sc.Check(soa, false, "c", &result)) {
2133        return result.c;
2134      }
2135    }
2136    return nullptr;
2137  }
2138
2139  static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass c) {
2140    ScopedObjectAccess soa(env);
2141    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2142    JniValueType args[3] = {{.E = env}, {.L = obj}, {.c = c}};
2143    if (sc.Check(soa, true, "ELc", args)) {
2144      JniValueType result;
2145      result.b = baseEnv(env)->IsInstanceOf(env, obj, c);
2146      if (sc.Check(soa, false, "b", &result)) {
2147        return result.b;
2148      }
2149    }
2150    return JNI_FALSE;
2151  }
2152
2153  static jmethodID GetMethodID(JNIEnv* env, jclass c, const char* name, const char* sig) {
2154    return GetMethodIDInternal(__FUNCTION__, env, c, name, sig, false);
2155  }
2156
2157  static jmethodID GetStaticMethodID(JNIEnv* env, jclass c, const char* name, const char* sig) {
2158    return GetMethodIDInternal(__FUNCTION__, env, c, name, sig, true);
2159  }
2160
2161  static jfieldID GetFieldID(JNIEnv* env, jclass c, const char* name, const char* sig) {
2162    return GetFieldIDInternal(__FUNCTION__, env, c, name, sig, false);
2163  }
2164
2165  static jfieldID GetStaticFieldID(JNIEnv* env, jclass c, const char* name, const char* sig) {
2166    return GetFieldIDInternal(__FUNCTION__, env, c, name, sig, true);
2167  }
2168
2169#define FIELD_ACCESSORS(jtype, name, ptype, shorty, slot_sized_shorty)  \
2170  static jtype GetStatic##name##Field(JNIEnv* env, jclass c, jfieldID fid) { \
2171    return GetField(__FUNCTION__, env, c, fid, true, ptype).shorty; \
2172  } \
2173  \
2174  static jtype Get##name##Field(JNIEnv* env, jobject obj, jfieldID fid) { \
2175    return GetField(__FUNCTION__, env, obj, fid, false, ptype).shorty; \
2176  } \
2177  \
2178  static void SetStatic##name##Field(JNIEnv* env, jclass c, jfieldID fid, jtype v) { \
2179    JniValueType value; \
2180    value.slot_sized_shorty = v; \
2181    SetField(__FUNCTION__, env, c, fid, true, ptype, value); \
2182  } \
2183  \
2184  static void Set##name##Field(JNIEnv* env, jobject obj, jfieldID fid, jtype v) { \
2185    JniValueType value; \
2186    value.slot_sized_shorty = v; \
2187    SetField(__FUNCTION__, env, obj, fid, false, ptype, value); \
2188  }
2189
2190  FIELD_ACCESSORS(jobject, Object, Primitive::kPrimNot, L, L)
2191  FIELD_ACCESSORS(jboolean, Boolean, Primitive::kPrimBoolean, Z, I)
2192  FIELD_ACCESSORS(jbyte, Byte, Primitive::kPrimByte, B, I)
2193  FIELD_ACCESSORS(jchar, Char, Primitive::kPrimChar, C, I)
2194  FIELD_ACCESSORS(jshort, Short, Primitive::kPrimShort, S, I)
2195  FIELD_ACCESSORS(jint, Int, Primitive::kPrimInt, I, I)
2196  FIELD_ACCESSORS(jlong, Long, Primitive::kPrimLong, J, J)
2197  FIELD_ACCESSORS(jfloat, Float, Primitive::kPrimFloat, F, F)
2198  FIELD_ACCESSORS(jdouble, Double, Primitive::kPrimDouble, D, D)
2199#undef FIELD_ACCESSORS
2200
2201  static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* vargs) {
2202    CallMethodA(__FUNCTION__, env, obj, nullptr, mid, vargs, Primitive::kPrimVoid, kVirtual);
2203  }
2204
2205  static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass c, jmethodID mid,
2206                                        jvalue* vargs) {
2207    CallMethodA(__FUNCTION__, env, obj, c, mid, vargs, Primitive::kPrimVoid, kDirect);
2208  }
2209
2210  static void CallStaticVoidMethodA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
2211    CallMethodA(__FUNCTION__, env, nullptr, c, mid, vargs, Primitive::kPrimVoid, kStatic);
2212  }
2213
2214  static void CallVoidMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list vargs) {
2215    CallMethodV(__FUNCTION__, env, obj, nullptr, mid, vargs, Primitive::kPrimVoid, kVirtual);
2216  }
2217
2218  static void CallNonvirtualVoidMethodV(JNIEnv* env, jobject obj, jclass c, jmethodID mid,
2219                                        va_list vargs) {
2220    CallMethodV(__FUNCTION__, env, obj, c, mid, vargs, Primitive::kPrimVoid, kDirect);
2221  }
2222
2223  static void CallStaticVoidMethodV(JNIEnv* env, jclass c, jmethodID mid, va_list vargs) {
2224    CallMethodV(__FUNCTION__, env, nullptr, c, mid, vargs, Primitive::kPrimVoid, kStatic);
2225  }
2226
2227  static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
2228    va_list vargs;
2229    va_start(vargs, mid);
2230    CallMethodV(__FUNCTION__, env, obj, nullptr, mid, vargs, Primitive::kPrimVoid, kVirtual);
2231    va_end(vargs);
2232  }
2233
2234  static void CallNonvirtualVoidMethod(JNIEnv* env, jobject obj, jclass c, jmethodID mid, ...) {
2235    va_list vargs;
2236    va_start(vargs, mid);
2237    CallMethodV(__FUNCTION__, env, obj, c, mid, vargs, Primitive::kPrimVoid, kDirect);
2238    va_end(vargs);
2239  }
2240
2241  static void CallStaticVoidMethod(JNIEnv* env, jclass c, jmethodID mid, ...) {
2242    va_list vargs;
2243    va_start(vargs, mid);
2244    CallMethodV(__FUNCTION__, env, nullptr, c, mid, vargs, Primitive::kPrimVoid, kStatic);
2245    va_end(vargs);
2246  }
2247
2248#define CALL(rtype, name, ptype, shorty) \
2249  static rtype Call##name##MethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* vargs) { \
2250    return CallMethodA(__FUNCTION__, env, obj, nullptr, mid, vargs, ptype, kVirtual).shorty; \
2251  } \
2252  \
2253  static rtype CallNonvirtual##name##MethodA(JNIEnv* env, jobject obj, jclass c, jmethodID mid, \
2254                                             jvalue* vargs) { \
2255    return CallMethodA(__FUNCTION__, env, obj, c, mid, vargs, ptype, kDirect).shorty; \
2256  } \
2257  \
2258  static rtype CallStatic##name##MethodA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) { \
2259    return CallMethodA(__FUNCTION__, env, nullptr, c, mid, vargs, ptype, kStatic).shorty; \
2260  } \
2261  \
2262  static rtype Call##name##MethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list vargs) { \
2263    return CallMethodV(__FUNCTION__, env, obj, nullptr, mid, vargs, ptype, kVirtual).shorty; \
2264  } \
2265  \
2266  static rtype CallNonvirtual##name##MethodV(JNIEnv* env, jobject obj, jclass c, jmethodID mid, \
2267                                             va_list vargs) { \
2268    return CallMethodV(__FUNCTION__, env, obj, c, mid, vargs, ptype, kDirect).shorty; \
2269  } \
2270  \
2271  static rtype CallStatic##name##MethodV(JNIEnv* env, jclass c, jmethodID mid, va_list vargs) { \
2272    return CallMethodV(__FUNCTION__, env, nullptr, c, mid, vargs, ptype, kStatic).shorty; \
2273  } \
2274  \
2275  static rtype Call##name##Method(JNIEnv* env, jobject obj, jmethodID mid, ...) { \
2276    va_list vargs; \
2277    va_start(vargs, mid); \
2278    rtype result = \
2279        CallMethodV(__FUNCTION__, env, obj, nullptr, mid, vargs, ptype, kVirtual).shorty; \
2280    va_end(vargs); \
2281    return result; \
2282  } \
2283  \
2284  static rtype CallNonvirtual##name##Method(JNIEnv* env, jobject obj, jclass c, jmethodID mid, \
2285                                            ...) { \
2286    va_list vargs; \
2287    va_start(vargs, mid); \
2288    rtype result = \
2289        CallMethodV(__FUNCTION__, env, obj, c, mid, vargs, ptype, kDirect).shorty; \
2290    va_end(vargs); \
2291    return result; \
2292  } \
2293  \
2294  static rtype CallStatic##name##Method(JNIEnv* env, jclass c, jmethodID mid, ...) { \
2295    va_list vargs; \
2296    va_start(vargs, mid); \
2297    rtype result = \
2298        CallMethodV(__FUNCTION__, env, nullptr, c, mid, vargs, ptype, kStatic).shorty; \
2299    va_end(vargs); \
2300    return result; \
2301  }
2302
2303  CALL(jobject, Object, Primitive::kPrimNot, L)
2304  CALL(jboolean, Boolean, Primitive::kPrimBoolean, Z)
2305  CALL(jbyte, Byte, Primitive::kPrimByte, B)
2306  CALL(jchar, Char, Primitive::kPrimChar, C)
2307  CALL(jshort, Short, Primitive::kPrimShort, S)
2308  CALL(jint, Int, Primitive::kPrimInt, I)
2309  CALL(jlong, Long, Primitive::kPrimLong, J)
2310  CALL(jfloat, Float, Primitive::kPrimFloat, F)
2311  CALL(jdouble, Double, Primitive::kPrimDouble, D)
2312#undef CALL
2313
2314  static jstring NewString(JNIEnv* env, const jchar* unicode_chars, jsize len) {
2315    ScopedObjectAccess soa(env);
2316    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2317    JniValueType args[3] = {{.E = env}, {.p = unicode_chars}, {.z = len}};
2318    if (sc.Check(soa, true, "Epz", args)) {
2319      JniValueType result;
2320      result.s = baseEnv(env)->NewString(env, unicode_chars, len);
2321      if (sc.Check(soa, false, "s", &result)) {
2322        return result.s;
2323      }
2324    }
2325    return nullptr;
2326  }
2327
2328  static jstring NewStringUTF(JNIEnv* env, const char* chars) {
2329    ScopedObjectAccess soa(env);
2330    ScopedCheck sc(kFlag_NullableUtf, __FUNCTION__);
2331    JniValueType args[2] = {{.E = env}, {.u = chars}};
2332    if (sc.Check(soa, true, "Eu", args)) {
2333      JniValueType result;
2334      // TODO: stale? show pointer and truncate string.
2335      result.s = baseEnv(env)->NewStringUTF(env, chars);
2336      if (sc.Check(soa, false, "s", &result)) {
2337        return result.s;
2338      }
2339    }
2340    return nullptr;
2341  }
2342
2343  static jsize GetStringLength(JNIEnv* env, jstring string) {
2344    ScopedObjectAccess soa(env);
2345    ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
2346    JniValueType args[2] = {{.E = env}, {.s = string}};
2347    if (sc.Check(soa, true, "Es", args)) {
2348      JniValueType result;
2349      result.z = baseEnv(env)->GetStringLength(env, string);
2350      if (sc.Check(soa, false, "z", &result)) {
2351        return result.z;
2352      }
2353    }
2354    return JNI_ERR;
2355  }
2356
2357  static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
2358    ScopedObjectAccess soa(env);
2359    ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
2360    JniValueType args[2] = {{.E = env}, {.s = string}};
2361    if (sc.Check(soa, true, "Es", args)) {
2362      JniValueType result;
2363      result.z = baseEnv(env)->GetStringUTFLength(env, string);
2364      if (sc.Check(soa, false, "z", &result)) {
2365        return result.z;
2366      }
2367    }
2368    return JNI_ERR;
2369  }
2370
2371  static const jchar* GetStringChars(JNIEnv* env, jstring string, jboolean* is_copy) {
2372    return reinterpret_cast<const jchar*>(GetStringCharsInternal(__FUNCTION__, env, string,
2373                                                                 is_copy, false, false));
2374  }
2375
2376  static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* is_copy) {
2377    return reinterpret_cast<const char*>(GetStringCharsInternal(__FUNCTION__, env, string,
2378                                                                is_copy, true, false));
2379  }
2380
2381  static const jchar* GetStringCritical(JNIEnv* env, jstring string, jboolean* is_copy) {
2382    return reinterpret_cast<const jchar*>(GetStringCharsInternal(__FUNCTION__, env, string,
2383                                                                 is_copy, false, true));
2384  }
2385
2386  static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
2387    ReleaseStringCharsInternal(__FUNCTION__, env, string, chars, false, false);
2388  }
2389
2390  static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
2391    ReleaseStringCharsInternal(__FUNCTION__, env, string, utf, true, false);
2392  }
2393
2394  static void ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* chars) {
2395    ReleaseStringCharsInternal(__FUNCTION__, env, string, chars, false, true);
2396  }
2397
2398  static void GetStringRegion(JNIEnv* env, jstring string, jsize start, jsize len, jchar* buf) {
2399    ScopedObjectAccess soa(env);
2400    ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
2401    JniValueType args[5] = {{.E = env}, {.s = string}, {.z = start}, {.z = len}, {.p = buf}};
2402    // Note: the start and len arguments are checked as 'I' rather than 'z' as invalid indices
2403    // result in ArrayIndexOutOfBoundsExceptions in the base implementation.
2404    if (sc.Check(soa, true, "EsIIp", args)) {
2405      baseEnv(env)->GetStringRegion(env, string, start, len, buf);
2406      JniValueType result;
2407      result.V = nullptr;
2408      sc.Check(soa, false, "V", &result);
2409    }
2410  }
2411
2412  static void GetStringUTFRegion(JNIEnv* env, jstring string, jsize start, jsize len, char* buf) {
2413    ScopedObjectAccess soa(env);
2414    ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
2415    JniValueType args[5] = {{.E = env}, {.s = string}, {.z = start}, {.z = len}, {.p = buf}};
2416    // Note: the start and len arguments are checked as 'I' rather than 'z' as invalid indices
2417    // result in ArrayIndexOutOfBoundsExceptions in the base implementation.
2418    if (sc.Check(soa, true, "EsIIp", args)) {
2419      baseEnv(env)->GetStringUTFRegion(env, string, start, len, buf);
2420      JniValueType result;
2421      result.V = nullptr;
2422      sc.Check(soa, false, "V", &result);
2423    }
2424  }
2425
2426  static jsize GetArrayLength(JNIEnv* env, jarray array) {
2427    ScopedObjectAccess soa(env);
2428    ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
2429    JniValueType args[2] = {{.E = env}, {.a = array}};
2430    if (sc.Check(soa, true, "Ea", args)) {
2431      JniValueType result;
2432      result.z = baseEnv(env)->GetArrayLength(env, array);
2433      if (sc.Check(soa, false, "z", &result)) {
2434        return result.z;
2435      }
2436    }
2437    return JNI_ERR;
2438  }
2439
2440  static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_class,
2441                                     jobject initial_element) {
2442    ScopedObjectAccess soa(env);
2443    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2444    JniValueType args[4] =
2445        {{.E = env}, {.z = length}, {.c = element_class}, {.L = initial_element}};
2446    if (sc.Check(soa, true, "EzcL", args)) {
2447      JniValueType result;
2448      // Note: assignability tests of initial_element are done in the base implementation.
2449      result.a = baseEnv(env)->NewObjectArray(env, length, element_class, initial_element);
2450      if (sc.Check(soa, false, "a", &result)) {
2451        return down_cast<jobjectArray>(result.a);
2452      }
2453    }
2454    return nullptr;
2455  }
2456
2457  static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
2458    ScopedObjectAccess soa(env);
2459    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2460    JniValueType args[3] = {{.E = env}, {.a = array}, {.z = index}};
2461    if (sc.Check(soa, true, "Eaz", args)) {
2462      JniValueType result;
2463      result.L = baseEnv(env)->GetObjectArrayElement(env, array, index);
2464      if (sc.Check(soa, false, "L", &result)) {
2465        return result.L;
2466      }
2467    }
2468    return nullptr;
2469  }
2470
2471  static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
2472    ScopedObjectAccess soa(env);
2473    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2474    JniValueType args[4] = {{.E = env}, {.a = array}, {.z = index}, {.L = value}};
2475    // Note: the index arguments is checked as 'I' rather than 'z' as invalid indices result in
2476    // ArrayIndexOutOfBoundsExceptions in the base implementation. Similarly invalid stores result
2477    // in ArrayStoreExceptions.
2478    if (sc.Check(soa, true, "EaIL", args)) {
2479      baseEnv(env)->SetObjectArrayElement(env, array, index, value);
2480      JniValueType result;
2481      result.V = nullptr;
2482      sc.Check(soa, false, "V", &result);
2483    }
2484  }
2485
2486  static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
2487    return down_cast<jbooleanArray>(NewPrimitiveArray(__FUNCTION__, env, length,
2488                                                      Primitive::kPrimBoolean));
2489  }
2490
2491  static jbyteArray NewByteArray(JNIEnv* env, jsize length) {
2492    return down_cast<jbyteArray>(NewPrimitiveArray(__FUNCTION__, env, length,
2493                                                   Primitive::kPrimByte));
2494  }
2495
2496  static jcharArray NewCharArray(JNIEnv* env, jsize length) {
2497    return down_cast<jcharArray>(NewPrimitiveArray(__FUNCTION__, env, length,
2498                                                   Primitive::kPrimChar));
2499  }
2500
2501  static jshortArray NewShortArray(JNIEnv* env, jsize length) {
2502    return down_cast<jshortArray>(NewPrimitiveArray(__FUNCTION__, env, length,
2503                                                    Primitive::kPrimShort));
2504  }
2505
2506  static jintArray NewIntArray(JNIEnv* env, jsize length) {
2507    return down_cast<jintArray>(NewPrimitiveArray(__FUNCTION__, env, length, Primitive::kPrimInt));
2508  }
2509
2510  static jlongArray NewLongArray(JNIEnv* env, jsize length) {
2511    return down_cast<jlongArray>(NewPrimitiveArray(__FUNCTION__, env, length,
2512                                                   Primitive::kPrimLong));
2513  }
2514
2515  static jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
2516    return down_cast<jfloatArray>(NewPrimitiveArray(__FUNCTION__, env, length,
2517                                                    Primitive::kPrimFloat));
2518  }
2519
2520  static jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
2521    return down_cast<jdoubleArray>(NewPrimitiveArray(__FUNCTION__, env, length,
2522                                                     Primitive::kPrimDouble));
2523  }
2524
2525// NOLINT added to avoid wrong warning/fix from clang-tidy.
2526#define PRIMITIVE_ARRAY_FUNCTIONS(ctype, name, ptype) \
2527  static ctype* Get##name##ArrayElements(JNIEnv* env, ctype##Array array, jboolean* is_copy) { /* NOLINT */ \
2528    return reinterpret_cast<ctype*>( /* NOLINT */ \
2529        GetPrimitiveArrayElements(__FUNCTION__, ptype, env, array, is_copy)); \
2530  } \
2531  \
2532  static void Release##name##ArrayElements(JNIEnv* env, ctype##Array array, ctype* elems, /* NOLINT */ \
2533                                           jint mode) { \
2534    ReleasePrimitiveArrayElements(__FUNCTION__, ptype, env, array, elems, mode); \
2535  } \
2536  \
2537  static void Get##name##ArrayRegion(JNIEnv* env, ctype##Array array, jsize start, jsize len, \
2538                                     ctype* buf) { /* NOLINT */ \
2539    GetPrimitiveArrayRegion(__FUNCTION__, ptype, env, array, start, len, buf); \
2540  } \
2541  \
2542  static void Set##name##ArrayRegion(JNIEnv* env, ctype##Array array, jsize start, jsize len, \
2543                                     const ctype* buf) { \
2544    SetPrimitiveArrayRegion(__FUNCTION__, ptype, env, array, start, len, buf); \
2545  }
2546
2547  PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, Primitive::kPrimBoolean)
2548  PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, Primitive::kPrimByte)
2549  PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, Primitive::kPrimChar)
2550  PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, Primitive::kPrimShort)
2551  PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, Primitive::kPrimInt)
2552  PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, Primitive::kPrimLong)
2553  PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, Primitive::kPrimFloat)
2554  PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, Primitive::kPrimDouble)
2555#undef PRIMITIVE_ARRAY_FUNCTIONS
2556
2557  static jint MonitorEnter(JNIEnv* env, jobject obj) {
2558    ScopedObjectAccess soa(env);
2559    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2560    JniValueType args[2] = {{.E = env}, {.L = obj}};
2561    if (sc.Check(soa, true, "EL", args)) {
2562      if (obj != nullptr) {
2563        down_cast<JNIEnvExt*>(env)->RecordMonitorEnter(obj);
2564      }
2565      JniValueType result;
2566      result.i = baseEnv(env)->MonitorEnter(env, obj);
2567      if (sc.Check(soa, false, "i", &result)) {
2568        return result.i;
2569      }
2570    }
2571    return JNI_ERR;
2572  }
2573
2574  static jint MonitorExit(JNIEnv* env, jobject obj) {
2575    ScopedObjectAccess soa(env);
2576    ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
2577    JniValueType args[2] = {{.E = env}, {.L = obj}};
2578    if (sc.Check(soa, true, "EL", args)) {
2579      if (obj != nullptr) {
2580        down_cast<JNIEnvExt*>(env)->CheckMonitorRelease(obj);
2581      }
2582      JniValueType result;
2583      result.i = baseEnv(env)->MonitorExit(env, obj);
2584      if (sc.Check(soa, false, "i", &result)) {
2585        return result.i;
2586      }
2587    }
2588    return JNI_ERR;
2589  }
2590
2591  static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* is_copy) {
2592    ScopedObjectAccess soa(env);
2593    ScopedCheck sc(kFlag_CritGet, __FUNCTION__);
2594    JniValueType args[3] = {{.E = env}, {.a = array}, {.p = is_copy}};
2595    if (sc.Check(soa, true, "Eap", args)) {
2596      JniValueType result;
2597      void* ptr = baseEnv(env)->GetPrimitiveArrayCritical(env, array, is_copy);
2598      if (ptr != nullptr && soa.ForceCopy()) {
2599        ptr = GuardedCopy::CreateGuardedPACopy(env, array, is_copy, ptr);
2600      }
2601      result.p = ptr;
2602      if (sc.Check(soa, false, "p", &result)) {
2603        return const_cast<void*>(result.p);
2604      }
2605    }
2606    return nullptr;
2607  }
2608
2609  static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
2610    ScopedObjectAccess soa(env);
2611    ScopedCheck sc(kFlag_CritRelease | kFlag_ExcepOkay, __FUNCTION__);
2612    sc.CheckNonNull(carray);
2613    JniValueType args[4] = {{.E = env}, {.a = array}, {.p = carray}, {.r = mode}};
2614    if (sc.Check(soa, true, "Eapr", args)) {
2615      if (soa.ForceCopy()) {
2616        carray = GuardedCopy::ReleaseGuardedPACopy(__FUNCTION__, env, array, carray, mode);
2617      }
2618      baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
2619      JniValueType result;
2620      result.V = nullptr;
2621      sc.Check(soa, false, "V", &result);
2622    }
2623  }
2624
2625  static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2626    ScopedObjectAccess soa(env);
2627    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2628    JniValueType args[3] = {{.E = env}, {.p = address}, {.J = capacity}};
2629    if (sc.Check(soa, true, "EpJ", args)) {
2630      JniValueType result;
2631      // Note: the validity of address and capacity are checked in the base implementation.
2632      result.L = baseEnv(env)->NewDirectByteBuffer(env, address, capacity);
2633      if (sc.Check(soa, false, "L", &result)) {
2634        return result.L;
2635      }
2636    }
2637    return nullptr;
2638  }
2639
2640  static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
2641    ScopedObjectAccess soa(env);
2642    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2643    JniValueType args[2] = {{.E = env}, {.L = buf}};
2644    if (sc.Check(soa, true, "EL", args)) {
2645      JniValueType result;
2646      // Note: this is implemented in the base environment by a GetLongField which will sanity
2647      // check the type of buf in GetLongField above.
2648      result.p = baseEnv(env)->GetDirectBufferAddress(env, buf);
2649      if (sc.Check(soa, false, "p", &result)) {
2650        return const_cast<void*>(result.p);
2651      }
2652    }
2653    return nullptr;
2654  }
2655
2656  static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
2657    ScopedObjectAccess soa(env);
2658    ScopedCheck sc(kFlag_Default, __FUNCTION__);
2659    JniValueType args[2] = {{.E = env}, {.L = buf}};
2660    if (sc.Check(soa, true, "EL", args)) {
2661      JniValueType result;
2662      // Note: this is implemented in the base environment by a GetIntField which will sanity
2663      // check the type of buf in GetIntField above.
2664      result.J = baseEnv(env)->GetDirectBufferCapacity(env, buf);
2665      if (sc.Check(soa, false, "J", &result)) {
2666        return result.J;
2667      }
2668    }
2669    return JNI_ERR;
2670  }
2671
2672 private:
2673  static JavaVMExt* GetJavaVMExt(JNIEnv* env) {
2674    return reinterpret_cast<JNIEnvExt*>(env)->GetVm();
2675  }
2676
2677  static const JNINativeInterface* baseEnv(JNIEnv* env) {
2678    return reinterpret_cast<JNIEnvExt*>(env)->GetUncheckedFunctions();
2679  }
2680
2681  static jobject NewRef(const char* function_name, JNIEnv* env, jobject obj, IndirectRefKind kind) {
2682    ScopedObjectAccess soa(env);
2683    ScopedCheck sc(kFlag_Default, function_name);
2684    JniValueType args[2] = {{.E = env}, {.L = obj}};
2685    if (sc.Check(soa, true, "EL", args)) {
2686      JniValueType result;
2687      switch (kind) {
2688        case kGlobal:
2689          result.L = baseEnv(env)->NewGlobalRef(env, obj);
2690          break;
2691        case kLocal:
2692          result.L = baseEnv(env)->NewLocalRef(env, obj);
2693          break;
2694        case kWeakGlobal:
2695          result.L = baseEnv(env)->NewWeakGlobalRef(env, obj);
2696          break;
2697        default:
2698          LOG(FATAL) << "Unexpected reference kind: " << kind;
2699      }
2700      if (sc.Check(soa, false, "L", &result)) {
2701        DCHECK_EQ(IsSameObject(env, obj, result.L), JNI_TRUE);
2702        DCHECK(sc.CheckReferenceKind(kind, soa.Self(), result.L));
2703        return result.L;
2704      }
2705    }
2706    return nullptr;
2707  }
2708
2709  static void DeleteRef(const char* function_name, JNIEnv* env, jobject obj, IndirectRefKind kind) {
2710    ScopedObjectAccess soa(env);
2711    ScopedCheck sc(kFlag_ExcepOkay, function_name);
2712    JniValueType args[2] = {{.E = env}, {.L = obj}};
2713    sc.Check(soa, true, "EL", args);
2714    if (sc.CheckReferenceKind(kind, soa.Self(), obj)) {
2715      JniValueType result;
2716      switch (kind) {
2717        case kGlobal:
2718          baseEnv(env)->DeleteGlobalRef(env, obj);
2719          break;
2720        case kLocal:
2721          baseEnv(env)->DeleteLocalRef(env, obj);
2722          break;
2723        case kWeakGlobal:
2724          baseEnv(env)->DeleteWeakGlobalRef(env, obj);
2725          break;
2726        default:
2727          LOG(FATAL) << "Unexpected reference kind: " << kind;
2728      }
2729      result.V = nullptr;
2730      sc.Check(soa, false, "V", &result);
2731    }
2732  }
2733
2734  static jmethodID GetMethodIDInternal(const char* function_name, JNIEnv* env, jclass c,
2735                                       const char* name, const char* sig, bool is_static) {
2736    ScopedObjectAccess soa(env);
2737    ScopedCheck sc(kFlag_Default, function_name);
2738    JniValueType args[4] = {{.E = env}, {.c = c}, {.u = name}, {.u = sig}};
2739    if (sc.Check(soa, true, "Ecuu", args)) {
2740      JniValueType result;
2741      if (is_static) {
2742        result.m = baseEnv(env)->GetStaticMethodID(env, c, name, sig);
2743      } else {
2744        result.m = baseEnv(env)->GetMethodID(env, c, name, sig);
2745      }
2746      if (sc.Check(soa, false, "m", &result)) {
2747        return result.m;
2748      }
2749    }
2750    return nullptr;
2751  }
2752
2753  static jfieldID GetFieldIDInternal(const char* function_name, JNIEnv* env, jclass c,
2754                                     const char* name, const char* sig, bool is_static) {
2755    ScopedObjectAccess soa(env);
2756    ScopedCheck sc(kFlag_Default, function_name);
2757    JniValueType args[4] = {{.E = env}, {.c = c}, {.u = name}, {.u = sig}};
2758    if (sc.Check(soa, true, "Ecuu", args)) {
2759      JniValueType result;
2760      if (is_static) {
2761        result.f = baseEnv(env)->GetStaticFieldID(env, c, name, sig);
2762      } else {
2763        result.f = baseEnv(env)->GetFieldID(env, c, name, sig);
2764      }
2765      if (sc.Check(soa, false, "f", &result)) {
2766        return result.f;
2767      }
2768    }
2769    return nullptr;
2770  }
2771
2772  static JniValueType GetField(const char* function_name, JNIEnv* env, jobject obj, jfieldID fid,
2773                               bool is_static, Primitive::Type type) {
2774    ScopedObjectAccess soa(env);
2775    ScopedCheck sc(kFlag_Default, function_name);
2776    JniValueType args[3] = {{.E = env}, {.L = obj}, {.f = fid}};
2777    JniValueType result;
2778    if (sc.Check(soa, true, is_static ? "Ecf" : "ELf", args) &&
2779        sc.CheckFieldAccess(soa, obj, fid, is_static, type)) {
2780      const char* result_check = nullptr;
2781      switch (type) {
2782        case Primitive::kPrimNot:
2783          if (is_static) {
2784            result.L = baseEnv(env)->GetStaticObjectField(env, down_cast<jclass>(obj), fid);
2785          } else {
2786            result.L = baseEnv(env)->GetObjectField(env, obj, fid);
2787          }
2788          result_check = "L";
2789          break;
2790        case Primitive::kPrimBoolean:
2791          if (is_static) {
2792            result.Z = baseEnv(env)->GetStaticBooleanField(env, down_cast<jclass>(obj), fid);
2793          } else {
2794            result.Z = baseEnv(env)->GetBooleanField(env, obj, fid);
2795          }
2796          result_check = "Z";
2797          break;
2798        case Primitive::kPrimByte:
2799          if (is_static) {
2800            result.B = baseEnv(env)->GetStaticByteField(env, down_cast<jclass>(obj), fid);
2801          } else {
2802            result.B = baseEnv(env)->GetByteField(env, obj, fid);
2803          }
2804          result_check = "B";
2805          break;
2806        case Primitive::kPrimChar:
2807          if (is_static) {
2808            result.C = baseEnv(env)->GetStaticCharField(env, down_cast<jclass>(obj), fid);
2809          } else {
2810            result.C = baseEnv(env)->GetCharField(env, obj, fid);
2811          }
2812          result_check = "C";
2813          break;
2814        case Primitive::kPrimShort:
2815          if (is_static) {
2816            result.S = baseEnv(env)->GetStaticShortField(env, down_cast<jclass>(obj), fid);
2817          } else {
2818            result.S = baseEnv(env)->GetShortField(env, obj, fid);
2819          }
2820          result_check = "S";
2821          break;
2822        case Primitive::kPrimInt:
2823          if (is_static) {
2824            result.I = baseEnv(env)->GetStaticIntField(env, down_cast<jclass>(obj), fid);
2825          } else {
2826            result.I = baseEnv(env)->GetIntField(env, obj, fid);
2827          }
2828          result_check = "I";
2829          break;
2830        case Primitive::kPrimLong:
2831          if (is_static) {
2832            result.J = baseEnv(env)->GetStaticLongField(env, down_cast<jclass>(obj), fid);
2833          } else {
2834            result.J = baseEnv(env)->GetLongField(env, obj, fid);
2835          }
2836          result_check = "J";
2837          break;
2838        case Primitive::kPrimFloat:
2839          if (is_static) {
2840            result.F = baseEnv(env)->GetStaticFloatField(env, down_cast<jclass>(obj), fid);
2841          } else {
2842            result.F = baseEnv(env)->GetFloatField(env, obj, fid);
2843          }
2844          result_check = "F";
2845          break;
2846        case Primitive::kPrimDouble:
2847          if (is_static) {
2848            result.D = baseEnv(env)->GetStaticDoubleField(env, down_cast<jclass>(obj), fid);
2849          } else {
2850            result.D = baseEnv(env)->GetDoubleField(env, obj, fid);
2851          }
2852          result_check = "D";
2853          break;
2854        case Primitive::kPrimVoid:
2855          LOG(FATAL) << "Unexpected type: " << type;
2856          break;
2857      }
2858      if (sc.Check(soa, false, result_check, &result)) {
2859        return result;
2860      }
2861    }
2862    result.J = 0;
2863    return result;
2864  }
2865
2866  static void SetField(const char* function_name, JNIEnv* env, jobject obj, jfieldID fid,
2867                       bool is_static, Primitive::Type type, JniValueType value) {
2868    ScopedObjectAccess soa(env);
2869    ScopedCheck sc(kFlag_Default, function_name);
2870    JniValueType args[4] = {{.E = env}, {.L = obj}, {.f = fid}, value};
2871    char sig[5] = { 'E', is_static ? 'c' : 'L', 'f',
2872        type == Primitive::kPrimNot ? 'L' : Primitive::Descriptor(type)[0], '\0'};
2873    if (sc.Check(soa, true, sig, args) &&
2874        sc.CheckFieldAccess(soa, obj, fid, is_static, type)) {
2875      switch (type) {
2876        case Primitive::kPrimNot:
2877          if (is_static) {
2878            baseEnv(env)->SetStaticObjectField(env, down_cast<jclass>(obj), fid, value.L);
2879          } else {
2880            baseEnv(env)->SetObjectField(env, obj, fid, value.L);
2881          }
2882          break;
2883        case Primitive::kPrimBoolean:
2884          if (is_static) {
2885            baseEnv(env)->SetStaticBooleanField(env, down_cast<jclass>(obj), fid, value.Z);
2886          } else {
2887            baseEnv(env)->SetBooleanField(env, obj, fid, value.Z);
2888          }
2889          break;
2890        case Primitive::kPrimByte:
2891          if (is_static) {
2892            baseEnv(env)->SetStaticByteField(env, down_cast<jclass>(obj), fid, value.B);
2893          } else {
2894            baseEnv(env)->SetByteField(env, obj, fid, value.B);
2895          }
2896          break;
2897        case Primitive::kPrimChar:
2898          if (is_static) {
2899            baseEnv(env)->SetStaticCharField(env, down_cast<jclass>(obj), fid, value.C);
2900          } else {
2901            baseEnv(env)->SetCharField(env, obj, fid, value.C);
2902          }
2903          break;
2904        case Primitive::kPrimShort:
2905          if (is_static) {
2906            baseEnv(env)->SetStaticShortField(env, down_cast<jclass>(obj), fid, value.S);
2907          } else {
2908            baseEnv(env)->SetShortField(env, obj, fid, value.S);
2909          }
2910          break;
2911        case Primitive::kPrimInt:
2912          if (is_static) {
2913            baseEnv(env)->SetStaticIntField(env, down_cast<jclass>(obj), fid, value.I);
2914          } else {
2915            baseEnv(env)->SetIntField(env, obj, fid, value.I);
2916          }
2917          break;
2918        case Primitive::kPrimLong:
2919          if (is_static) {
2920            baseEnv(env)->SetStaticLongField(env, down_cast<jclass>(obj), fid, value.J);
2921          } else {
2922            baseEnv(env)->SetLongField(env, obj, fid, value.J);
2923          }
2924          break;
2925        case Primitive::kPrimFloat:
2926          if (is_static) {
2927            baseEnv(env)->SetStaticFloatField(env, down_cast<jclass>(obj), fid, value.F);
2928          } else {
2929            baseEnv(env)->SetFloatField(env, obj, fid, value.F);
2930          }
2931          break;
2932        case Primitive::kPrimDouble:
2933          if (is_static) {
2934            baseEnv(env)->SetStaticDoubleField(env, down_cast<jclass>(obj), fid, value.D);
2935          } else {
2936            baseEnv(env)->SetDoubleField(env, obj, fid, value.D);
2937          }
2938          break;
2939        case Primitive::kPrimVoid:
2940          LOG(FATAL) << "Unexpected type: " << type;
2941          break;
2942      }
2943      JniValueType result;
2944      result.V = nullptr;
2945      sc.Check(soa, false, "V", &result);
2946    }
2947  }
2948
2949  static bool CheckCallArgs(ScopedObjectAccess& soa, ScopedCheck& sc, JNIEnv* env, jobject obj,
2950                            jclass c, jmethodID mid, InvokeType invoke, const VarArgs* vargs)
2951      REQUIRES_SHARED(Locks::mutator_lock_) {
2952    bool checked;
2953    switch (invoke) {
2954      case kVirtual: {
2955        DCHECK(c == nullptr);
2956        JniValueType args[4] = {{.E = env}, {.L = obj}, {.m = mid}, {.va = vargs}};
2957        checked = sc.Check(soa, true, "ELm.", args);
2958        break;
2959      }
2960      case kDirect: {
2961        JniValueType args[5] = {{.E = env}, {.L = obj}, {.c = c}, {.m = mid}, {.va = vargs}};
2962        checked = sc.Check(soa, true, "ELcm.", args);
2963        break;
2964      }
2965      case kStatic: {
2966        DCHECK(obj == nullptr);
2967        JniValueType args[4] = {{.E = env}, {.c = c}, {.m = mid}, {.va = vargs}};
2968        checked = sc.Check(soa, true, "Ecm.", args);
2969        break;
2970      }
2971      default:
2972        LOG(FATAL) << "Unexpected invoke: " << invoke;
2973        checked = false;
2974        break;
2975    }
2976    return checked;
2977  }
2978
2979  static JniValueType CallMethodA(const char* function_name, JNIEnv* env, jobject obj, jclass c,
2980                                  jmethodID mid, jvalue* vargs, Primitive::Type type,
2981                                  InvokeType invoke) {
2982    ScopedObjectAccess soa(env);
2983    ScopedCheck sc(kFlag_Default, function_name);
2984    JniValueType result;
2985    VarArgs rest(mid, vargs);
2986    if (CheckCallArgs(soa, sc, env, obj, c, mid, invoke, &rest) &&
2987        sc.CheckMethodAndSig(soa, obj, c, mid, type, invoke)) {
2988      const char* result_check;
2989      switch (type) {
2990        case Primitive::kPrimNot:
2991          result_check = "L";
2992          switch (invoke) {
2993            case kVirtual:
2994              result.L = baseEnv(env)->CallObjectMethodA(env, obj, mid, vargs);
2995              break;
2996            case kDirect:
2997              result.L = baseEnv(env)->CallNonvirtualObjectMethodA(env, obj, c, mid, vargs);
2998              break;
2999            case kStatic:
3000              result.L = baseEnv(env)->CallStaticObjectMethodA(env, c, mid, vargs);
3001              break;
3002            default:
3003              break;
3004          }
3005          break;
3006        case Primitive::kPrimBoolean:
3007          result_check = "Z";
3008          switch (invoke) {
3009            case kVirtual:
3010              result.Z = baseEnv(env)->CallBooleanMethodA(env, obj, mid, vargs);
3011              break;
3012            case kDirect:
3013              result.Z = baseEnv(env)->CallNonvirtualBooleanMethodA(env, obj, c, mid, vargs);
3014              break;
3015            case kStatic:
3016              result.Z = baseEnv(env)->CallStaticBooleanMethodA(env, c, mid, vargs);
3017              break;
3018            default:
3019              break;
3020          }
3021          break;
3022        case Primitive::kPrimByte:
3023          result_check = "B";
3024          switch (invoke) {
3025            case kVirtual:
3026              result.B = baseEnv(env)->CallByteMethodA(env, obj, mid, vargs);
3027              break;
3028            case kDirect:
3029              result.B = baseEnv(env)->CallNonvirtualByteMethodA(env, obj, c, mid, vargs);
3030              break;
3031            case kStatic:
3032              result.B = baseEnv(env)->CallStaticByteMethodA(env, c, mid, vargs);
3033              break;
3034            default:
3035              break;
3036          }
3037          break;
3038        case Primitive::kPrimChar:
3039          result_check = "C";
3040          switch (invoke) {
3041            case kVirtual:
3042              result.C = baseEnv(env)->CallCharMethodA(env, obj, mid, vargs);
3043              break;
3044            case kDirect:
3045              result.C = baseEnv(env)->CallNonvirtualCharMethodA(env, obj, c, mid, vargs);
3046              break;
3047            case kStatic:
3048              result.C = baseEnv(env)->CallStaticCharMethodA(env, c, mid, vargs);
3049              break;
3050            default:
3051              break;
3052          }
3053          break;
3054        case Primitive::kPrimShort:
3055          result_check = "S";
3056          switch (invoke) {
3057            case kVirtual:
3058              result.S = baseEnv(env)->CallShortMethodA(env, obj, mid, vargs);
3059              break;
3060            case kDirect:
3061              result.S = baseEnv(env)->CallNonvirtualShortMethodA(env, obj, c, mid, vargs);
3062              break;
3063            case kStatic:
3064              result.S = baseEnv(env)->CallStaticShortMethodA(env, c, mid, vargs);
3065              break;
3066            default:
3067              break;
3068          }
3069          break;
3070        case Primitive::kPrimInt:
3071          result_check = "I";
3072          switch (invoke) {
3073            case kVirtual:
3074              result.I = baseEnv(env)->CallIntMethodA(env, obj, mid, vargs);
3075              break;
3076            case kDirect:
3077              result.I = baseEnv(env)->CallNonvirtualIntMethodA(env, obj, c, mid, vargs);
3078              break;
3079            case kStatic:
3080              result.I = baseEnv(env)->CallStaticIntMethodA(env, c, mid, vargs);
3081              break;
3082            default:
3083              break;
3084          }
3085          break;
3086        case Primitive::kPrimLong:
3087          result_check = "J";
3088          switch (invoke) {
3089            case kVirtual:
3090              result.J = baseEnv(env)->CallLongMethodA(env, obj, mid, vargs);
3091              break;
3092            case kDirect:
3093              result.J = baseEnv(env)->CallNonvirtualLongMethodA(env, obj, c, mid, vargs);
3094              break;
3095            case kStatic:
3096              result.J = baseEnv(env)->CallStaticLongMethodA(env, c, mid, vargs);
3097              break;
3098            default:
3099              break;
3100          }
3101          break;
3102        case Primitive::kPrimFloat:
3103          result_check = "F";
3104          switch (invoke) {
3105            case kVirtual:
3106              result.F = baseEnv(env)->CallFloatMethodA(env, obj, mid, vargs);
3107              break;
3108            case kDirect:
3109              result.F = baseEnv(env)->CallNonvirtualFloatMethodA(env, obj, c, mid, vargs);
3110              break;
3111            case kStatic:
3112              result.F = baseEnv(env)->CallStaticFloatMethodA(env, c, mid, vargs);
3113              break;
3114            default:
3115              break;
3116          }
3117          break;
3118        case Primitive::kPrimDouble:
3119          result_check = "D";
3120          switch (invoke) {
3121            case kVirtual:
3122              result.D = baseEnv(env)->CallDoubleMethodA(env, obj, mid, vargs);
3123              break;
3124            case kDirect:
3125              result.D = baseEnv(env)->CallNonvirtualDoubleMethodA(env, obj, c, mid, vargs);
3126              break;
3127            case kStatic:
3128              result.D = baseEnv(env)->CallStaticDoubleMethodA(env, c, mid, vargs);
3129              break;
3130            default:
3131              break;
3132          }
3133          break;
3134        case Primitive::kPrimVoid:
3135          result_check = "V";
3136          result.V = nullptr;
3137          switch (invoke) {
3138            case kVirtual:
3139              baseEnv(env)->CallVoidMethodA(env, obj, mid, vargs);
3140              break;
3141            case kDirect:
3142              baseEnv(env)->CallNonvirtualVoidMethodA(env, obj, c, mid, vargs);
3143              break;
3144            case kStatic:
3145              baseEnv(env)->CallStaticVoidMethodA(env, c, mid, vargs);
3146              break;
3147            default:
3148              LOG(FATAL) << "Unexpected invoke: " << invoke;
3149          }
3150          break;
3151        default:
3152          LOG(FATAL) << "Unexpected return type: " << type;
3153          result_check = nullptr;
3154      }
3155      if (sc.Check(soa, false, result_check, &result)) {
3156        return result;
3157      }
3158    }
3159    result.J = 0;
3160    return result;
3161  }
3162
3163  static JniValueType CallMethodV(const char* function_name, JNIEnv* env, jobject obj, jclass c,
3164                                  jmethodID mid, va_list vargs, Primitive::Type type,
3165                                  InvokeType invoke) {
3166    ScopedObjectAccess soa(env);
3167    ScopedCheck sc(kFlag_Default, function_name);
3168    JniValueType result;
3169    VarArgs rest(mid, vargs);
3170    if (CheckCallArgs(soa, sc, env, obj, c, mid, invoke, &rest) &&
3171        sc.CheckMethodAndSig(soa, obj, c, mid, type, invoke)) {
3172      const char* result_check;
3173      switch (type) {
3174        case Primitive::kPrimNot:
3175          result_check = "L";
3176          switch (invoke) {
3177            case kVirtual:
3178              result.L = baseEnv(env)->CallObjectMethodV(env, obj, mid, vargs);
3179              break;
3180            case kDirect:
3181              result.L = baseEnv(env)->CallNonvirtualObjectMethodV(env, obj, c, mid, vargs);
3182              break;
3183            case kStatic:
3184              result.L = baseEnv(env)->CallStaticObjectMethodV(env, c, mid, vargs);
3185              break;
3186            default:
3187              LOG(FATAL) << "Unexpected invoke: " << invoke;
3188          }
3189          break;
3190        case Primitive::kPrimBoolean:
3191          result_check = "Z";
3192          switch (invoke) {
3193            case kVirtual:
3194              result.Z = baseEnv(env)->CallBooleanMethodV(env, obj, mid, vargs);
3195              break;
3196            case kDirect:
3197              result.Z = baseEnv(env)->CallNonvirtualBooleanMethodV(env, obj, c, mid, vargs);
3198              break;
3199            case kStatic:
3200              result.Z = baseEnv(env)->CallStaticBooleanMethodV(env, c, mid, vargs);
3201              break;
3202            default:
3203              LOG(FATAL) << "Unexpected invoke: " << invoke;
3204          }
3205          break;
3206        case Primitive::kPrimByte:
3207          result_check = "B";
3208          switch (invoke) {
3209            case kVirtual:
3210              result.B = baseEnv(env)->CallByteMethodV(env, obj, mid, vargs);
3211              break;
3212            case kDirect:
3213              result.B = baseEnv(env)->CallNonvirtualByteMethodV(env, obj, c, mid, vargs);
3214              break;
3215            case kStatic:
3216              result.B = baseEnv(env)->CallStaticByteMethodV(env, c, mid, vargs);
3217              break;
3218            default:
3219              LOG(FATAL) << "Unexpected invoke: " << invoke;
3220          }
3221          break;
3222        case Primitive::kPrimChar:
3223          result_check = "C";
3224          switch (invoke) {
3225            case kVirtual:
3226              result.C = baseEnv(env)->CallCharMethodV(env, obj, mid, vargs);
3227              break;
3228            case kDirect:
3229              result.C = baseEnv(env)->CallNonvirtualCharMethodV(env, obj, c, mid, vargs);
3230              break;
3231            case kStatic:
3232              result.C = baseEnv(env)->CallStaticCharMethodV(env, c, mid, vargs);
3233              break;
3234            default:
3235              LOG(FATAL) << "Unexpected invoke: " << invoke;
3236          }
3237          break;
3238        case Primitive::kPrimShort:
3239          result_check = "S";
3240          switch (invoke) {
3241            case kVirtual:
3242              result.S = baseEnv(env)->CallShortMethodV(env, obj, mid, vargs);
3243              break;
3244            case kDirect:
3245              result.S = baseEnv(env)->CallNonvirtualShortMethodV(env, obj, c, mid, vargs);
3246              break;
3247            case kStatic:
3248              result.S = baseEnv(env)->CallStaticShortMethodV(env, c, mid, vargs);
3249              break;
3250            default:
3251              LOG(FATAL) << "Unexpected invoke: " << invoke;
3252          }
3253          break;
3254        case Primitive::kPrimInt:
3255          result_check = "I";
3256          switch (invoke) {
3257            case kVirtual:
3258              result.I = baseEnv(env)->CallIntMethodV(env, obj, mid, vargs);
3259              break;
3260            case kDirect:
3261              result.I = baseEnv(env)->CallNonvirtualIntMethodV(env, obj, c, mid, vargs);
3262              break;
3263            case kStatic:
3264              result.I = baseEnv(env)->CallStaticIntMethodV(env, c, mid, vargs);
3265              break;
3266            default:
3267              LOG(FATAL) << "Unexpected invoke: " << invoke;
3268          }
3269          break;
3270        case Primitive::kPrimLong:
3271          result_check = "J";
3272          switch (invoke) {
3273            case kVirtual:
3274              result.J = baseEnv(env)->CallLongMethodV(env, obj, mid, vargs);
3275              break;
3276            case kDirect:
3277              result.J = baseEnv(env)->CallNonvirtualLongMethodV(env, obj, c, mid, vargs);
3278              break;
3279            case kStatic:
3280              result.J = baseEnv(env)->CallStaticLongMethodV(env, c, mid, vargs);
3281              break;
3282            default:
3283              LOG(FATAL) << "Unexpected invoke: " << invoke;
3284          }
3285          break;
3286        case Primitive::kPrimFloat:
3287          result_check = "F";
3288          switch (invoke) {
3289            case kVirtual:
3290              result.F = baseEnv(env)->CallFloatMethodV(env, obj, mid, vargs);
3291              break;
3292            case kDirect:
3293              result.F = baseEnv(env)->CallNonvirtualFloatMethodV(env, obj, c, mid, vargs);
3294              break;
3295            case kStatic:
3296              result.F = baseEnv(env)->CallStaticFloatMethodV(env, c, mid, vargs);
3297              break;
3298            default:
3299              LOG(FATAL) << "Unexpected invoke: " << invoke;
3300          }
3301          break;
3302        case Primitive::kPrimDouble:
3303          result_check = "D";
3304          switch (invoke) {
3305            case kVirtual:
3306              result.D = baseEnv(env)->CallDoubleMethodV(env, obj, mid, vargs);
3307              break;
3308            case kDirect:
3309              result.D = baseEnv(env)->CallNonvirtualDoubleMethodV(env, obj, c, mid, vargs);
3310              break;
3311            case kStatic:
3312              result.D = baseEnv(env)->CallStaticDoubleMethodV(env, c, mid, vargs);
3313              break;
3314            default:
3315              LOG(FATAL) << "Unexpected invoke: " << invoke;
3316          }
3317          break;
3318        case Primitive::kPrimVoid:
3319          result_check = "V";
3320          result.V = nullptr;
3321          switch (invoke) {
3322            case kVirtual:
3323              baseEnv(env)->CallVoidMethodV(env, obj, mid, vargs);
3324              break;
3325            case kDirect:
3326              baseEnv(env)->CallNonvirtualVoidMethodV(env, obj, c, mid, vargs);
3327              break;
3328            case kStatic:
3329              baseEnv(env)->CallStaticVoidMethodV(env, c, mid, vargs);
3330              break;
3331            default:
3332              LOG(FATAL) << "Unexpected invoke: " << invoke;
3333          }
3334          break;
3335        default:
3336          LOG(FATAL) << "Unexpected return type: " << type;
3337          result_check = nullptr;
3338      }
3339      if (sc.Check(soa, false, result_check, &result)) {
3340        return result;
3341      }
3342    }
3343    result.J = 0;
3344    return result;
3345  }
3346
3347  static const void* GetStringCharsInternal(const char* function_name, JNIEnv* env, jstring string,
3348                                            jboolean* is_copy, bool utf, bool critical) {
3349    ScopedObjectAccess soa(env);
3350    int flags = critical ? kFlag_CritGet : kFlag_CritOkay;
3351    ScopedCheck sc(flags, function_name);
3352    JniValueType args[3] = {{.E = env}, {.s = string}, {.p = is_copy}};
3353    if (sc.Check(soa, true, "Esp", args)) {
3354      JniValueType result;
3355      void* ptr;
3356      if (utf) {
3357        CHECK(!critical);
3358        ptr = const_cast<char*>(baseEnv(env)->GetStringUTFChars(env, string, is_copy));
3359        result.u = reinterpret_cast<char*>(ptr);
3360      } else {
3361        ptr = const_cast<jchar*>(critical ? baseEnv(env)->GetStringCritical(env, string, is_copy) :
3362            baseEnv(env)->GetStringChars(env, string, is_copy));
3363        result.p = ptr;
3364      }
3365      // TODO: could we be smarter about not copying when local_is_copy?
3366      if (ptr != nullptr && soa.ForceCopy()) {
3367        if (utf) {
3368          size_t length_in_bytes = strlen(result.u) + 1;
3369          result.u =
3370              reinterpret_cast<const char*>(GuardedCopy::Create(ptr, length_in_bytes, false));
3371        } else {
3372          size_t length_in_bytes = baseEnv(env)->GetStringLength(env, string) * 2;
3373          result.p =
3374              reinterpret_cast<const jchar*>(GuardedCopy::Create(ptr, length_in_bytes, false));
3375        }
3376        if (is_copy != nullptr) {
3377          *is_copy = JNI_TRUE;
3378        }
3379      }
3380      if (sc.Check(soa, false, utf ? "u" : "p", &result)) {
3381        return utf ? result.u : result.p;
3382      }
3383    }
3384    return nullptr;
3385  }
3386
3387  static void ReleaseStringCharsInternal(const char* function_name, JNIEnv* env, jstring string,
3388                                         const void* chars, bool utf, bool critical) {
3389    ScopedObjectAccess soa(env);
3390    int flags = kFlag_ExcepOkay | kFlag_Release;
3391    if (critical) {
3392      flags |= kFlag_CritRelease;
3393    }
3394    ScopedCheck sc(flags, function_name);
3395    sc.CheckNonNull(chars);
3396    bool force_copy_ok = !soa.ForceCopy() || GuardedCopy::Check(function_name, chars, false);
3397    if (force_copy_ok && soa.ForceCopy()) {
3398      chars = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<void*>(chars)));
3399    }
3400    if (force_copy_ok) {
3401      JniValueType args[3] = {{.E = env}, {.s = string}, {.p = chars}};
3402      if (sc.Check(soa, true, utf ? "Esu" : "Esp", args)) {
3403        if (utf) {
3404          CHECK(!critical);
3405          baseEnv(env)->ReleaseStringUTFChars(env, string, reinterpret_cast<const char*>(chars));
3406        } else {
3407          if (critical) {
3408            baseEnv(env)->ReleaseStringCritical(env, string, reinterpret_cast<const jchar*>(chars));
3409          } else {
3410            baseEnv(env)->ReleaseStringChars(env, string, reinterpret_cast<const jchar*>(chars));
3411          }
3412        }
3413        JniValueType result;
3414        sc.Check(soa, false, "V", &result);
3415      }
3416    }
3417  }
3418
3419  static jarray NewPrimitiveArray(const char* function_name, JNIEnv* env, jsize length,
3420                                  Primitive::Type type) {
3421    ScopedObjectAccess soa(env);
3422    ScopedCheck sc(kFlag_Default, function_name);
3423    JniValueType args[2] = {{.E = env}, {.z = length}};
3424    if (sc.Check(soa, true, "Ez", args)) {
3425      JniValueType result;
3426      switch (type) {
3427        case Primitive::kPrimBoolean:
3428          result.a = baseEnv(env)->NewBooleanArray(env, length);
3429          break;
3430        case Primitive::kPrimByte:
3431          result.a = baseEnv(env)->NewByteArray(env, length);
3432          break;
3433        case Primitive::kPrimChar:
3434          result.a = baseEnv(env)->NewCharArray(env, length);
3435          break;
3436        case Primitive::kPrimShort:
3437          result.a = baseEnv(env)->NewShortArray(env, length);
3438          break;
3439        case Primitive::kPrimInt:
3440          result.a = baseEnv(env)->NewIntArray(env, length);
3441          break;
3442        case Primitive::kPrimLong:
3443          result.a = baseEnv(env)->NewLongArray(env, length);
3444          break;
3445        case Primitive::kPrimFloat:
3446          result.a = baseEnv(env)->NewFloatArray(env, length);
3447          break;
3448        case Primitive::kPrimDouble:
3449          result.a = baseEnv(env)->NewDoubleArray(env, length);
3450          break;
3451        default:
3452          LOG(FATAL) << "Unexpected primitive type: " << type;
3453      }
3454      if (sc.Check(soa, false, "a", &result)) {
3455        return result.a;
3456      }
3457    }
3458    return nullptr;
3459  }
3460
3461  static void* GetPrimitiveArrayElements(const char* function_name, Primitive::Type type,
3462                                         JNIEnv* env, jarray array, jboolean* is_copy) {
3463    ScopedObjectAccess soa(env);
3464    ScopedCheck sc(kFlag_Default, function_name);
3465    JniValueType args[3] = {{.E = env}, {.a = array}, {.p = is_copy}};
3466    if (sc.Check(soa, true, "Eap", args) && sc.CheckPrimitiveArrayType(soa, array, type)) {
3467      JniValueType result;
3468      void* ptr = nullptr;
3469      switch (type) {
3470        case Primitive::kPrimBoolean:
3471          ptr = baseEnv(env)->GetBooleanArrayElements(env, down_cast<jbooleanArray>(array),
3472                                                      is_copy);
3473          break;
3474        case Primitive::kPrimByte:
3475          ptr = baseEnv(env)->GetByteArrayElements(env, down_cast<jbyteArray>(array), is_copy);
3476          break;
3477        case Primitive::kPrimChar:
3478          ptr = baseEnv(env)->GetCharArrayElements(env, down_cast<jcharArray>(array), is_copy);
3479          break;
3480        case Primitive::kPrimShort:
3481          ptr = baseEnv(env)->GetShortArrayElements(env, down_cast<jshortArray>(array), is_copy);
3482          break;
3483        case Primitive::kPrimInt:
3484          ptr = baseEnv(env)->GetIntArrayElements(env, down_cast<jintArray>(array), is_copy);
3485          break;
3486        case Primitive::kPrimLong:
3487          ptr = baseEnv(env)->GetLongArrayElements(env, down_cast<jlongArray>(array), is_copy);
3488          break;
3489        case Primitive::kPrimFloat:
3490          ptr = baseEnv(env)->GetFloatArrayElements(env, down_cast<jfloatArray>(array), is_copy);
3491          break;
3492        case Primitive::kPrimDouble:
3493          ptr = baseEnv(env)->GetDoubleArrayElements(env, down_cast<jdoubleArray>(array), is_copy);
3494          break;
3495        default:
3496          LOG(FATAL) << "Unexpected primitive type: " << type;
3497      }
3498      if (ptr != nullptr && soa.ForceCopy()) {
3499        ptr = GuardedCopy::CreateGuardedPACopy(env, array, is_copy, ptr);
3500        if (is_copy != nullptr) {
3501          *is_copy = JNI_TRUE;
3502        }
3503      }
3504      result.p = ptr;
3505      if (sc.Check(soa, false, "p", &result)) {
3506        return const_cast<void*>(result.p);
3507      }
3508    }
3509    return nullptr;
3510  }
3511
3512  static void ReleasePrimitiveArrayElements(const char* function_name, Primitive::Type type,
3513                                            JNIEnv* env, jarray array, void* elems, jint mode) {
3514    ScopedObjectAccess soa(env);
3515    ScopedCheck sc(kFlag_ExcepOkay, function_name);
3516    if (sc.CheckNonNull(elems) && sc.CheckPrimitiveArrayType(soa, array, type)) {
3517      if (soa.ForceCopy()) {
3518        elems = GuardedCopy::ReleaseGuardedPACopy(function_name, env, array, elems, mode);
3519      }
3520      if (!soa.ForceCopy() || elems != nullptr) {
3521        JniValueType args[4] = {{.E = env}, {.a = array}, {.p = elems}, {.r = mode}};
3522        if (sc.Check(soa, true, "Eapr", args)) {
3523          switch (type) {
3524            case Primitive::kPrimBoolean:
3525              baseEnv(env)->ReleaseBooleanArrayElements(env, down_cast<jbooleanArray>(array),
3526                                                        reinterpret_cast<jboolean*>(elems), mode);
3527              break;
3528            case Primitive::kPrimByte:
3529              baseEnv(env)->ReleaseByteArrayElements(env, down_cast<jbyteArray>(array),
3530                                                     reinterpret_cast<jbyte*>(elems), mode);
3531              break;
3532            case Primitive::kPrimChar:
3533              baseEnv(env)->ReleaseCharArrayElements(env, down_cast<jcharArray>(array),
3534                                                     reinterpret_cast<jchar*>(elems), mode);
3535              break;
3536            case Primitive::kPrimShort:
3537              baseEnv(env)->ReleaseShortArrayElements(env, down_cast<jshortArray>(array),
3538                                                      reinterpret_cast<jshort*>(elems), mode);
3539              break;
3540            case Primitive::kPrimInt:
3541              baseEnv(env)->ReleaseIntArrayElements(env, down_cast<jintArray>(array),
3542                                                    reinterpret_cast<jint*>(elems), mode);
3543              break;
3544            case Primitive::kPrimLong:
3545              baseEnv(env)->ReleaseLongArrayElements(env, down_cast<jlongArray>(array),
3546                                                     reinterpret_cast<jlong*>(elems), mode);
3547              break;
3548            case Primitive::kPrimFloat:
3549              baseEnv(env)->ReleaseFloatArrayElements(env, down_cast<jfloatArray>(array),
3550                                                      reinterpret_cast<jfloat*>(elems), mode);
3551              break;
3552            case Primitive::kPrimDouble:
3553              baseEnv(env)->ReleaseDoubleArrayElements(env, down_cast<jdoubleArray>(array),
3554                                                       reinterpret_cast<jdouble*>(elems), mode);
3555              break;
3556            default:
3557              LOG(FATAL) << "Unexpected primitive type: " << type;
3558          }
3559          JniValueType result;
3560          result.V = nullptr;
3561          sc.Check(soa, false, "V", &result);
3562        }
3563      }
3564    }
3565  }
3566
3567  static void GetPrimitiveArrayRegion(const char* function_name, Primitive::Type type, JNIEnv* env,
3568                                      jarray array, jsize start, jsize len, void* buf) {
3569    ScopedObjectAccess soa(env);
3570    ScopedCheck sc(kFlag_Default, function_name);
3571    JniValueType args[5] = {{.E = env}, {.a = array}, {.z = start}, {.z = len}, {.p = buf}};
3572    // Note: the start and len arguments are checked as 'I' rather than 'z' as invalid indices
3573    // result in ArrayIndexOutOfBoundsExceptions in the base implementation.
3574    if (sc.Check(soa, true, "EaIIp", args) && sc.CheckPrimitiveArrayType(soa, array, type)) {
3575      switch (type) {
3576        case Primitive::kPrimBoolean:
3577          baseEnv(env)->GetBooleanArrayRegion(env, down_cast<jbooleanArray>(array), start, len,
3578                                              reinterpret_cast<jboolean*>(buf));
3579          break;
3580        case Primitive::kPrimByte:
3581          baseEnv(env)->GetByteArrayRegion(env, down_cast<jbyteArray>(array), start, len,
3582                                           reinterpret_cast<jbyte*>(buf));
3583          break;
3584        case Primitive::kPrimChar:
3585          baseEnv(env)->GetCharArrayRegion(env, down_cast<jcharArray>(array), start, len,
3586                                           reinterpret_cast<jchar*>(buf));
3587          break;
3588        case Primitive::kPrimShort:
3589          baseEnv(env)->GetShortArrayRegion(env, down_cast<jshortArray>(array), start, len,
3590                                            reinterpret_cast<jshort*>(buf));
3591          break;
3592        case Primitive::kPrimInt:
3593          baseEnv(env)->GetIntArrayRegion(env, down_cast<jintArray>(array), start, len,
3594                                          reinterpret_cast<jint*>(buf));
3595          break;
3596        case Primitive::kPrimLong:
3597          baseEnv(env)->GetLongArrayRegion(env, down_cast<jlongArray>(array), start, len,
3598                                           reinterpret_cast<jlong*>(buf));
3599          break;
3600        case Primitive::kPrimFloat:
3601          baseEnv(env)->GetFloatArrayRegion(env, down_cast<jfloatArray>(array), start, len,
3602                                            reinterpret_cast<jfloat*>(buf));
3603          break;
3604        case Primitive::kPrimDouble:
3605          baseEnv(env)->GetDoubleArrayRegion(env, down_cast<jdoubleArray>(array), start, len,
3606                                             reinterpret_cast<jdouble*>(buf));
3607          break;
3608        default:
3609          LOG(FATAL) << "Unexpected primitive type: " << type;
3610      }
3611      JniValueType result;
3612      result.V = nullptr;
3613      sc.Check(soa, false, "V", &result);
3614    }
3615  }
3616
3617  static void SetPrimitiveArrayRegion(const char* function_name, Primitive::Type type, JNIEnv* env,
3618                                      jarray array, jsize start, jsize len, const void* buf) {
3619    ScopedObjectAccess soa(env);
3620    ScopedCheck sc(kFlag_Default, function_name);
3621    JniValueType args[5] = {{.E = env}, {.a = array}, {.z = start}, {.z = len}, {.p = buf}};
3622    // Note: the start and len arguments are checked as 'I' rather than 'z' as invalid indices
3623    // result in ArrayIndexOutOfBoundsExceptions in the base implementation.
3624    if (sc.Check(soa, true, "EaIIp", args) && sc.CheckPrimitiveArrayType(soa, array, type)) {
3625      switch (type) {
3626        case Primitive::kPrimBoolean:
3627          baseEnv(env)->SetBooleanArrayRegion(env, down_cast<jbooleanArray>(array), start, len,
3628                                              reinterpret_cast<const jboolean*>(buf));
3629          break;
3630        case Primitive::kPrimByte:
3631          baseEnv(env)->SetByteArrayRegion(env, down_cast<jbyteArray>(array), start, len,
3632                                           reinterpret_cast<const jbyte*>(buf));
3633          break;
3634        case Primitive::kPrimChar:
3635          baseEnv(env)->SetCharArrayRegion(env, down_cast<jcharArray>(array), start, len,
3636                                           reinterpret_cast<const jchar*>(buf));
3637          break;
3638        case Primitive::kPrimShort:
3639          baseEnv(env)->SetShortArrayRegion(env, down_cast<jshortArray>(array), start, len,
3640                                              reinterpret_cast<const jshort*>(buf));
3641          break;
3642        case Primitive::kPrimInt:
3643          baseEnv(env)->SetIntArrayRegion(env, down_cast<jintArray>(array), start, len,
3644                                          reinterpret_cast<const jint*>(buf));
3645          break;
3646        case Primitive::kPrimLong:
3647          baseEnv(env)->SetLongArrayRegion(env, down_cast<jlongArray>(array), start, len,
3648                                              reinterpret_cast<const jlong*>(buf));
3649          break;
3650        case Primitive::kPrimFloat:
3651          baseEnv(env)->SetFloatArrayRegion(env, down_cast<jfloatArray>(array), start, len,
3652                                            reinterpret_cast<const jfloat*>(buf));
3653          break;
3654        case Primitive::kPrimDouble:
3655          baseEnv(env)->SetDoubleArrayRegion(env, down_cast<jdoubleArray>(array), start, len,
3656                                             reinterpret_cast<const jdouble*>(buf));
3657          break;
3658        default:
3659          LOG(FATAL) << "Unexpected primitive type: " << type;
3660      }
3661      JniValueType result;
3662      result.V = nullptr;
3663      sc.Check(soa, false, "V", &result);
3664    }
3665  }
3666};
3667
3668const JNINativeInterface gCheckNativeInterface = {
3669  nullptr,  // reserved0.
3670  nullptr,  // reserved1.
3671  nullptr,  // reserved2.
3672  nullptr,  // reserved3.
3673  CheckJNI::GetVersion,
3674  CheckJNI::DefineClass,
3675  CheckJNI::FindClass,
3676  CheckJNI::FromReflectedMethod,
3677  CheckJNI::FromReflectedField,
3678  CheckJNI::ToReflectedMethod,
3679  CheckJNI::GetSuperclass,
3680  CheckJNI::IsAssignableFrom,
3681  CheckJNI::ToReflectedField,
3682  CheckJNI::Throw,
3683  CheckJNI::ThrowNew,
3684  CheckJNI::ExceptionOccurred,
3685  CheckJNI::ExceptionDescribe,
3686  CheckJNI::ExceptionClear,
3687  CheckJNI::FatalError,
3688  CheckJNI::PushLocalFrame,
3689  CheckJNI::PopLocalFrame,
3690  CheckJNI::NewGlobalRef,
3691  CheckJNI::DeleteGlobalRef,
3692  CheckJNI::DeleteLocalRef,
3693  CheckJNI::IsSameObject,
3694  CheckJNI::NewLocalRef,
3695  CheckJNI::EnsureLocalCapacity,
3696  CheckJNI::AllocObject,
3697  CheckJNI::NewObject,
3698  CheckJNI::NewObjectV,
3699  CheckJNI::NewObjectA,
3700  CheckJNI::GetObjectClass,
3701  CheckJNI::IsInstanceOf,
3702  CheckJNI::GetMethodID,
3703  CheckJNI::CallObjectMethod,
3704  CheckJNI::CallObjectMethodV,
3705  CheckJNI::CallObjectMethodA,
3706  CheckJNI::CallBooleanMethod,
3707  CheckJNI::CallBooleanMethodV,
3708  CheckJNI::CallBooleanMethodA,
3709  CheckJNI::CallByteMethod,
3710  CheckJNI::CallByteMethodV,
3711  CheckJNI::CallByteMethodA,
3712  CheckJNI::CallCharMethod,
3713  CheckJNI::CallCharMethodV,
3714  CheckJNI::CallCharMethodA,
3715  CheckJNI::CallShortMethod,
3716  CheckJNI::CallShortMethodV,
3717  CheckJNI::CallShortMethodA,
3718  CheckJNI::CallIntMethod,
3719  CheckJNI::CallIntMethodV,
3720  CheckJNI::CallIntMethodA,
3721  CheckJNI::CallLongMethod,
3722  CheckJNI::CallLongMethodV,
3723  CheckJNI::CallLongMethodA,
3724  CheckJNI::CallFloatMethod,
3725  CheckJNI::CallFloatMethodV,
3726  CheckJNI::CallFloatMethodA,
3727  CheckJNI::CallDoubleMethod,
3728  CheckJNI::CallDoubleMethodV,
3729  CheckJNI::CallDoubleMethodA,
3730  CheckJNI::CallVoidMethod,
3731  CheckJNI::CallVoidMethodV,
3732  CheckJNI::CallVoidMethodA,
3733  CheckJNI::CallNonvirtualObjectMethod,
3734  CheckJNI::CallNonvirtualObjectMethodV,
3735  CheckJNI::CallNonvirtualObjectMethodA,
3736  CheckJNI::CallNonvirtualBooleanMethod,
3737  CheckJNI::CallNonvirtualBooleanMethodV,
3738  CheckJNI::CallNonvirtualBooleanMethodA,
3739  CheckJNI::CallNonvirtualByteMethod,
3740  CheckJNI::CallNonvirtualByteMethodV,
3741  CheckJNI::CallNonvirtualByteMethodA,
3742  CheckJNI::CallNonvirtualCharMethod,
3743  CheckJNI::CallNonvirtualCharMethodV,
3744  CheckJNI::CallNonvirtualCharMethodA,
3745  CheckJNI::CallNonvirtualShortMethod,
3746  CheckJNI::CallNonvirtualShortMethodV,
3747  CheckJNI::CallNonvirtualShortMethodA,
3748  CheckJNI::CallNonvirtualIntMethod,
3749  CheckJNI::CallNonvirtualIntMethodV,
3750  CheckJNI::CallNonvirtualIntMethodA,
3751  CheckJNI::CallNonvirtualLongMethod,
3752  CheckJNI::CallNonvirtualLongMethodV,
3753  CheckJNI::CallNonvirtualLongMethodA,
3754  CheckJNI::CallNonvirtualFloatMethod,
3755  CheckJNI::CallNonvirtualFloatMethodV,
3756  CheckJNI::CallNonvirtualFloatMethodA,
3757  CheckJNI::CallNonvirtualDoubleMethod,
3758  CheckJNI::CallNonvirtualDoubleMethodV,
3759  CheckJNI::CallNonvirtualDoubleMethodA,
3760  CheckJNI::CallNonvirtualVoidMethod,
3761  CheckJNI::CallNonvirtualVoidMethodV,
3762  CheckJNI::CallNonvirtualVoidMethodA,
3763  CheckJNI::GetFieldID,
3764  CheckJNI::GetObjectField,
3765  CheckJNI::GetBooleanField,
3766  CheckJNI::GetByteField,
3767  CheckJNI::GetCharField,
3768  CheckJNI::GetShortField,
3769  CheckJNI::GetIntField,
3770  CheckJNI::GetLongField,
3771  CheckJNI::GetFloatField,
3772  CheckJNI::GetDoubleField,
3773  CheckJNI::SetObjectField,
3774  CheckJNI::SetBooleanField,
3775  CheckJNI::SetByteField,
3776  CheckJNI::SetCharField,
3777  CheckJNI::SetShortField,
3778  CheckJNI::SetIntField,
3779  CheckJNI::SetLongField,
3780  CheckJNI::SetFloatField,
3781  CheckJNI::SetDoubleField,
3782  CheckJNI::GetStaticMethodID,
3783  CheckJNI::CallStaticObjectMethod,
3784  CheckJNI::CallStaticObjectMethodV,
3785  CheckJNI::CallStaticObjectMethodA,
3786  CheckJNI::CallStaticBooleanMethod,
3787  CheckJNI::CallStaticBooleanMethodV,
3788  CheckJNI::CallStaticBooleanMethodA,
3789  CheckJNI::CallStaticByteMethod,
3790  CheckJNI::CallStaticByteMethodV,
3791  CheckJNI::CallStaticByteMethodA,
3792  CheckJNI::CallStaticCharMethod,
3793  CheckJNI::CallStaticCharMethodV,
3794  CheckJNI::CallStaticCharMethodA,
3795  CheckJNI::CallStaticShortMethod,
3796  CheckJNI::CallStaticShortMethodV,
3797  CheckJNI::CallStaticShortMethodA,
3798  CheckJNI::CallStaticIntMethod,
3799  CheckJNI::CallStaticIntMethodV,
3800  CheckJNI::CallStaticIntMethodA,
3801  CheckJNI::CallStaticLongMethod,
3802  CheckJNI::CallStaticLongMethodV,
3803  CheckJNI::CallStaticLongMethodA,
3804  CheckJNI::CallStaticFloatMethod,
3805  CheckJNI::CallStaticFloatMethodV,
3806  CheckJNI::CallStaticFloatMethodA,
3807  CheckJNI::CallStaticDoubleMethod,
3808  CheckJNI::CallStaticDoubleMethodV,
3809  CheckJNI::CallStaticDoubleMethodA,
3810  CheckJNI::CallStaticVoidMethod,
3811  CheckJNI::CallStaticVoidMethodV,
3812  CheckJNI::CallStaticVoidMethodA,
3813  CheckJNI::GetStaticFieldID,
3814  CheckJNI::GetStaticObjectField,
3815  CheckJNI::GetStaticBooleanField,
3816  CheckJNI::GetStaticByteField,
3817  CheckJNI::GetStaticCharField,
3818  CheckJNI::GetStaticShortField,
3819  CheckJNI::GetStaticIntField,
3820  CheckJNI::GetStaticLongField,
3821  CheckJNI::GetStaticFloatField,
3822  CheckJNI::GetStaticDoubleField,
3823  CheckJNI::SetStaticObjectField,
3824  CheckJNI::SetStaticBooleanField,
3825  CheckJNI::SetStaticByteField,
3826  CheckJNI::SetStaticCharField,
3827  CheckJNI::SetStaticShortField,
3828  CheckJNI::SetStaticIntField,
3829  CheckJNI::SetStaticLongField,
3830  CheckJNI::SetStaticFloatField,
3831  CheckJNI::SetStaticDoubleField,
3832  CheckJNI::NewString,
3833  CheckJNI::GetStringLength,
3834  CheckJNI::GetStringChars,
3835  CheckJNI::ReleaseStringChars,
3836  CheckJNI::NewStringUTF,
3837  CheckJNI::GetStringUTFLength,
3838  CheckJNI::GetStringUTFChars,
3839  CheckJNI::ReleaseStringUTFChars,
3840  CheckJNI::GetArrayLength,
3841  CheckJNI::NewObjectArray,
3842  CheckJNI::GetObjectArrayElement,
3843  CheckJNI::SetObjectArrayElement,
3844  CheckJNI::NewBooleanArray,
3845  CheckJNI::NewByteArray,
3846  CheckJNI::NewCharArray,
3847  CheckJNI::NewShortArray,
3848  CheckJNI::NewIntArray,
3849  CheckJNI::NewLongArray,
3850  CheckJNI::NewFloatArray,
3851  CheckJNI::NewDoubleArray,
3852  CheckJNI::GetBooleanArrayElements,
3853  CheckJNI::GetByteArrayElements,
3854  CheckJNI::GetCharArrayElements,
3855  CheckJNI::GetShortArrayElements,
3856  CheckJNI::GetIntArrayElements,
3857  CheckJNI::GetLongArrayElements,
3858  CheckJNI::GetFloatArrayElements,
3859  CheckJNI::GetDoubleArrayElements,
3860  CheckJNI::ReleaseBooleanArrayElements,
3861  CheckJNI::ReleaseByteArrayElements,
3862  CheckJNI::ReleaseCharArrayElements,
3863  CheckJNI::ReleaseShortArrayElements,
3864  CheckJNI::ReleaseIntArrayElements,
3865  CheckJNI::ReleaseLongArrayElements,
3866  CheckJNI::ReleaseFloatArrayElements,
3867  CheckJNI::ReleaseDoubleArrayElements,
3868  CheckJNI::GetBooleanArrayRegion,
3869  CheckJNI::GetByteArrayRegion,
3870  CheckJNI::GetCharArrayRegion,
3871  CheckJNI::GetShortArrayRegion,
3872  CheckJNI::GetIntArrayRegion,
3873  CheckJNI::GetLongArrayRegion,
3874  CheckJNI::GetFloatArrayRegion,
3875  CheckJNI::GetDoubleArrayRegion,
3876  CheckJNI::SetBooleanArrayRegion,
3877  CheckJNI::SetByteArrayRegion,
3878  CheckJNI::SetCharArrayRegion,
3879  CheckJNI::SetShortArrayRegion,
3880  CheckJNI::SetIntArrayRegion,
3881  CheckJNI::SetLongArrayRegion,
3882  CheckJNI::SetFloatArrayRegion,
3883  CheckJNI::SetDoubleArrayRegion,
3884  CheckJNI::RegisterNatives,
3885  CheckJNI::UnregisterNatives,
3886  CheckJNI::MonitorEnter,
3887  CheckJNI::MonitorExit,
3888  CheckJNI::GetJavaVM,
3889  CheckJNI::GetStringRegion,
3890  CheckJNI::GetStringUTFRegion,
3891  CheckJNI::GetPrimitiveArrayCritical,
3892  CheckJNI::ReleasePrimitiveArrayCritical,
3893  CheckJNI::GetStringCritical,
3894  CheckJNI::ReleaseStringCritical,
3895  CheckJNI::NewWeakGlobalRef,
3896  CheckJNI::DeleteWeakGlobalRef,
3897  CheckJNI::ExceptionCheck,
3898  CheckJNI::NewDirectByteBuffer,
3899  CheckJNI::GetDirectBufferAddress,
3900  CheckJNI::GetDirectBufferCapacity,
3901  CheckJNI::GetObjectRefType,
3902};
3903
3904class CheckJII {
3905 public:
3906  static jint DestroyJavaVM(JavaVM* vm) {
3907    ScopedCheck sc(kFlag_Invocation, __FUNCTION__, false);
3908    JniValueType args[1] = {{.v = vm}};
3909    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), true, "v", args);
3910    JniValueType result;
3911    result.i = BaseVm(vm)->DestroyJavaVM(vm);
3912    // Use null to signal that the JavaVM isn't valid anymore. DestroyJavaVM deletes the runtime,
3913    // which will delete the JavaVMExt.
3914    sc.CheckNonHeap(nullptr, false, "i", &result);
3915    return result.i;
3916  }
3917
3918  static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
3919    ScopedCheck sc(kFlag_Invocation, __FUNCTION__);
3920    JniValueType args[3] = {{.v = vm}, {.p = p_env}, {.p = thr_args}};
3921    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), true, "vpp", args);
3922    JniValueType result;
3923    result.i = BaseVm(vm)->AttachCurrentThread(vm, p_env, thr_args);
3924    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), false, "i", &result);
3925    return result.i;
3926  }
3927
3928  static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
3929    ScopedCheck sc(kFlag_Invocation, __FUNCTION__);
3930    JniValueType args[3] = {{.v = vm}, {.p = p_env}, {.p = thr_args}};
3931    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), true, "vpp", args);
3932    JniValueType result;
3933    result.i = BaseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args);
3934    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), false, "i", &result);
3935    return result.i;
3936  }
3937
3938  static jint DetachCurrentThread(JavaVM* vm) {
3939    ScopedCheck sc(kFlag_Invocation, __FUNCTION__);
3940    JniValueType args[1] = {{.v = vm}};
3941    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), true, "v", args);
3942    JniValueType result;
3943    result.i = BaseVm(vm)->DetachCurrentThread(vm);
3944    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), false, "i", &result);
3945    return result.i;
3946  }
3947
3948  static jint GetEnv(JavaVM* vm, void** p_env, jint version) {
3949    ScopedCheck sc(kFlag_Invocation, __FUNCTION__);
3950    JniValueType args[3] = {{.v = vm}, {.p = p_env}, {.I = version}};
3951    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), true, "vpI", args);
3952    JniValueType result;
3953    result.i = BaseVm(vm)->GetEnv(vm, p_env, version);
3954    sc.CheckNonHeap(reinterpret_cast<JavaVMExt*>(vm), false, "i", &result);
3955    return result.i;
3956  }
3957
3958 private:
3959  static const JNIInvokeInterface* BaseVm(JavaVM* vm) {
3960    return reinterpret_cast<JavaVMExt*>(vm)->GetUncheckedFunctions();
3961  }
3962};
3963
3964const JNIInvokeInterface gCheckInvokeInterface = {
3965  nullptr,  // reserved0
3966  nullptr,  // reserved1
3967  nullptr,  // reserved2
3968  CheckJII::DestroyJavaVM,
3969  CheckJII::AttachCurrentThread,
3970  CheckJII::DetachCurrentThread,
3971  CheckJII::GetEnv,
3972  CheckJII::AttachCurrentThreadAsDaemon
3973};
3974
3975}  // anonymous namespace
3976
3977const JNINativeInterface* GetCheckJniNativeInterface() {
3978  return &gCheckNativeInterface;
3979}
3980
3981const JNIInvokeInterface* GetCheckJniInvokeInterface() {
3982  return &gCheckInvokeInterface;
3983}
3984
3985}  // namespace art
3986