blob: 0189ba3581675d18fb5436c62e724767f2704eff [file] [log] [blame]
Elliott Hughesa2501992011-08-26 19:39:54 -07001/*
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 "jni_internal.h"
18
19#include <sys/mman.h>
20#include <zlib.h>
21
22#include "class_linker.h"
23#include "logging.h"
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080024#include "object_utils.h"
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -070025#include "scoped_jni_thread_state.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070026#include "thread.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070027#include "runtime.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070028
Elliott Hughese6087632011-09-26 12:18:25 -070029#define LIBCORE_CPP_JNI_HELPERS
30#include <JNIHelp.h> // from libcore
31#undef LIBCORE_CPP_JNI_HELPERS
32
Elliott Hughesa2501992011-08-26 19:39:54 -070033namespace art {
34
35void JniAbort(const char* jni_function_name) {
Elliott Hughesa0957642011-09-02 14:27:33 -070036 Thread* self = Thread::Current();
Elliott Hughesd07986f2011-12-06 18:27:45 -080037 Method* current_method = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -070038
Elliott Hughes3b6baaa2011-10-14 19:13:56 -070039 std::ostringstream os;
Elliott Hughese6087632011-09-26 12:18:25 -070040 os << "Aborting because JNI app bug detected (see above for details)";
Elliott Hughesa2501992011-08-26 19:39:54 -070041
42 if (jni_function_name != NULL) {
43 os << "\n in call to " << jni_function_name;
44 }
Elliott Hughesa0957642011-09-02 14:27:33 -070045 // TODO: is this useful given that we're about to dump the calling thread's stack?
46 if (current_method != NULL) {
47 os << "\n from " << PrettyMethod(current_method);
48 }
49 os << "\n";
50 self->Dump(os);
Elliott Hughesa2501992011-08-26 19:39:54 -070051
52 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
53 if (vm->check_jni_abort_hook != NULL) {
54 vm->check_jni_abort_hook(os.str());
55 } else {
56 LOG(FATAL) << os.str();
57 }
58}
59
60/*
61 * ===========================================================================
62 * JNI function helpers
63 * ===========================================================================
64 */
65
Elliott Hughesa2501992011-08-26 19:39:54 -070066template<typename T>
67T Decode(ScopedJniThreadState& ts, jobject obj) {
68 return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
69}
70
Elliott Hughesa2501992011-08-26 19:39:54 -070071/*
72 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
73 * The code deliberately uses an invalid sequence of operations, so we
74 * need to pass it through unmodified. Review that code before making
75 * any changes here.
76 */
77#define kNoCopyMagic 0xd5aab57f
78
79/*
80 * Flags passed into ScopedCheck.
81 */
82#define kFlag_Default 0x0000
83
84#define kFlag_CritBad 0x0000 /* calling while in critical is bad */
85#define kFlag_CritOkay 0x0001 /* ...okay */
86#define kFlag_CritGet 0x0002 /* this is a critical "get" */
87#define kFlag_CritRelease 0x0003 /* this is a critical "release" */
88#define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */
89
90#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */
91#define kFlag_ExcepOkay 0x0004 /* ...okay */
92
93#define kFlag_Release 0x0010 /* are we in a non-critical release function? */
94#define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */
95
96#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */
97
Elliott Hughes485cac42011-12-09 17:49:35 -080098#define kFlag_ForceTrace 0x80000000 // Add this to a JNI function's flags if you want to trace every call.
99
Elliott Hughesa0957642011-09-02 14:27:33 -0700100static const char* gBuiltInPrefixes[] = {
101 "Landroid/",
102 "Lcom/android/",
103 "Lcom/google/android/",
104 "Ldalvik/",
105 "Ljava/",
106 "Ljavax/",
107 "Llibcore/",
108 "Lorg/apache/harmony/",
109 NULL
110};
111
112bool ShouldTrace(JavaVMExt* vm, const Method* method) {
113 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
114 // when a native method that matches the -Xjnitrace argument calls a JNI function
115 // such as NewByteArray.
116 // If -verbose:third-party-jni is on, we want to log any JNI function calls
117 // made by a third-party native method.
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800118 std::string classNameStr(MethodHelper(method).GetDeclaringClassDescriptor());
Elliott Hughesa0957642011-09-02 14:27:33 -0700119 if (!vm->trace.empty() && classNameStr.find(vm->trace) != std::string::npos) {
120 return true;
121 }
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800122 if (VLOG_IS_ON(third_party_jni)) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700123 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
124 // like part of Android.
125 StringPiece className(classNameStr);
126 for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) {
127 if (className.starts_with(gBuiltInPrefixes[i])) {
128 return false;
129 }
130 }
131 return true;
132 }
133 return false;
134}
135
Elliott Hughesa2501992011-08-26 19:39:54 -0700136class ScopedCheck {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800137 public:
Elliott Hughesa2501992011-08-26 19:39:54 -0700138 // For JNIEnv* functions.
139 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700140 Init(env, reinterpret_cast<JNIEnvExt*>(env)->vm, flags, functionName, true);
141 CheckThread(flags);
Elliott Hughesa2501992011-08-26 19:39:54 -0700142 }
143
144 // For JavaVM* functions.
Elliott Hughesa0957642011-09-02 14:27:33 -0700145 explicit ScopedCheck(JavaVM* vm, bool hasMethod, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700146 Init(NULL, vm, kFlag_Invocation, functionName, hasMethod);
Elliott Hughesa2501992011-08-26 19:39:54 -0700147 }
148
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700149 bool ForceCopy() {
Elliott Hughesa2501992011-08-26 19:39:54 -0700150 return Runtime::Current()->GetJavaVM()->force_copy;
151 }
152
153 /*
154 * In some circumstances the VM will screen class names, but it doesn't
155 * for class lookup. When things get bounced through a class loader, they
156 * can actually get normalized a couple of times; as a result, passing in
157 * a class name like "java.lang.Thread" instead of "java/lang/Thread" will
158 * work in some circumstances.
159 *
160 * This is incorrect and could cause strange behavior or compatibility
161 * problems, so we want to screen that out here.
162 *
163 * We expect "fully-qualified" class names, like "java/lang/Thread" or
164 * "[Ljava/lang/Object;".
165 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700166 void CheckClassName(const char* className) {
Elliott Hughes906e6852011-10-28 14:52:10 -0700167 if (!IsValidJniClassName(className)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700168 LOG(ERROR) << "JNI ERROR: illegal class name '" << className << "' (" << function_name_ << ")\n"
Elliott Hughesa2501992011-08-26 19:39:54 -0700169 << " (should be of the form 'java/lang/String', [Ljava/lang/String;' or '[[B')\n";
170 JniAbort();
171 }
172 }
173
174 /*
175 * Verify that the field is of the appropriate type. If the field has an
176 * object type, "java_object" is the object we're trying to assign into it.
177 *
178 * Works for both static and instance fields.
179 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700180 void CheckFieldType(jobject java_object, jfieldID fid, char prim, bool isStatic) {
181 ScopedJniThreadState ts(env_);
182 Field* f = CheckFieldID(fid);
183 if (f == NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700184 return;
185 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800186 Class* field_type = FieldHelper(f).GetType();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700187 if (!field_type->IsPrimitive()) {
188 if (java_object != NULL) {
189 Object* obj = Decode<Object*>(ts, java_object);
190 /*
191 * If java_object is a weak global ref whose referent has been cleared,
192 * obj will be NULL. Otherwise, obj should always be non-NULL
193 * and valid.
194 */
195 if (obj != NULL && !Heap::IsHeapAddress(obj)) {
196 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
Elliott Hughesa2501992011-08-26 19:39:54 -0700197 JniAbort();
198 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700199 } else {
Brian Carlstrom16192862011-09-12 17:50:06 -0700200 if (!obj->InstanceOf(field_type)) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700201 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << PrettyTypeOf(obj);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700202 JniAbort();
203 return;
204 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700205 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700206 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700207 } else if (field_type != Runtime::Current()->GetClassLinker()->FindPrimitiveClass(prim)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700208 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << prim;
209 JniAbort();
210 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700211 }
212
213 if (isStatic && !f->IsStatic()) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700214 if (isStatic) {
215 LOG(ERROR) << "JNI ERROR: accessing non-static field " << PrettyField(f) << " as static";
216 } else {
217 LOG(ERROR) << "JNI ERROR: accessing static field " << PrettyField(f) << " as non-static";
218 }
219 JniAbort();
220 return;
221 }
222 }
223
224 /*
225 * Verify that this instance field ID is valid for this object.
226 *
227 * Assumes "jobj" has already been validated.
228 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700229 void CheckInstanceFieldID(jobject java_object, jfieldID fid) {
230 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700231
232 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700233 if (o == NULL || !Heap::IsHeapAddress(o)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700234 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
235 JniAbort();
236 return;
237 }
238
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700239 Field* f = CheckFieldID(fid);
240 if (f == NULL) {
241 return;
242 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700243 Class* c = o->GetClass();
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800244 FieldHelper fh(f);
245 if (c->FindInstanceField(fh.GetName(), fh.GetTypeDescriptor()) == NULL) {
Elliott Hughes906e6852011-10-28 14:52:10 -0700246 LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f)
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700247 << " not valid for an object of class " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700248 JniAbort();
249 }
250 }
251
252 /*
253 * Verify that the pointer value is non-NULL.
254 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700255 void CheckNonNull(const void* ptr) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700256 if (ptr == NULL) {
257 LOG(ERROR) << "JNI ERROR: invalid null pointer";
258 JniAbort();
259 }
260 }
261
262 /*
263 * Verify that the method's return type matches the type of call.
264 * 'expectedType' will be "L" for all objects, including arrays.
265 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700266 void CheckSig(jmethodID mid, const char* expectedType, bool isStatic) {
267 ScopedJniThreadState ts(env_);
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800268 Method* m = CheckMethodID(mid);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700269 if (m == NULL) {
270 return;
271 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800272 if (*expectedType != MethodHelper(m).GetShorty()[0]) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700273 LOG(ERROR) << "JNI ERROR: the return type of " << function_name_ << " does not match "
274 << PrettyMethod(m);
Elliott Hughesa2501992011-08-26 19:39:54 -0700275 JniAbort();
276 } else if (isStatic && !m->IsStatic()) {
277 if (isStatic) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700278 LOG(ERROR) << "JNI ERROR: calling non-static method "
279 << PrettyMethod(m) << " with " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700280 } else {
Elliott Hughes726079d2011-10-07 18:43:44 -0700281 LOG(ERROR) << "JNI ERROR: calling static method "
282 << PrettyMethod(m) << " with non-static " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700283 }
284 JniAbort();
285 }
286 }
287
288 /*
289 * Verify that this static field ID is valid for this class.
290 *
291 * Assumes "java_class" has already been validated.
292 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700293 void CheckStaticFieldID(jclass java_class, jfieldID fid) {
294 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700295 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700296 const Field* f = CheckFieldID(fid);
297 if (f == NULL) {
298 return;
299 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700300 if (f->GetDeclaringClass() != c) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700301 LOG(ERROR) << "JNI ERROR: static jfieldID " << fid << " not valid for class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700302 JniAbort();
303 }
304 }
305
306 /*
307 * Verify that "mid" is appropriate for "clazz".
308 *
309 * A mismatch isn't dangerous, because the jmethodID defines the class. In
310 * fact, jclazz is unused in the implementation. It's best if we don't
311 * allow bad code in the system though.
312 *
313 * Instances of "jclazz" must be instances of the method's declaring class.
314 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700315 void CheckStaticMethod(jclass java_class, jmethodID mid) {
316 ScopedJniThreadState ts(env_);
317 const Method* m = CheckMethodID(mid);
318 if (m == NULL) {
319 return;
320 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700321 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughesa2501992011-08-26 19:39:54 -0700322 if (!c->IsAssignableFrom(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700323 LOG(ERROR) << "JNI ERROR: can't call static " << PrettyMethod(m) << " on class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700324 JniAbort();
325 }
326 }
327
328 /*
329 * Verify that "mid" is appropriate for "jobj".
330 *
331 * Make sure the object is an instance of the method's declaring class.
332 * (Note the mid might point to a declaration in an interface; this
333 * will be handled automatically by the instanceof check.)
334 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700335 void CheckVirtualMethod(jobject java_object, jmethodID mid) {
336 ScopedJniThreadState ts(env_);
337 const Method* m = CheckMethodID(mid);
338 if (m == NULL) {
339 return;
340 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700341 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesa2501992011-08-26 19:39:54 -0700342 if (!o->InstanceOf(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700343 LOG(ERROR) << "JNI ERROR: can't call " << PrettyMethod(m) << " on instance of " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700344 JniAbort();
345 }
346 }
347
348 /**
349 * The format string is a sequence of the following characters,
350 * and must be followed by arguments of the corresponding types
351 * in the same order.
352 *
353 * Java primitive types:
354 * B - jbyte
355 * C - jchar
356 * D - jdouble
357 * F - jfloat
358 * I - jint
359 * J - jlong
360 * S - jshort
361 * Z - jboolean (shown as true and false)
362 * V - void
363 *
364 * Java reference types:
365 * L - jobject
366 * a - jarray
367 * c - jclass
368 * s - jstring
369 *
370 * JNI types:
371 * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
372 * f - jfieldID
373 * m - jmethodID
374 * p - void*
375 * r - jint (for release mode arguments)
Elliott Hughes78090d12011-10-07 14:31:47 -0700376 * u - const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700377 * z - jsize (for lengths; use i if negative values are okay)
378 * v - JavaVM*
379 * E - JNIEnv*
380 * . - no argument; just print "..." (used for varargs JNI calls)
381 *
382 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
383 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700384 void Check(bool entry, const char* fmt0, ...) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700385 va_list ap;
386
Elliott Hughesa0957642011-09-02 14:27:33 -0700387 const Method* traceMethod = NULL;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800388 if ((!vm_->trace.empty() || VLOG_IS_ON(third_party_jni)) && has_method_) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700389 // We need to guard some of the invocation interface's calls: a bad caller might
390 // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
Elliott Hughesa0957642011-09-02 14:27:33 -0700391 Thread* self = Thread::Current();
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700392 if ((flags_ & kFlag_Invocation) == 0 || self != NULL) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700393 traceMethod = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -0700394 }
395 }
Elliott Hughesa0957642011-09-02 14:27:33 -0700396
Elliott Hughes485cac42011-12-09 17:49:35 -0800397 if (((flags_ & kFlag_ForceTrace) != 0) || (traceMethod != NULL && ShouldTrace(vm_, traceMethod))) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700398 va_start(ap, fmt0);
399 std::string msg;
400 for (const char* fmt = fmt0; *fmt;) {
401 char ch = *fmt++;
402 if (ch == 'B') { // jbyte
403 jbyte b = va_arg(ap, int);
404 if (b >= 0 && b < 10) {
405 StringAppendF(&msg, "%d", b);
406 } else {
407 StringAppendF(&msg, "%#x (%d)", b, b);
408 }
409 } else if (ch == 'C') { // jchar
410 jchar c = va_arg(ap, int);
411 if (c < 0x7f && c >= ' ') {
412 StringAppendF(&msg, "U+%x ('%c')", c, c);
413 } else {
414 StringAppendF(&msg, "U+%x", c);
415 }
416 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
417 StringAppendF(&msg, "%g", va_arg(ap, double));
418 } else if (ch == 'I' || ch == 'S') { // jint, jshort
419 StringAppendF(&msg, "%d", va_arg(ap, int));
420 } else if (ch == 'J') { // jlong
421 StringAppendF(&msg, "%lld", va_arg(ap, jlong));
422 } else if (ch == 'Z') { // jboolean
423 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
424 } else if (ch == 'V') { // void
425 msg += "void";
426 } else if (ch == 'v') { // JavaVM*
427 JavaVM* vm = va_arg(ap, JavaVM*);
428 StringAppendF(&msg, "(JavaVM*)%p", vm);
429 } else if (ch == 'E') { // JNIEnv*
430 JNIEnv* env = va_arg(ap, JNIEnv*);
431 StringAppendF(&msg, "(JNIEnv*)%p", env);
432 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
433 // For logging purposes, these are identical.
434 jobject o = va_arg(ap, jobject);
435 if (o == NULL) {
436 msg += "NULL";
437 } else {
438 StringAppendF(&msg, "%p", o);
439 }
440 } else if (ch == 'b') { // jboolean (JNI-style)
441 jboolean b = va_arg(ap, int);
442 msg += (b ? "JNI_TRUE" : "JNI_FALSE");
443 } else if (ch == 'c') { // jclass
444 jclass jc = va_arg(ap, jclass);
445 Class* c = reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(jc));
446 if (c == NULL) {
447 msg += "NULL";
448 } else if (c == kInvalidIndirectRefObject || !Heap::IsHeapAddress(c)) {
Elliott Hughes485cac42011-12-09 17:49:35 -0800449 StringAppendF(&msg, "INVALID POINTER:%p", jc);
450 } else if (!c->IsClass()) {
451 msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700452 } else {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700453 msg += PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700454 if (!entry) {
455 StringAppendF(&msg, " (%p)", jc);
456 }
457 }
458 } else if (ch == 'f') { // jfieldID
459 jfieldID fid = va_arg(ap, jfieldID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700460 Field* f = reinterpret_cast<Field*>(fid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700461 msg += PrettyField(f);
462 if (!entry) {
463 StringAppendF(&msg, " (%p)", fid);
464 }
465 } else if (ch == 'z') { // non-negative jsize
466 // You might expect jsize to be size_t, but it's not; it's the same as jint.
467 // We only treat this specially so we can do the non-negative check.
468 // TODO: maybe this wasn't worth it?
469 jint i = va_arg(ap, jint);
470 StringAppendF(&msg, "%d", i);
471 } else if (ch == 'm') { // jmethodID
472 jmethodID mid = va_arg(ap, jmethodID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700473 Method* m = reinterpret_cast<Method*>(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700474 msg += PrettyMethod(m);
475 if (!entry) {
476 StringAppendF(&msg, " (%p)", mid);
477 }
478 } else if (ch == 'p') { // void* ("pointer")
479 void* p = va_arg(ap, void*);
480 if (p == NULL) {
481 msg += "NULL";
482 } else {
483 StringAppendF(&msg, "(void*) %p", p);
484 }
485 } else if (ch == 'r') { // jint (release mode)
486 jint releaseMode = va_arg(ap, jint);
487 if (releaseMode == 0) {
488 msg += "0";
489 } else if (releaseMode == JNI_ABORT) {
490 msg += "JNI_ABORT";
491 } else if (releaseMode == JNI_COMMIT) {
492 msg += "JNI_COMMIT";
493 } else {
494 StringAppendF(&msg, "invalid release mode %d", releaseMode);
495 }
Elliott Hughes78090d12011-10-07 14:31:47 -0700496 } else if (ch == 'u') { // const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700497 const char* utf = va_arg(ap, const char*);
498 if (utf == NULL) {
499 msg += "NULL";
500 } else {
501 StringAppendF(&msg, "\"%s\"", utf);
502 }
503 } else if (ch == '.') {
504 msg += "...";
505 } else {
506 LOG(ERROR) << "unknown trace format specifier: " << ch;
507 JniAbort();
508 return;
509 }
510 if (*fmt) {
511 StringAppendF(&msg, ", ");
512 }
513 }
514 va_end(ap);
515
Elliott Hughes485cac42011-12-09 17:49:35 -0800516 if ((flags_ & kFlag_ForceTrace) != 0) {
517 LOG(INFO) << "JNI: call to " << function_name_ << "(" << msg << ")";
518 } else if (entry) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700519 if (has_method_) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700520 std::string methodName(PrettyMethod(traceMethod, false));
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700521 LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
522 indent_ = methodName.size() + 1;
Elliott Hughesa2501992011-08-26 19:39:54 -0700523 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700524 LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
525 indent_ = 0;
Elliott Hughesa2501992011-08-26 19:39:54 -0700526 }
527 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700528 LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
Elliott Hughesa2501992011-08-26 19:39:54 -0700529 }
530 }
531
532 // We always do the thorough checks on entry, and never on exit...
533 if (entry) {
534 va_start(ap, fmt0);
535 for (const char* fmt = fmt0; *fmt; ++fmt) {
536 char ch = *fmt;
537 if (ch == 'a') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700538 CheckArray(va_arg(ap, jarray));
Elliott Hughesa2501992011-08-26 19:39:54 -0700539 } else if (ch == 'c') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700540 CheckInstance(kClass, va_arg(ap, jclass));
Elliott Hughesa2501992011-08-26 19:39:54 -0700541 } else if (ch == 'L') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700542 CheckObject(va_arg(ap, jobject));
Elliott Hughesa2501992011-08-26 19:39:54 -0700543 } else if (ch == 'r') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700544 CheckReleaseMode(va_arg(ap, jint));
Elliott Hughesa2501992011-08-26 19:39:54 -0700545 } else if (ch == 's') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700546 CheckInstance(kString, va_arg(ap, jstring));
Elliott Hughesa2501992011-08-26 19:39:54 -0700547 } else if (ch == 'u') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700548 if ((flags_ & kFlag_Release) != 0) {
549 CheckNonNull(va_arg(ap, const char*));
Elliott Hughesa2501992011-08-26 19:39:54 -0700550 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700551 bool nullable = ((flags_ & kFlag_NullableUtf) != 0);
552 CheckUtfString(va_arg(ap, const char*), nullable);
Elliott Hughesa2501992011-08-26 19:39:54 -0700553 }
554 } else if (ch == 'z') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700555 CheckLengthPositive(va_arg(ap, jsize));
Elliott Hughesa2501992011-08-26 19:39:54 -0700556 } else if (strchr("BCISZbfmpEv", ch) != NULL) {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800557 va_arg(ap, uint32_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700558 } else if (ch == 'D' || ch == 'F') {
559 va_arg(ap, double); // Skip this argument.
560 } else if (ch == 'J') {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800561 va_arg(ap, uint64_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700562 } else if (ch == '.') {
563 } else {
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800564 LOG(FATAL) << "Unknown check format specifier: " << ch;
Elliott Hughesa2501992011-08-26 19:39:54 -0700565 }
566 }
567 va_end(ap);
568 }
569 }
570
Elliott Hughesba8eee12012-01-24 20:25:24 -0800571 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700572 void Init(JNIEnv* env, JavaVM* vm, int flags, const char* functionName, bool hasMethod) {
573 env_ = reinterpret_cast<JNIEnvExt*>(env);
574 vm_ = reinterpret_cast<JavaVMExt*>(vm);
575 flags_ = flags;
576 function_name_ = functionName;
Elliott Hughesa2501992011-08-26 19:39:54 -0700577
578 // Set "hasMethod" to true if we have a valid thread with a method pointer.
579 // We won't have one before attaching a thread, after detaching a thread, or
580 // after destroying the VM.
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700581 has_method_ = hasMethod;
Elliott Hughesa2501992011-08-26 19:39:54 -0700582 }
583
584 /*
585 * Verify that "array" is non-NULL and points to an Array object.
586 *
587 * Since we're dealing with objects, switch to "running" mode.
588 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700589 void CheckArray(jarray java_array) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700590 if (java_array == NULL) {
591 LOG(ERROR) << "JNI ERROR: received null array";
592 JniAbort();
593 return;
594 }
595
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700596 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700597 Array* a = Decode<Array*>(ts, java_array);
598 if (!Heap::IsHeapAddress(a)) {
599 LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array);
600 JniAbort();
601 } else if (!a->IsArrayInstance()) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700602 LOG(ERROR) << "JNI ERROR: jarray argument has non-array type: " << PrettyTypeOf(a);
Elliott Hughesa2501992011-08-26 19:39:54 -0700603 JniAbort();
604 }
605 }
606
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700607 void CheckLengthPositive(jsize length) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700608 if (length < 0) {
609 LOG(ERROR) << "JNI ERROR: negative jsize: " << length;
610 JniAbort();
611 }
612 }
613
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700614 Field* CheckFieldID(jfieldID fid) {
615 if (fid == NULL) {
616 LOG(ERROR) << "JNI ERROR: null jfieldID";
617 JniAbort();
618 return NULL;
619 }
620 Field* f = DecodeField(fid);
621 if (!Heap::IsHeapAddress(f)) {
622 LOG(ERROR) << "JNI ERROR: invalid jfieldID: " << fid;
623 JniAbort();
624 return NULL;
625 }
626 return f;
627 }
628
629 Method* CheckMethodID(jmethodID mid) {
630 if (mid == NULL) {
631 LOG(ERROR) << "JNI ERROR: null jmethodID";
632 JniAbort();
633 return NULL;
634 }
635 Method* m = DecodeMethod(mid);
636 if (!Heap::IsHeapAddress(m)) {
637 LOG(ERROR) << "JNI ERROR: invalid jmethodID: " << mid;
638 JniAbort();
639 return NULL;
640 }
641 return m;
642 }
643
Elliott Hughesa2501992011-08-26 19:39:54 -0700644 /*
645 * Verify that "jobj" is a valid object, and that it's an object that JNI
646 * is allowed to know about. We allow NULL references.
647 *
648 * Switches to "running" mode before performing checks.
649 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700650 void CheckObject(jobject java_object) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700651 if (java_object == NULL) {
652 return;
653 }
654
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700655 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700656
657 Object* o = Decode<Object*>(ts, java_object);
658 if (o != NULL && !Heap::IsHeapAddress(o)) {
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700659 // TODO: when we remove work_around_app_jni_bugs, this should be impossible.
Elliott Hughesa2501992011-08-26 19:39:54 -0700660 LOG(ERROR) << "JNI ERROR: native code passing in reference to invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
661 JniAbort();
662 }
663 }
664
665 /*
666 * Verify that the "mode" argument passed to a primitive array Release
667 * function is one of the valid values.
668 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700669 void CheckReleaseMode(jint mode) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700670 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
671 LOG(ERROR) << "JNI ERROR: bad value for release mode: " << mode;
672 JniAbort();
673 }
674 }
675
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700676 void CheckThread(int flags) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700677 Thread* self = Thread::Current();
678 if (self == NULL) {
679 LOG(ERROR) << "JNI ERROR: non-VM thread making JNI calls";
680 JniAbort();
681 return;
682 }
683
684 // Get the *correct* JNIEnv by going through our TLS pointer.
685 JNIEnvExt* threadEnv = self->GetJniEnv();
686
687 /*
688 * Verify that the current thread is (a) attached and (b) associated with
689 * this particular instance of JNIEnv.
690 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700691 if (env_ != threadEnv) {
692 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNIEnv* from thread " << *env_->self;
Elliott Hughesa2501992011-08-26 19:39:54 -0700693 // If we're keeping broken code limping along, we need to suppress the abort...
Elliott Hughesc2dc62d2012-01-17 20:06:12 -0800694 if (!vm_->work_around_app_jni_bugs) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700695 JniAbort();
696 return;
697 }
698 }
699
700 /*
701 * Verify that, if this thread previously made a critical "get" call, we
702 * do the corresponding "release" call before we try anything else.
703 */
704 switch (flags & kFlag_CritMask) {
705 case kFlag_CritOkay: // okay to call this method
706 break;
707 case kFlag_CritBad: // not okay to call
708 if (threadEnv->critical) {
709 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNI after critical get";
710 JniAbort();
711 return;
712 }
713 break;
714 case kFlag_CritGet: // this is a "get" call
715 /* don't check here; we allow nested gets */
716 threadEnv->critical++;
717 break;
718 case kFlag_CritRelease: // this is a "release" call
719 threadEnv->critical--;
720 if (threadEnv->critical < 0) {
721 LOG(ERROR) << "JNI ERROR: thread " << *self << " called too many critical releases";
722 JniAbort();
723 return;
724 }
725 break;
726 default:
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800727 LOG(FATAL) << "Bad flags (internal error): " << flags;
Elliott Hughesa2501992011-08-26 19:39:54 -0700728 }
729
730 /*
731 * Verify that, if an exception has been raised, the native code doesn't
732 * make any JNI calls other than the Exception* methods.
733 */
734 if ((flags & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
Elliott Hughes30646832011-10-13 16:59:46 -0700735 std::string type(PrettyTypeOf(self->GetException()));
736 LOG(ERROR) << "JNI ERROR: JNI " << function_name_ << " called with " << type << " pending";
737 // TODO: write native code that doesn't require allocation for dumping an exception.
738 if (type != "java.lang.OutOfMemoryError") {
739 LOG(ERROR) << "Pending exception is: ";
740 LOG(ERROR) << jniGetStackTrace(env_);
741 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700742 JniAbort();
743 return;
744 }
745 }
746
747 /*
Elliott Hughes78090d12011-10-07 14:31:47 -0700748 * Verify that "bytes" points to valid Modified UTF-8 data.
Elliott Hughesa2501992011-08-26 19:39:54 -0700749 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700750 void CheckUtfString(const char* bytes, bool nullable) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700751 if (bytes == NULL) {
752 if (!nullable) {
753 LOG(ERROR) << "JNI ERROR: non-nullable const char* was NULL";
754 JniAbort();
755 return;
756 }
757 return;
758 }
759
760 const char* errorKind = NULL;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700761 uint8_t utf8 = CheckUtfBytes(bytes, &errorKind);
Elliott Hughesa2501992011-08-26 19:39:54 -0700762 if (errorKind != NULL) {
Elliott Hughes78090d12011-10-07 14:31:47 -0700763 LOG(ERROR) << "JNI ERROR: input is not valid Modified UTF-8: "
764 << "illegal " << errorKind << " byte " << StringPrintf("%#x", utf8) << "\n"
765 << " string: '" << bytes << "'";
Elliott Hughesa2501992011-08-26 19:39:54 -0700766 JniAbort();
767 return;
768 }
769 }
770
771 enum InstanceKind {
772 kClass,
773 kDirectByteBuffer,
774 kString,
775 kThrowable,
776 };
777
778 /*
779 * Verify that "jobj" is a valid non-NULL object reference, and points to
780 * an instance of expectedClass.
781 *
782 * Because we're looking at an object on the GC heap, we have to switch
783 * to "running" mode before doing the checks.
784 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700785 void CheckInstance(InstanceKind kind, jobject java_object) {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700786 const char* what = NULL;
Elliott Hughesa2501992011-08-26 19:39:54 -0700787 switch (kind) {
788 case kClass:
789 what = "jclass";
790 break;
791 case kDirectByteBuffer:
792 what = "direct ByteBuffer";
793 break;
794 case kString:
795 what = "jstring";
796 break;
797 case kThrowable:
798 what = "jthrowable";
799 break;
800 default:
801 CHECK(false) << static_cast<int>(kind);
802 }
803
804 if (java_object == NULL) {
805 LOG(ERROR) << "JNI ERROR: received null " << what;
806 JniAbort();
807 return;
808 }
809
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700810 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700811 Object* obj = Decode<Object*>(ts, java_object);
812 if (!Heap::IsHeapAddress(obj)) {
813 LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
814 JniAbort();
815 return;
816 }
817
818 bool okay = true;
819 switch (kind) {
820 case kClass:
821 okay = obj->IsClass();
822 break;
823 case kDirectByteBuffer:
824 // TODO
825 break;
826 case kString:
Elliott Hughesdbb40792011-11-18 17:05:22 -0800827 okay = obj->GetClass()->IsStringClass();
Elliott Hughesa2501992011-08-26 19:39:54 -0700828 break;
829 case kThrowable:
Elliott Hughes485cac42011-12-09 17:49:35 -0800830 okay = obj->GetClass()->IsThrowableClass();
Elliott Hughesa2501992011-08-26 19:39:54 -0700831 break;
832 }
833 if (!okay) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700834 LOG(ERROR) << "JNI ERROR: " << what << " has wrong type: " << PrettyTypeOf(obj);
Elliott Hughesa2501992011-08-26 19:39:54 -0700835 JniAbort();
836 }
837 }
838
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700839 static uint8_t CheckUtfBytes(const char* bytes, const char** errorKind) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700840 while (*bytes != '\0') {
841 uint8_t utf8 = *(bytes++);
842 // Switch on the high four bits.
843 switch (utf8 >> 4) {
844 case 0x00:
845 case 0x01:
846 case 0x02:
847 case 0x03:
848 case 0x04:
849 case 0x05:
850 case 0x06:
851 case 0x07:
852 // Bit pattern 0xxx. No need for any extra bytes.
853 break;
854 case 0x08:
855 case 0x09:
856 case 0x0a:
857 case 0x0b:
858 case 0x0f:
859 /*
860 * Bit pattern 10xx or 1111, which are illegal start bytes.
861 * Note: 1111 is valid for normal UTF-8, but not the
Elliott Hughes78090d12011-10-07 14:31:47 -0700862 * Modified UTF-8 used here.
Elliott Hughesa2501992011-08-26 19:39:54 -0700863 */
864 *errorKind = "start";
865 return utf8;
866 case 0x0e:
867 // Bit pattern 1110, so there are two additional bytes.
868 utf8 = *(bytes++);
869 if ((utf8 & 0xc0) != 0x80) {
870 *errorKind = "continuation";
871 return utf8;
872 }
873 // Fall through to take care of the final byte.
874 case 0x0c:
875 case 0x0d:
876 // Bit pattern 110x, so there is one additional byte.
877 utf8 = *(bytes++);
878 if ((utf8 & 0xc0) != 0x80) {
879 *errorKind = "continuation";
880 return utf8;
881 }
882 break;
883 }
884 }
885 return 0;
886 }
887
888 void JniAbort() {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700889 ::art::JniAbort(function_name_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700890 }
891
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700892 JNIEnvExt* env_;
893 JavaVMExt* vm_;
894 const char* function_name_;
895 int flags_;
896 bool has_method_;
Elliott Hughes92cb4982011-12-16 16:57:28 -0800897 int indent_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700898
899 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
900};
901
902#define CHECK_JNI_ENTRY(flags, types, args...) \
903 ScopedCheck sc(env, flags, __FUNCTION__); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700904 sc.Check(true, types, ##args)
Elliott Hughesa2501992011-08-26 19:39:54 -0700905
906#define CHECK_JNI_EXIT(type, exp) ({ \
Elliott Hughes362f9bc2011-10-17 18:56:41 -0700907 typeof(exp) _rc = (exp); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700908 sc.Check(false, type, _rc); \
Elliott Hughesa2501992011-08-26 19:39:54 -0700909 _rc; })
910#define CHECK_JNI_EXIT_VOID() \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700911 sc.Check(false, "V")
Elliott Hughesa2501992011-08-26 19:39:54 -0700912
913/*
914 * ===========================================================================
915 * Guarded arrays
916 * ===========================================================================
917 */
918
919#define kGuardLen 512 /* must be multiple of 2 */
920#define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */
921#define kGuardMagic 0xffd5aa96
922
923/* this gets tucked in at the start of the buffer; struct size must be even */
924struct GuardedCopy {
925 uint32_t magic;
926 uLong adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700927 size_t original_length;
928 const void* original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700929
930 /* find the GuardedCopy given the pointer into the "live" data */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700931 static inline const GuardedCopy* FromData(const void* dataBuf) {
932 return reinterpret_cast<const GuardedCopy*>(ActualBuffer(dataBuf));
Elliott Hughesa2501992011-08-26 19:39:54 -0700933 }
934
935 /*
936 * Create an over-sized buffer to hold the contents of "buf". Copy it in,
937 * filling in the area around it with guard data.
938 *
939 * We use a 16-bit pattern to make a rogue memset less likely to elude us.
940 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700941 static void* Create(const void* buf, size_t len, bool modOkay) {
942 size_t newLen = ActualLength(len);
943 uint8_t* newBuf = DebugAlloc(newLen);
Elliott Hughesa2501992011-08-26 19:39:54 -0700944
945 /* fill it in with a pattern */
Elliott Hughesba8eee12012-01-24 20:25:24 -0800946 uint16_t* pat = reinterpret_cast<uint16_t*>(newBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -0700947 for (size_t i = 0; i < newLen / 2; i++) {
948 *pat++ = kGuardPattern;
949 }
950
951 /* copy the data in; note "len" could be zero */
952 memcpy(newBuf + kGuardLen / 2, buf, len);
953
954 /* if modification is not expected, grab a checksum */
955 uLong adler = 0;
956 if (!modOkay) {
957 adler = adler32(0L, Z_NULL, 0);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800958 adler = adler32(adler, reinterpret_cast<const Bytef*>(buf), len);
959 *reinterpret_cast<uLong*>(newBuf) = adler;
Elliott Hughesa2501992011-08-26 19:39:54 -0700960 }
961
962 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
963 pExtra->magic = kGuardMagic;
964 pExtra->adler = adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700965 pExtra->original_ptr = buf;
966 pExtra->original_length = len;
Elliott Hughesa2501992011-08-26 19:39:54 -0700967
968 return newBuf + kGuardLen / 2;
969 }
970
971 /*
972 * Free up the guard buffer, scrub it, and return the original pointer.
973 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700974 static void* Destroy(void* dataBuf) {
975 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800976 void* original_ptr = const_cast<void*>(pExtra->original_ptr);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700977 size_t len = pExtra->original_length;
978 DebugFree(dataBuf, len);
979 return original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700980 }
981
982 /*
983 * Verify the guard area and, if "modOkay" is false, that the data itself
984 * has not been altered.
985 *
986 * The caller has already checked that "dataBuf" is non-NULL.
987 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700988 static void Check(const char* functionName, const void* dataBuf, bool modOkay) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700989 static const uint32_t kMagicCmp = kGuardMagic;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700990 const uint8_t* fullBuf = ActualBuffer(dataBuf);
991 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -0700992
993 /*
994 * Before we do anything with "pExtra", check the magic number. We
995 * do the check with memcmp rather than "==" in case the pointer is
996 * unaligned. If it points to completely bogus memory we're going
997 * to crash, but there's no easy way around that.
998 */
999 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
1000 uint8_t buf[4];
1001 memcpy(buf, &pExtra->magic, 4);
1002 LOG(ERROR) << StringPrintf("JNI: guard magic does not match "
1003 "(found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
1004 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
1005 JniAbort(functionName);
1006 }
1007
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001008 size_t len = pExtra->original_length;
Elliott Hughesa2501992011-08-26 19:39:54 -07001009
1010 /* check bottom half of guard; skip over optional checksum storage */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001011 const uint16_t* pat = reinterpret_cast<const uint16_t*>(fullBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001012 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
1013 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001014 LOG(ERROR) << "JNI: guard pattern(1) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001015 JniAbort(functionName);
1016 }
1017 }
1018
1019 int offset = kGuardLen / 2 + len;
1020 if (offset & 0x01) {
1021 /* odd byte; expected value depends on endian-ness of host */
1022 const uint16_t patSample = kGuardPattern;
Elliott Hughesba8eee12012-01-24 20:25:24 -08001023 if (fullBuf[offset] != reinterpret_cast<const uint8_t*>(&patSample)[1]) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001024 LOG(ERROR) << "JNI: guard pattern disturbed in odd byte after "
Elliott Hughesba8eee12012-01-24 20:25:24 -08001025 << reinterpret_cast<const void*>(fullBuf) << " (+" << offset << ") "
Elliott Hughesa2501992011-08-26 19:39:54 -07001026 << StringPrintf("0x%02x 0x%02x", fullBuf[offset], ((const uint8_t*) &patSample)[1]);
1027 JniAbort(functionName);
1028 }
1029 offset++;
1030 }
1031
1032 /* check top half of guard */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001033 pat = reinterpret_cast<const uint16_t*>(fullBuf + offset);
Elliott Hughesa2501992011-08-26 19:39:54 -07001034 for (size_t i = 0; i < kGuardLen / 4; i++) {
1035 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001036 LOG(ERROR) << "JNI: guard pattern(2) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (offset + i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001037 JniAbort(functionName);
1038 }
1039 }
1040
1041 /*
1042 * If modification is not expected, verify checksum. Strictly speaking
1043 * this is wrong: if we told the client that we made a copy, there's no
1044 * reason they can't alter the buffer.
1045 */
1046 if (!modOkay) {
1047 uLong adler = adler32(0L, Z_NULL, 0);
1048 adler = adler32(adler, (const Bytef*)dataBuf, len);
1049 if (pExtra->adler != adler) {
1050 LOG(ERROR) << StringPrintf("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", pExtra->adler, adler, dataBuf);
1051 JniAbort(functionName);
1052 }
1053 }
1054 }
1055
1056 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001057 static uint8_t* DebugAlloc(size_t len) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001058 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1059 if (result == MAP_FAILED) {
1060 PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed";
1061 }
1062 return reinterpret_cast<uint8_t*>(result);
1063 }
1064
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001065 static void DebugFree(void* dataBuf, size_t len) {
1066 uint8_t* fullBuf = ActualBuffer(dataBuf);
1067 size_t totalByteCount = ActualLength(len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001068 // TODO: we could mprotect instead, and keep the allocation around for a while.
1069 // This would be even more expensive, but it might catch more errors.
1070 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
1071 // LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
1072 // }
1073 if (munmap(fullBuf, totalByteCount) != 0) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001074 PLOG(FATAL) << "munmap(" << reinterpret_cast<void*>(fullBuf) << ", " << totalByteCount << ") failed";
Elliott Hughesa2501992011-08-26 19:39:54 -07001075 }
1076 }
1077
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001078 static const uint8_t* ActualBuffer(const void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001079 return reinterpret_cast<const uint8_t*>(dataBuf) - kGuardLen / 2;
1080 }
1081
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001082 static uint8_t* ActualBuffer(void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001083 return reinterpret_cast<uint8_t*>(dataBuf) - kGuardLen / 2;
1084 }
1085
1086 // Underlying length of a user allocation of 'length' bytes.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001087 static size_t ActualLength(size_t length) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001088 return (length + kGuardLen + 1) & ~0x01;
1089 }
1090};
1091
1092/*
1093 * Create a guarded copy of a primitive array. Modifications to the copied
1094 * data are allowed. Returns a pointer to the copied data.
1095 */
1096void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* isCopy) {
1097 ScopedJniThreadState ts(env);
1098
1099 Array* a = Decode<Array*>(ts, java_array);
1100 size_t byte_count = a->GetLength() * a->GetClass()->GetComponentSize();
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001101 void* result = GuardedCopy::Create(a->GetRawData(), byte_count, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001102 if (isCopy != NULL) {
1103 *isCopy = JNI_TRUE;
1104 }
1105 return result;
1106}
1107
1108/*
1109 * Perform the array "release" operation, which may or may not copy data
1110 * back into the VM, and may or may not release the underlying storage.
1111 */
1112void ReleaseGuardedPACopy(JNIEnv* env, jarray java_array, void* dataBuf, int mode) {
1113 if (reinterpret_cast<uintptr_t>(dataBuf) == kNoCopyMagic) {
1114 return;
1115 }
1116
1117 ScopedJniThreadState ts(env);
1118 Array* a = Decode<Array*>(ts, java_array);
1119
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001120 GuardedCopy::Check(__FUNCTION__, dataBuf, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001121
1122 if (mode != JNI_ABORT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001123 size_t len = GuardedCopy::FromData(dataBuf)->original_length;
Elliott Hughesbf86d042011-08-31 17:53:14 -07001124 memcpy(a->GetRawData(), dataBuf, len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001125 }
1126 if (mode != JNI_COMMIT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001127 GuardedCopy::Destroy(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001128 }
1129}
1130
1131/*
1132 * ===========================================================================
1133 * JNI functions
1134 * ===========================================================================
1135 */
1136
1137class CheckJNI {
1138 public:
1139 static jint GetVersion(JNIEnv* env) {
1140 CHECK_JNI_ENTRY(kFlag_Default, "E", env);
1141 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
1142 }
1143
1144 static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf, jsize bufLen) {
1145 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001146 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001147 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
1148 }
1149
1150 static jclass FindClass(JNIEnv* env, const char* name) {
1151 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001152 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001153 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
1154 }
1155
1156 static jclass GetSuperclass(JNIEnv* env, jclass clazz) {
1157 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1158 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz));
1159 }
1160
1161 static jboolean IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) {
1162 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2);
1163 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2));
1164 }
1165
1166 static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
1167 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
1168 // TODO: check that 'field' is a java.lang.reflect.Method.
1169 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
1170 }
1171
1172 static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
1173 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
1174 // TODO: check that 'field' is a java.lang.reflect.Field.
1175 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
1176 }
1177
1178 static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
1179 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, mid, isStatic);
1180 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, mid, isStatic));
1181 }
1182
1183 static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
1184 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fid, isStatic);
1185 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fid, isStatic));
1186 }
1187
1188 static jint Throw(JNIEnv* env, jthrowable obj) {
1189 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1190 // TODO: check that 'obj' is a java.lang.Throwable.
1191 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
1192 }
1193
1194 static jint ThrowNew(JNIEnv* env, jclass clazz, const char* message) {
1195 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message);
1196 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message));
1197 }
1198
1199 static jthrowable ExceptionOccurred(JNIEnv* env) {
1200 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1201 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
1202 }
1203
1204 static void ExceptionDescribe(JNIEnv* env) {
1205 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1206 baseEnv(env)->ExceptionDescribe(env);
1207 CHECK_JNI_EXIT_VOID();
1208 }
1209
1210 static void ExceptionClear(JNIEnv* env) {
1211 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1212 baseEnv(env)->ExceptionClear(env);
1213 CHECK_JNI_EXIT_VOID();
1214 }
1215
1216 static void FatalError(JNIEnv* env, const char* msg) {
1217 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
1218 baseEnv(env)->FatalError(env, msg);
1219 CHECK_JNI_EXIT_VOID();
1220 }
1221
1222 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1223 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
1224 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
1225 }
1226
1227 static jobject PopLocalFrame(JNIEnv* env, jobject res) {
1228 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
1229 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
1230 }
1231
1232 static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
1233 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1234 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
1235 }
1236
1237 static jobject NewLocalRef(JNIEnv* env, jobject ref) {
1238 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
1239 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
1240 }
1241
1242 static void DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
1243 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
1244 if (globalRef != NULL && GetIndirectRefKind(globalRef) != kGlobal) {
1245 LOG(ERROR) << "JNI ERROR: DeleteGlobalRef on " << GetIndirectRefKind(globalRef) << ": " << globalRef;
1246 JniAbort(__FUNCTION__);
1247 } else {
1248 baseEnv(env)->DeleteGlobalRef(env, globalRef);
1249 CHECK_JNI_EXIT_VOID();
1250 }
1251 }
1252
1253 static void DeleteWeakGlobalRef(JNIEnv* env, jweak weakGlobalRef) {
1254 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, weakGlobalRef);
1255 if (weakGlobalRef != NULL && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) {
1256 LOG(ERROR) << "JNI ERROR: DeleteWeakGlobalRef on " << GetIndirectRefKind(weakGlobalRef) << ": " << weakGlobalRef;
1257 JniAbort(__FUNCTION__);
1258 } else {
1259 baseEnv(env)->DeleteWeakGlobalRef(env, weakGlobalRef);
1260 CHECK_JNI_EXIT_VOID();
1261 }
1262 }
1263
1264 static void DeleteLocalRef(JNIEnv* env, jobject localRef) {
1265 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
1266 if (localRef != NULL && GetIndirectRefKind(localRef) != kLocal) {
1267 LOG(ERROR) << "JNI ERROR: DeleteLocalRef on " << GetIndirectRefKind(localRef) << ": " << localRef;
1268 JniAbort(__FUNCTION__);
1269 } else {
1270 baseEnv(env)->DeleteLocalRef(env, localRef);
1271 CHECK_JNI_EXIT_VOID();
1272 }
1273 }
1274
1275 static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
1276 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
1277 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
1278 }
1279
1280 static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
1281 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
1282 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
1283 }
1284
1285 static jobject AllocObject(JNIEnv* env, jclass clazz) {
1286 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1287 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz));
1288 }
1289
1290 static jobject NewObject(JNIEnv* env, jclass clazz, jmethodID mid, ...) {
1291 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1292 va_list args;
1293 va_start(args, mid);
1294 jobject result = baseEnv(env)->NewObjectV(env, clazz, mid, args);
1295 va_end(args);
1296 return CHECK_JNI_EXIT("L", result);
1297 }
1298
1299 static jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) {
1300 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1301 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, mid, args));
1302 }
1303
1304 static jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) {
1305 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1306 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, mid, args));
1307 }
1308
1309 static jclass GetObjectClass(JNIEnv* env, jobject obj) {
1310 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1311 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
1312 }
1313
1314 static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
1315 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz);
1316 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz));
1317 }
1318
1319 static jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1320 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1321 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig));
1322 }
1323
1324 static jfieldID GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1325 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1326 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig));
1327 }
1328
1329 static jmethodID GetStaticMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1330 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1331 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig));
1332 }
1333
1334 static jfieldID GetStaticFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1335 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1336 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig));
1337 }
1338
1339#define FIELD_ACCESSORS(_ctype, _jname, _type) \
1340 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid) { \
1341 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001342 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001343 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fid)); \
1344 } \
1345 static _ctype Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid) { \
1346 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001347 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001348 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fid)); \
1349 } \
1350 static void SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid, _ctype value) { \
1351 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001352 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001353 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001354 sc.CheckFieldType((jobject)(uint32_t)value, fid, _type[0], true); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001355 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fid, value); \
1356 CHECK_JNI_EXIT_VOID(); \
1357 } \
1358 static void Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid, _ctype value) { \
1359 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001360 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001361 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001362 sc.CheckFieldType((jobject)(uint32_t) value, fid, _type[0], false); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001363 baseEnv(env)->Set##_jname##Field(env, obj, fid, value); \
1364 CHECK_JNI_EXIT_VOID(); \
1365 }
1366
1367FIELD_ACCESSORS(jobject, Object, "L");
1368FIELD_ACCESSORS(jboolean, Boolean, "Z");
1369FIELD_ACCESSORS(jbyte, Byte, "B");
1370FIELD_ACCESSORS(jchar, Char, "C");
1371FIELD_ACCESSORS(jshort, Short, "S");
1372FIELD_ACCESSORS(jint, Int, "I");
1373FIELD_ACCESSORS(jlong, Long, "J");
1374FIELD_ACCESSORS(jfloat, Float, "F");
1375FIELD_ACCESSORS(jdouble, Double, "D");
1376
1377#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
1378 /* Virtual... */ \
1379 static _ctype Call##_jname##Method(JNIEnv* env, jobject obj, \
1380 jmethodID mid, ...) \
1381 { \
1382 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001383 sc.CheckSig(mid, _retsig, false); \
1384 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001385 _retdecl; \
1386 va_list args; \
1387 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001388 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001389 va_end(args); \
1390 _retok; \
1391 } \
1392 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1393 jmethodID mid, va_list args) \
1394 { \
1395 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001396 sc.CheckSig(mid, _retsig, false); \
1397 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001398 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001399 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001400 _retok; \
1401 } \
1402 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1403 jmethodID mid, jvalue* args) \
1404 { \
1405 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001406 sc.CheckSig(mid, _retsig, false); \
1407 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001408 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001409 _retasgn(baseEnv(env)->Call##_jname##MethodA(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001410 _retok; \
1411 } \
1412 /* Non-virtual... */ \
1413 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, \
1414 jobject obj, jclass clazz, jmethodID mid, ...) \
1415 { \
1416 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001417 sc.CheckSig(mid, _retsig, false); \
1418 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001419 _retdecl; \
1420 va_list args; \
1421 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001422 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001423 va_end(args); \
1424 _retok; \
1425 } \
1426 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, \
1427 jobject obj, jclass clazz, jmethodID mid, va_list args) \
1428 { \
1429 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001430 sc.CheckSig(mid, _retsig, false); \
1431 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001432 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001433 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001434 _retok; \
1435 } \
1436 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, \
1437 jobject obj, jclass clazz, jmethodID mid, jvalue* args) \
1438 { \
1439 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001440 sc.CheckSig(mid, _retsig, false); \
1441 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001442 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001443 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001444 _retok; \
1445 } \
1446 /* Static... */ \
1447 static _ctype CallStatic##_jname##Method(JNIEnv* env, \
1448 jclass clazz, jmethodID mid, ...) \
1449 { \
1450 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001451 sc.CheckSig(mid, _retsig, true); \
1452 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001453 _retdecl; \
1454 va_list args; \
1455 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001456 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001457 va_end(args); \
1458 _retok; \
1459 } \
1460 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, \
1461 jclass clazz, jmethodID mid, va_list args) \
1462 { \
1463 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001464 sc.CheckSig(mid, _retsig, true); \
1465 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001466 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001467 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001468 _retok; \
1469 } \
1470 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, \
1471 jclass clazz, jmethodID mid, jvalue* args) \
1472 { \
1473 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001474 sc.CheckSig(mid, _retsig, true); \
1475 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001476 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001477 _retasgn(baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001478 _retok; \
1479 }
1480
1481#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
1482#define VOID_RETURN CHECK_JNI_EXIT_VOID()
1483
Elliott Hughesba8eee12012-01-24 20:25:24 -08001484CALL(jobject, Object, Object* result, result = reinterpret_cast<Object*>, NON_VOID_RETURN("L", jobject), "L");
1485CALL(jboolean, Boolean, jboolean result, result =, NON_VOID_RETURN("Z", jboolean), "Z");
1486CALL(jbyte, Byte, jbyte result, result =, NON_VOID_RETURN("B", jbyte), "B");
1487CALL(jchar, Char, jchar result, result =, NON_VOID_RETURN("C", jchar), "C");
1488CALL(jshort, Short, jshort result, result =, NON_VOID_RETURN("S", jshort), "S");
1489CALL(jint, Int, jint result, result =, NON_VOID_RETURN("I", jint), "I");
1490CALL(jlong, Long, jlong result, result =, NON_VOID_RETURN("J", jlong), "J");
1491CALL(jfloat, Float, jfloat result, result =, NON_VOID_RETURN("F", jfloat), "F");
1492CALL(jdouble, Double, jdouble result, result =, NON_VOID_RETURN("D", jdouble), "D");
Elliott Hughesa2501992011-08-26 19:39:54 -07001493CALL(void, Void, , , VOID_RETURN, "V");
1494
1495 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
1496 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
1497 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
1498 }
1499
1500 static jsize GetStringLength(JNIEnv* env, jstring string) {
1501 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1502 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
1503 }
1504
1505 static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1506 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, java_string, isCopy);
1507 const jchar* result = baseEnv(env)->GetStringChars(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001508 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001509 ScopedJniThreadState ts(env);
1510 String* s = Decode<String*>(ts, java_string);
1511 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001512 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001513 if (isCopy != NULL) {
1514 *isCopy = JNI_TRUE;
1515 }
1516 }
1517 return CHECK_JNI_EXIT("p", result);
1518 }
1519
1520 static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
1521 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001522 sc.CheckNonNull(chars);
1523 if (sc.ForceCopy()) {
1524 GuardedCopy::Check(__FUNCTION__, chars, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001525 chars = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(chars)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001526 }
1527 baseEnv(env)->ReleaseStringChars(env, string, chars);
1528 CHECK_JNI_EXIT_VOID();
1529 }
1530
1531 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
1532 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
1533 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
1534 }
1535
1536 static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
1537 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1538 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
1539 }
1540
1541 static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1542 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1543 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001544 if (sc.ForceCopy() && result != NULL) {
1545 result = (const char*) GuardedCopy::Create(result, strlen(result) + 1, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001546 if (isCopy != NULL) {
1547 *isCopy = JNI_TRUE;
1548 }
1549 }
1550 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
1551 }
1552
1553 static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
1554 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001555 if (sc.ForceCopy()) {
1556 GuardedCopy::Check(__FUNCTION__, utf, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001557 utf = reinterpret_cast<const char*>(GuardedCopy::Destroy(const_cast<char*>(utf)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001558 }
1559 baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
1560 CHECK_JNI_EXIT_VOID();
1561 }
1562
1563 static jsize GetArrayLength(JNIEnv* env, jarray array) {
1564 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
1565 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
1566 }
1567
1568 static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass elementClass, jobject initialElement) {
1569 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
1570 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
1571 }
1572
1573 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
1574 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
1575 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
1576 }
1577
1578 static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
1579 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
1580 baseEnv(env)->SetObjectArrayElement(env, array, index, value);
1581 CHECK_JNI_EXIT_VOID();
1582 }
1583
1584#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
1585 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
1586 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
1587 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
1588 }
1589NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
1590NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
1591NEW_PRIMITIVE_ARRAY(jcharArray, Char);
1592NEW_PRIMITIVE_ARRAY(jshortArray, Short);
1593NEW_PRIMITIVE_ARRAY(jintArray, Int);
1594NEW_PRIMITIVE_ARRAY(jlongArray, Long);
1595NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
1596NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
1597
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001598struct ForceCopyGetChecker {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001599 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07001600 ForceCopyGetChecker(ScopedCheck& sc, jboolean* isCopy) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001601 force_copy = sc.ForceCopy();
1602 no_copy = 0;
1603 if (force_copy && isCopy != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001604 /* capture this before the base call tramples on it */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001605 no_copy = *reinterpret_cast<uint32_t*>(isCopy);
Elliott Hughesa2501992011-08-26 19:39:54 -07001606 }
1607 }
1608
1609 template<typename ResultT>
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001610 ResultT Check(JNIEnv* env, jarray array, jboolean* isCopy, ResultT result) {
1611 if (force_copy && result != NULL) {
1612 if (no_copy != kNoCopyMagic) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001613 result = reinterpret_cast<ResultT>(CreateGuardedPACopy(env, array, isCopy));
1614 }
1615 }
1616 return result;
1617 }
1618
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001619 uint32_t no_copy;
1620 bool force_copy;
Elliott Hughesa2501992011-08-26 19:39:54 -07001621};
1622
1623#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1624 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, jboolean* isCopy) { \
1625 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001626 _ctype* result = ForceCopyGetChecker(sc, isCopy).Check(env, array, isCopy, baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001627 return CHECK_JNI_EXIT("p", result); \
1628 }
1629
1630#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1631 static void Release##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, _ctype* elems, jint mode) { \
1632 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001633 sc.CheckNonNull(elems); \
1634 if (sc.ForceCopy()) { \
Elliott Hughesa2501992011-08-26 19:39:54 -07001635 ReleaseGuardedPACopy(env, array, elems, mode); \
1636 } \
1637 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
1638 CHECK_JNI_EXIT_VOID(); \
1639 }
1640
1641#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1642 static void Get##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
1643 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1644 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
1645 CHECK_JNI_EXIT_VOID(); \
1646 }
1647
1648#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1649 static void Set##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
1650 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1651 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
1652 CHECK_JNI_EXIT_VOID(); \
1653 }
1654
1655#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
1656 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1657 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1658 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
1659 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
1660
1661/* TODO: verify primitive array type matches call type */
1662PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
1663PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
1664PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
1665PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
1666PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
1667PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
1668PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
1669PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
1670
1671 static jint RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) {
1672 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods);
1673 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods));
1674 }
1675
1676 static jint UnregisterNatives(JNIEnv* env, jclass clazz) {
1677 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1678 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz));
1679 }
1680
1681 static jint MonitorEnter(JNIEnv* env, jobject obj) {
1682 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1683 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
1684 }
1685
1686 static jint MonitorExit(JNIEnv* env, jobject obj) {
1687 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
1688 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
1689 }
1690
1691 static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
1692 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
1693 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
1694 }
1695
1696 static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
1697 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1698 baseEnv(env)->GetStringRegion(env, str, start, len, buf);
1699 CHECK_JNI_EXIT_VOID();
1700 }
1701
1702 static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
1703 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1704 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
1705 CHECK_JNI_EXIT_VOID();
1706 }
1707
1708 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
1709 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
1710 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001711 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001712 result = CreateGuardedPACopy(env, array, isCopy);
1713 }
1714 return CHECK_JNI_EXIT("p", result);
1715 }
1716
1717 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
1718 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001719 sc.CheckNonNull(carray);
1720 if (sc.ForceCopy()) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001721 ReleaseGuardedPACopy(env, array, carray, mode);
1722 }
1723 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
1724 CHECK_JNI_EXIT_VOID();
1725 }
1726
1727 static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1728 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, java_string, isCopy);
1729 const jchar* result = baseEnv(env)->GetStringCritical(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001730 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001731 ScopedJniThreadState ts(env);
1732 String* s = Decode<String*>(ts, java_string);
1733 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001734 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001735 if (isCopy != NULL) {
1736 *isCopy = JNI_TRUE;
1737 }
1738 }
1739 return CHECK_JNI_EXIT("p", result);
1740 }
1741
1742 static void ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
1743 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001744 sc.CheckNonNull(carray);
1745 if (sc.ForceCopy()) {
1746 GuardedCopy::Check(__FUNCTION__, carray, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001747 carray = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(carray)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001748 }
1749 baseEnv(env)->ReleaseStringCritical(env, string, carray);
1750 CHECK_JNI_EXIT_VOID();
1751 }
1752
1753 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
1754 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1755 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
1756 }
1757
1758 static jboolean ExceptionCheck(JNIEnv* env) {
1759 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
1760 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
1761 }
1762
1763 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
1764 // Note: we use "Ep" rather than "EL" because this is the one JNI function
1765 // that it's okay to pass an invalid reference to.
1766 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, obj);
1767 // TODO: proper decoding of jobjectRefType!
1768 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
1769 }
1770
1771 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
1772 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
1773 if (address == NULL) {
1774 LOG(ERROR) << "JNI ERROR: non-nullable address is NULL";
1775 JniAbort(__FUNCTION__);
1776 }
1777 if (capacity <= 0) {
1778 LOG(ERROR) << "JNI ERROR: capacity must be greater than 0: " << capacity;
1779 JniAbort(__FUNCTION__);
1780 }
1781 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
1782 }
1783
1784 static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
1785 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1786 // TODO: check that 'buf' is a java.nio.Buffer.
1787 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
1788 }
1789
1790 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
1791 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1792 // TODO: check that 'buf' is a java.nio.Buffer.
1793 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
1794 }
1795
1796 private:
1797 static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
1798 return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions;
1799 }
1800};
1801
1802const JNINativeInterface gCheckNativeInterface = {
1803 NULL, // reserved0.
1804 NULL, // reserved1.
1805 NULL, // reserved2.
1806 NULL, // reserved3.
1807 CheckJNI::GetVersion,
1808 CheckJNI::DefineClass,
1809 CheckJNI::FindClass,
1810 CheckJNI::FromReflectedMethod,
1811 CheckJNI::FromReflectedField,
1812 CheckJNI::ToReflectedMethod,
1813 CheckJNI::GetSuperclass,
1814 CheckJNI::IsAssignableFrom,
1815 CheckJNI::ToReflectedField,
1816 CheckJNI::Throw,
1817 CheckJNI::ThrowNew,
1818 CheckJNI::ExceptionOccurred,
1819 CheckJNI::ExceptionDescribe,
1820 CheckJNI::ExceptionClear,
1821 CheckJNI::FatalError,
1822 CheckJNI::PushLocalFrame,
1823 CheckJNI::PopLocalFrame,
1824 CheckJNI::NewGlobalRef,
1825 CheckJNI::DeleteGlobalRef,
1826 CheckJNI::DeleteLocalRef,
1827 CheckJNI::IsSameObject,
1828 CheckJNI::NewLocalRef,
1829 CheckJNI::EnsureLocalCapacity,
1830 CheckJNI::AllocObject,
1831 CheckJNI::NewObject,
1832 CheckJNI::NewObjectV,
1833 CheckJNI::NewObjectA,
1834 CheckJNI::GetObjectClass,
1835 CheckJNI::IsInstanceOf,
1836 CheckJNI::GetMethodID,
1837 CheckJNI::CallObjectMethod,
1838 CheckJNI::CallObjectMethodV,
1839 CheckJNI::CallObjectMethodA,
1840 CheckJNI::CallBooleanMethod,
1841 CheckJNI::CallBooleanMethodV,
1842 CheckJNI::CallBooleanMethodA,
1843 CheckJNI::CallByteMethod,
1844 CheckJNI::CallByteMethodV,
1845 CheckJNI::CallByteMethodA,
1846 CheckJNI::CallCharMethod,
1847 CheckJNI::CallCharMethodV,
1848 CheckJNI::CallCharMethodA,
1849 CheckJNI::CallShortMethod,
1850 CheckJNI::CallShortMethodV,
1851 CheckJNI::CallShortMethodA,
1852 CheckJNI::CallIntMethod,
1853 CheckJNI::CallIntMethodV,
1854 CheckJNI::CallIntMethodA,
1855 CheckJNI::CallLongMethod,
1856 CheckJNI::CallLongMethodV,
1857 CheckJNI::CallLongMethodA,
1858 CheckJNI::CallFloatMethod,
1859 CheckJNI::CallFloatMethodV,
1860 CheckJNI::CallFloatMethodA,
1861 CheckJNI::CallDoubleMethod,
1862 CheckJNI::CallDoubleMethodV,
1863 CheckJNI::CallDoubleMethodA,
1864 CheckJNI::CallVoidMethod,
1865 CheckJNI::CallVoidMethodV,
1866 CheckJNI::CallVoidMethodA,
1867 CheckJNI::CallNonvirtualObjectMethod,
1868 CheckJNI::CallNonvirtualObjectMethodV,
1869 CheckJNI::CallNonvirtualObjectMethodA,
1870 CheckJNI::CallNonvirtualBooleanMethod,
1871 CheckJNI::CallNonvirtualBooleanMethodV,
1872 CheckJNI::CallNonvirtualBooleanMethodA,
1873 CheckJNI::CallNonvirtualByteMethod,
1874 CheckJNI::CallNonvirtualByteMethodV,
1875 CheckJNI::CallNonvirtualByteMethodA,
1876 CheckJNI::CallNonvirtualCharMethod,
1877 CheckJNI::CallNonvirtualCharMethodV,
1878 CheckJNI::CallNonvirtualCharMethodA,
1879 CheckJNI::CallNonvirtualShortMethod,
1880 CheckJNI::CallNonvirtualShortMethodV,
1881 CheckJNI::CallNonvirtualShortMethodA,
1882 CheckJNI::CallNonvirtualIntMethod,
1883 CheckJNI::CallNonvirtualIntMethodV,
1884 CheckJNI::CallNonvirtualIntMethodA,
1885 CheckJNI::CallNonvirtualLongMethod,
1886 CheckJNI::CallNonvirtualLongMethodV,
1887 CheckJNI::CallNonvirtualLongMethodA,
1888 CheckJNI::CallNonvirtualFloatMethod,
1889 CheckJNI::CallNonvirtualFloatMethodV,
1890 CheckJNI::CallNonvirtualFloatMethodA,
1891 CheckJNI::CallNonvirtualDoubleMethod,
1892 CheckJNI::CallNonvirtualDoubleMethodV,
1893 CheckJNI::CallNonvirtualDoubleMethodA,
1894 CheckJNI::CallNonvirtualVoidMethod,
1895 CheckJNI::CallNonvirtualVoidMethodV,
1896 CheckJNI::CallNonvirtualVoidMethodA,
1897 CheckJNI::GetFieldID,
1898 CheckJNI::GetObjectField,
1899 CheckJNI::GetBooleanField,
1900 CheckJNI::GetByteField,
1901 CheckJNI::GetCharField,
1902 CheckJNI::GetShortField,
1903 CheckJNI::GetIntField,
1904 CheckJNI::GetLongField,
1905 CheckJNI::GetFloatField,
1906 CheckJNI::GetDoubleField,
1907 CheckJNI::SetObjectField,
1908 CheckJNI::SetBooleanField,
1909 CheckJNI::SetByteField,
1910 CheckJNI::SetCharField,
1911 CheckJNI::SetShortField,
1912 CheckJNI::SetIntField,
1913 CheckJNI::SetLongField,
1914 CheckJNI::SetFloatField,
1915 CheckJNI::SetDoubleField,
1916 CheckJNI::GetStaticMethodID,
1917 CheckJNI::CallStaticObjectMethod,
1918 CheckJNI::CallStaticObjectMethodV,
1919 CheckJNI::CallStaticObjectMethodA,
1920 CheckJNI::CallStaticBooleanMethod,
1921 CheckJNI::CallStaticBooleanMethodV,
1922 CheckJNI::CallStaticBooleanMethodA,
1923 CheckJNI::CallStaticByteMethod,
1924 CheckJNI::CallStaticByteMethodV,
1925 CheckJNI::CallStaticByteMethodA,
1926 CheckJNI::CallStaticCharMethod,
1927 CheckJNI::CallStaticCharMethodV,
1928 CheckJNI::CallStaticCharMethodA,
1929 CheckJNI::CallStaticShortMethod,
1930 CheckJNI::CallStaticShortMethodV,
1931 CheckJNI::CallStaticShortMethodA,
1932 CheckJNI::CallStaticIntMethod,
1933 CheckJNI::CallStaticIntMethodV,
1934 CheckJNI::CallStaticIntMethodA,
1935 CheckJNI::CallStaticLongMethod,
1936 CheckJNI::CallStaticLongMethodV,
1937 CheckJNI::CallStaticLongMethodA,
1938 CheckJNI::CallStaticFloatMethod,
1939 CheckJNI::CallStaticFloatMethodV,
1940 CheckJNI::CallStaticFloatMethodA,
1941 CheckJNI::CallStaticDoubleMethod,
1942 CheckJNI::CallStaticDoubleMethodV,
1943 CheckJNI::CallStaticDoubleMethodA,
1944 CheckJNI::CallStaticVoidMethod,
1945 CheckJNI::CallStaticVoidMethodV,
1946 CheckJNI::CallStaticVoidMethodA,
1947 CheckJNI::GetStaticFieldID,
1948 CheckJNI::GetStaticObjectField,
1949 CheckJNI::GetStaticBooleanField,
1950 CheckJNI::GetStaticByteField,
1951 CheckJNI::GetStaticCharField,
1952 CheckJNI::GetStaticShortField,
1953 CheckJNI::GetStaticIntField,
1954 CheckJNI::GetStaticLongField,
1955 CheckJNI::GetStaticFloatField,
1956 CheckJNI::GetStaticDoubleField,
1957 CheckJNI::SetStaticObjectField,
1958 CheckJNI::SetStaticBooleanField,
1959 CheckJNI::SetStaticByteField,
1960 CheckJNI::SetStaticCharField,
1961 CheckJNI::SetStaticShortField,
1962 CheckJNI::SetStaticIntField,
1963 CheckJNI::SetStaticLongField,
1964 CheckJNI::SetStaticFloatField,
1965 CheckJNI::SetStaticDoubleField,
1966 CheckJNI::NewString,
1967 CheckJNI::GetStringLength,
1968 CheckJNI::GetStringChars,
1969 CheckJNI::ReleaseStringChars,
1970 CheckJNI::NewStringUTF,
1971 CheckJNI::GetStringUTFLength,
1972 CheckJNI::GetStringUTFChars,
1973 CheckJNI::ReleaseStringUTFChars,
1974 CheckJNI::GetArrayLength,
1975 CheckJNI::NewObjectArray,
1976 CheckJNI::GetObjectArrayElement,
1977 CheckJNI::SetObjectArrayElement,
1978 CheckJNI::NewBooleanArray,
1979 CheckJNI::NewByteArray,
1980 CheckJNI::NewCharArray,
1981 CheckJNI::NewShortArray,
1982 CheckJNI::NewIntArray,
1983 CheckJNI::NewLongArray,
1984 CheckJNI::NewFloatArray,
1985 CheckJNI::NewDoubleArray,
1986 CheckJNI::GetBooleanArrayElements,
1987 CheckJNI::GetByteArrayElements,
1988 CheckJNI::GetCharArrayElements,
1989 CheckJNI::GetShortArrayElements,
1990 CheckJNI::GetIntArrayElements,
1991 CheckJNI::GetLongArrayElements,
1992 CheckJNI::GetFloatArrayElements,
1993 CheckJNI::GetDoubleArrayElements,
1994 CheckJNI::ReleaseBooleanArrayElements,
1995 CheckJNI::ReleaseByteArrayElements,
1996 CheckJNI::ReleaseCharArrayElements,
1997 CheckJNI::ReleaseShortArrayElements,
1998 CheckJNI::ReleaseIntArrayElements,
1999 CheckJNI::ReleaseLongArrayElements,
2000 CheckJNI::ReleaseFloatArrayElements,
2001 CheckJNI::ReleaseDoubleArrayElements,
2002 CheckJNI::GetBooleanArrayRegion,
2003 CheckJNI::GetByteArrayRegion,
2004 CheckJNI::GetCharArrayRegion,
2005 CheckJNI::GetShortArrayRegion,
2006 CheckJNI::GetIntArrayRegion,
2007 CheckJNI::GetLongArrayRegion,
2008 CheckJNI::GetFloatArrayRegion,
2009 CheckJNI::GetDoubleArrayRegion,
2010 CheckJNI::SetBooleanArrayRegion,
2011 CheckJNI::SetByteArrayRegion,
2012 CheckJNI::SetCharArrayRegion,
2013 CheckJNI::SetShortArrayRegion,
2014 CheckJNI::SetIntArrayRegion,
2015 CheckJNI::SetLongArrayRegion,
2016 CheckJNI::SetFloatArrayRegion,
2017 CheckJNI::SetDoubleArrayRegion,
2018 CheckJNI::RegisterNatives,
2019 CheckJNI::UnregisterNatives,
2020 CheckJNI::MonitorEnter,
2021 CheckJNI::MonitorExit,
2022 CheckJNI::GetJavaVM,
2023 CheckJNI::GetStringRegion,
2024 CheckJNI::GetStringUTFRegion,
2025 CheckJNI::GetPrimitiveArrayCritical,
2026 CheckJNI::ReleasePrimitiveArrayCritical,
2027 CheckJNI::GetStringCritical,
2028 CheckJNI::ReleaseStringCritical,
2029 CheckJNI::NewWeakGlobalRef,
2030 CheckJNI::DeleteWeakGlobalRef,
2031 CheckJNI::ExceptionCheck,
2032 CheckJNI::NewDirectByteBuffer,
2033 CheckJNI::GetDirectBufferAddress,
2034 CheckJNI::GetDirectBufferCapacity,
2035 CheckJNI::GetObjectRefType,
2036};
2037
2038const JNINativeInterface* GetCheckJniNativeInterface() {
2039 return &gCheckNativeInterface;
2040}
2041
2042class CheckJII {
Elliott Hughesba8eee12012-01-24 20:25:24 -08002043 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07002044 static jint DestroyJavaVM(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002045 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002046 sc.Check(true, "v", vm);
2047 return CHECK_JNI_EXIT("I", BaseVm(vm)->DestroyJavaVM(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002048 }
2049
2050 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002051 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002052 sc.Check(true, "vpp", vm, p_env, thr_args);
2053 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002054 }
2055
2056 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002057 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002058 sc.Check(true, "vpp", vm, p_env, thr_args);
2059 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002060 }
2061
2062 static jint DetachCurrentThread(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002063 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002064 sc.Check(true, "v", vm);
2065 return CHECK_JNI_EXIT("I", BaseVm(vm)->DetachCurrentThread(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002066 }
2067
2068 static jint GetEnv(JavaVM* vm, void** env, jint version) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002069 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002070 sc.Check(true, "v", vm);
2071 return CHECK_JNI_EXIT("I", BaseVm(vm)->GetEnv(vm, env, version));
Elliott Hughesa2501992011-08-26 19:39:54 -07002072 }
2073
2074 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002075 static inline const JNIInvokeInterface* BaseVm(JavaVM* vm) {
Elliott Hughesa2501992011-08-26 19:39:54 -07002076 return reinterpret_cast<JavaVMExt*>(vm)->unchecked_functions;
2077 }
2078};
2079
2080const JNIInvokeInterface gCheckInvokeInterface = {
2081 NULL, // reserved0
2082 NULL, // reserved1
2083 NULL, // reserved2
2084 CheckJII::DestroyJavaVM,
2085 CheckJII::AttachCurrentThread,
2086 CheckJII::DetachCurrentThread,
2087 CheckJII::GetEnv,
2088 CheckJII::AttachCurrentThreadAsDaemon
2089};
2090
2091const JNIInvokeInterface* GetCheckJniInvokeInterface() {
2092 return &gCheckInvokeInterface;
2093}
2094
2095} // namespace art