blob: 6ff0fd779b51b66d4a8c32ed5c25152486609d59 [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"
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -070024#include "scoped_jni_thread_state.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070025#include "thread.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070026#include "runtime.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070027
Elliott Hughese6087632011-09-26 12:18:25 -070028#define LIBCORE_CPP_JNI_HELPERS
29#include <JNIHelp.h> // from libcore
30#undef LIBCORE_CPP_JNI_HELPERS
31
Elliott Hughesa2501992011-08-26 19:39:54 -070032namespace art {
33
34void JniAbort(const char* jni_function_name) {
Elliott Hughesa0957642011-09-02 14:27:33 -070035 Thread* self = Thread::Current();
36 const Method* current_method = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -070037
Elliott Hughesa0957642011-09-02 14:27:33 -070038 std::stringstream os;
Elliott Hughese6087632011-09-26 12:18:25 -070039 os << "Aborting because JNI app bug detected (see above for details)";
Elliott Hughesa2501992011-08-26 19:39:54 -070040
41 if (jni_function_name != NULL) {
42 os << "\n in call to " << jni_function_name;
43 }
Elliott Hughesa0957642011-09-02 14:27:33 -070044 // TODO: is this useful given that we're about to dump the calling thread's stack?
45 if (current_method != NULL) {
46 os << "\n from " << PrettyMethod(current_method);
47 }
48 os << "\n";
49 self->Dump(os);
Elliott Hughesa2501992011-08-26 19:39:54 -070050
51 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
52 if (vm->check_jni_abort_hook != NULL) {
53 vm->check_jni_abort_hook(os.str());
54 } else {
55 LOG(FATAL) << os.str();
56 }
57}
58
59/*
60 * ===========================================================================
61 * JNI function helpers
62 * ===========================================================================
63 */
64
Elliott Hughesa2501992011-08-26 19:39:54 -070065template<typename T>
66T Decode(ScopedJniThreadState& ts, jobject obj) {
67 return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
68}
69
Elliott Hughesa2501992011-08-26 19:39:54 -070070/*
71 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
72 * The code deliberately uses an invalid sequence of operations, so we
73 * need to pass it through unmodified. Review that code before making
74 * any changes here.
75 */
76#define kNoCopyMagic 0xd5aab57f
77
78/*
79 * Flags passed into ScopedCheck.
80 */
81#define kFlag_Default 0x0000
82
83#define kFlag_CritBad 0x0000 /* calling while in critical is bad */
84#define kFlag_CritOkay 0x0001 /* ...okay */
85#define kFlag_CritGet 0x0002 /* this is a critical "get" */
86#define kFlag_CritRelease 0x0003 /* this is a critical "release" */
87#define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */
88
89#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */
90#define kFlag_ExcepOkay 0x0004 /* ...okay */
91
92#define kFlag_Release 0x0010 /* are we in a non-critical release function? */
93#define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */
94
95#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */
96
Elliott Hughesa0957642011-09-02 14:27:33 -070097static const char* gBuiltInPrefixes[] = {
98 "Landroid/",
99 "Lcom/android/",
100 "Lcom/google/android/",
101 "Ldalvik/",
102 "Ljava/",
103 "Ljavax/",
104 "Llibcore/",
105 "Lorg/apache/harmony/",
106 NULL
107};
108
109bool ShouldTrace(JavaVMExt* vm, const Method* method) {
110 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
111 // when a native method that matches the -Xjnitrace argument calls a JNI function
112 // such as NewByteArray.
113 // If -verbose:third-party-jni is on, we want to log any JNI function calls
114 // made by a third-party native method.
115 std::string classNameStr(method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8());
116 if (!vm->trace.empty() && classNameStr.find(vm->trace) != std::string::npos) {
117 return true;
118 }
119 if (vm->log_third_party_jni) {
120 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
121 // like part of Android.
122 StringPiece className(classNameStr);
123 for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) {
124 if (className.starts_with(gBuiltInPrefixes[i])) {
125 return false;
126 }
127 }
128 return true;
129 }
130 return false;
131}
132
Elliott Hughesa2501992011-08-26 19:39:54 -0700133class ScopedCheck {
134public:
135 // For JNIEnv* functions.
136 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700137 init(env, reinterpret_cast<JNIEnvExt*>(env)->vm, flags, functionName, true);
Elliott Hughesa2501992011-08-26 19:39:54 -0700138 checkThread(flags);
139 }
140
141 // For JavaVM* functions.
Elliott Hughesa0957642011-09-02 14:27:33 -0700142 explicit ScopedCheck(JavaVM* vm, bool hasMethod, const char* functionName) {
143 init(NULL, vm, kFlag_Invocation, functionName, hasMethod);
Elliott Hughesa2501992011-08-26 19:39:54 -0700144 }
145
146 bool forceCopy() {
147 return Runtime::Current()->GetJavaVM()->force_copy;
148 }
149
150 /*
151 * In some circumstances the VM will screen class names, but it doesn't
152 * for class lookup. When things get bounced through a class loader, they
153 * can actually get normalized a couple of times; as a result, passing in
154 * a class name like "java.lang.Thread" instead of "java/lang/Thread" will
155 * work in some circumstances.
156 *
157 * This is incorrect and could cause strange behavior or compatibility
158 * problems, so we want to screen that out here.
159 *
160 * We expect "fully-qualified" class names, like "java/lang/Thread" or
161 * "[Ljava/lang/Object;".
162 */
163 void checkClassName(const char* className) {
164 if (!IsValidClassName(className, true, false)) {
165 LOG(ERROR) << "JNI ERROR: illegal class name '" << className << "' (" << mFunctionName << ")\n"
166 << " (should be of the form 'java/lang/String', [Ljava/lang/String;' or '[[B')\n";
167 JniAbort();
168 }
169 }
170
171 /*
172 * Verify that the field is of the appropriate type. If the field has an
173 * object type, "java_object" is the object we're trying to assign into it.
174 *
175 * Works for both static and instance fields.
176 */
177 void checkFieldType(jobject java_object, jfieldID fid, char prim, bool isStatic) {
178 if (fid == NULL) {
179 LOG(ERROR) << "JNI ERROR: null jfieldID";
180 JniAbort();
181 return;
182 }
183
184 ScopedJniThreadState ts(mEnv);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700185 Field* f = DecodeField(fid);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700186 Class* field_type = f->GetType();
187 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 */
229 void checkInstanceFieldID(jobject java_object, jfieldID fid) {
230 ScopedJniThreadState ts(mEnv);
231
232 Object* o = Decode<Object*>(ts, java_object);
233 if (!Heap::IsHeapAddress(o)) {
234 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
235 JniAbort();
236 return;
237 }
238
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700239 Field* f = DecodeField(fid);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700240 Class* f_type = f->GetType();
241 // check invariant that all jfieldIDs have resovled types
242 DCHECK(f_type != NULL);
Elliott Hughesa2501992011-08-26 19:39:54 -0700243 Class* c = o->GetClass();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700244 if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f_type) == NULL) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700245 LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f) << " not valid for an object of class " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700246 JniAbort();
247 }
248 }
249
250 /*
251 * Verify that the pointer value is non-NULL.
252 */
253 void checkNonNull(const void* ptr) {
254 if (ptr == NULL) {
255 LOG(ERROR) << "JNI ERROR: invalid null pointer";
256 JniAbort();
257 }
258 }
259
260 /*
261 * Verify that the method's return type matches the type of call.
262 * 'expectedType' will be "L" for all objects, including arrays.
263 */
264 void checkSig(jmethodID mid, const char* expectedType, bool isStatic) {
265 ScopedJniThreadState ts(mEnv);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700266 const Method* m = DecodeMethod(mid);
Brian Carlstrom2ed67392011-09-09 14:53:28 -0700267 if (*expectedType != m->GetShorty()->CharAt(0)) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700268 LOG(ERROR) << "JNI ERROR: expected return type '" << *expectedType << "' calling " << PrettyMethod(m);
Elliott Hughesa2501992011-08-26 19:39:54 -0700269 JniAbort();
270 } else if (isStatic && !m->IsStatic()) {
271 if (isStatic) {
272 LOG(ERROR) << "JNI ERROR: calling non-static method " << PrettyMethod(m) << " with static call";
273 } else {
274 LOG(ERROR) << "JNI ERROR: calling static method " << PrettyMethod(m) << " with non-static call";
275 }
276 JniAbort();
277 }
278 }
279
280 /*
281 * Verify that this static field ID is valid for this class.
282 *
283 * Assumes "java_class" has already been validated.
284 */
285 void checkStaticFieldID(jclass java_class, jfieldID fid) {
286 ScopedJniThreadState ts(mEnv);
287 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700288 const Field* f = DecodeField(fid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700289 if (f->GetDeclaringClass() != c) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700290 LOG(ERROR) << "JNI ERROR: static jfieldID " << fid << " not valid for class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700291 JniAbort();
292 }
293 }
294
295 /*
296 * Verify that "mid" is appropriate for "clazz".
297 *
298 * A mismatch isn't dangerous, because the jmethodID defines the class. In
299 * fact, jclazz is unused in the implementation. It's best if we don't
300 * allow bad code in the system though.
301 *
302 * Instances of "jclazz" must be instances of the method's declaring class.
303 */
304 void checkStaticMethod(jclass java_class, jmethodID mid) {
305 ScopedJniThreadState ts(mEnv);
306 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700307 const Method* m = DecodeMethod(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700308 if (!c->IsAssignableFrom(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700309 LOG(ERROR) << "JNI ERROR: can't call static " << PrettyMethod(m) << " on class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700310 JniAbort();
311 }
312 }
313
314 /*
315 * Verify that "mid" is appropriate for "jobj".
316 *
317 * Make sure the object is an instance of the method's declaring class.
318 * (Note the mid might point to a declaration in an interface; this
319 * will be handled automatically by the instanceof check.)
320 */
321 void checkVirtualMethod(jobject java_object, jmethodID mid) {
322 ScopedJniThreadState ts(mEnv);
323 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700324 const Method* m = DecodeMethod(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700325 if (!o->InstanceOf(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700326 LOG(ERROR) << "JNI ERROR: can't call " << PrettyMethod(m) << " on instance of " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700327 JniAbort();
328 }
329 }
330
331 /**
332 * The format string is a sequence of the following characters,
333 * and must be followed by arguments of the corresponding types
334 * in the same order.
335 *
336 * Java primitive types:
337 * B - jbyte
338 * C - jchar
339 * D - jdouble
340 * F - jfloat
341 * I - jint
342 * J - jlong
343 * S - jshort
344 * Z - jboolean (shown as true and false)
345 * V - void
346 *
347 * Java reference types:
348 * L - jobject
349 * a - jarray
350 * c - jclass
351 * s - jstring
352 *
353 * JNI types:
354 * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
355 * f - jfieldID
356 * m - jmethodID
357 * p - void*
358 * r - jint (for release mode arguments)
359 * u - const char* (modified UTF-8)
360 * z - jsize (for lengths; use i if negative values are okay)
361 * v - JavaVM*
362 * E - JNIEnv*
363 * . - no argument; just print "..." (used for varargs JNI calls)
364 *
365 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
366 */
367 void check(bool entry, const char* fmt0, ...) {
368 va_list ap;
369
Elliott Hughesa0957642011-09-02 14:27:33 -0700370 const Method* traceMethod = NULL;
371 if ((!mVm->trace.empty() || mVm->log_third_party_jni) && mHasMethod) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700372 // We need to guard some of the invocation interface's calls: a bad caller might
373 // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
Elliott Hughesa0957642011-09-02 14:27:33 -0700374 Thread* self = Thread::Current();
375 if ((mFlags & kFlag_Invocation) == 0 || self != NULL) {
376 traceMethod = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -0700377 }
378 }
Elliott Hughesa0957642011-09-02 14:27:33 -0700379
380 if (traceMethod != NULL && ShouldTrace(mVm, traceMethod)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700381 va_start(ap, fmt0);
382 std::string msg;
383 for (const char* fmt = fmt0; *fmt;) {
384 char ch = *fmt++;
385 if (ch == 'B') { // jbyte
386 jbyte b = va_arg(ap, int);
387 if (b >= 0 && b < 10) {
388 StringAppendF(&msg, "%d", b);
389 } else {
390 StringAppendF(&msg, "%#x (%d)", b, b);
391 }
392 } else if (ch == 'C') { // jchar
393 jchar c = va_arg(ap, int);
394 if (c < 0x7f && c >= ' ') {
395 StringAppendF(&msg, "U+%x ('%c')", c, c);
396 } else {
397 StringAppendF(&msg, "U+%x", c);
398 }
399 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
400 StringAppendF(&msg, "%g", va_arg(ap, double));
401 } else if (ch == 'I' || ch == 'S') { // jint, jshort
402 StringAppendF(&msg, "%d", va_arg(ap, int));
403 } else if (ch == 'J') { // jlong
404 StringAppendF(&msg, "%lld", va_arg(ap, jlong));
405 } else if (ch == 'Z') { // jboolean
406 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
407 } else if (ch == 'V') { // void
408 msg += "void";
409 } else if (ch == 'v') { // JavaVM*
410 JavaVM* vm = va_arg(ap, JavaVM*);
411 StringAppendF(&msg, "(JavaVM*)%p", vm);
412 } else if (ch == 'E') { // JNIEnv*
413 JNIEnv* env = va_arg(ap, JNIEnv*);
414 StringAppendF(&msg, "(JNIEnv*)%p", env);
415 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
416 // For logging purposes, these are identical.
417 jobject o = va_arg(ap, jobject);
418 if (o == NULL) {
419 msg += "NULL";
420 } else {
421 StringAppendF(&msg, "%p", o);
422 }
423 } else if (ch == 'b') { // jboolean (JNI-style)
424 jboolean b = va_arg(ap, int);
425 msg += (b ? "JNI_TRUE" : "JNI_FALSE");
426 } else if (ch == 'c') { // jclass
427 jclass jc = va_arg(ap, jclass);
428 Class* c = reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(jc));
429 if (c == NULL) {
430 msg += "NULL";
431 } else if (c == kInvalidIndirectRefObject || !Heap::IsHeapAddress(c)) {
432 StringAppendF(&msg, "%p(INVALID)", jc);
433 } else {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700434 msg += PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700435 if (!entry) {
436 StringAppendF(&msg, " (%p)", jc);
437 }
438 }
439 } else if (ch == 'f') { // jfieldID
440 jfieldID fid = va_arg(ap, jfieldID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700441 Field* f = reinterpret_cast<Field*>(fid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700442 msg += PrettyField(f);
443 if (!entry) {
444 StringAppendF(&msg, " (%p)", fid);
445 }
446 } else if (ch == 'z') { // non-negative jsize
447 // You might expect jsize to be size_t, but it's not; it's the same as jint.
448 // We only treat this specially so we can do the non-negative check.
449 // TODO: maybe this wasn't worth it?
450 jint i = va_arg(ap, jint);
451 StringAppendF(&msg, "%d", i);
452 } else if (ch == 'm') { // jmethodID
453 jmethodID mid = va_arg(ap, jmethodID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700454 Method* m = reinterpret_cast<Method*>(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700455 msg += PrettyMethod(m);
456 if (!entry) {
457 StringAppendF(&msg, " (%p)", mid);
458 }
459 } else if (ch == 'p') { // void* ("pointer")
460 void* p = va_arg(ap, void*);
461 if (p == NULL) {
462 msg += "NULL";
463 } else {
464 StringAppendF(&msg, "(void*) %p", p);
465 }
466 } else if (ch == 'r') { // jint (release mode)
467 jint releaseMode = va_arg(ap, jint);
468 if (releaseMode == 0) {
469 msg += "0";
470 } else if (releaseMode == JNI_ABORT) {
471 msg += "JNI_ABORT";
472 } else if (releaseMode == JNI_COMMIT) {
473 msg += "JNI_COMMIT";
474 } else {
475 StringAppendF(&msg, "invalid release mode %d", releaseMode);
476 }
477 } else if (ch == 'u') { // const char* (modified UTF-8)
478 const char* utf = va_arg(ap, const char*);
479 if (utf == NULL) {
480 msg += "NULL";
481 } else {
482 StringAppendF(&msg, "\"%s\"", utf);
483 }
484 } else if (ch == '.') {
485 msg += "...";
486 } else {
487 LOG(ERROR) << "unknown trace format specifier: " << ch;
488 JniAbort();
489 return;
490 }
491 if (*fmt) {
492 StringAppendF(&msg, ", ");
493 }
494 }
495 va_end(ap);
496
497 if (entry) {
498 if (mHasMethod) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700499 std::string methodName(PrettyMethod(traceMethod, false));
Elliott Hughesa2501992011-08-26 19:39:54 -0700500 LOG(INFO) << "JNI: " << methodName << " -> " << mFunctionName << "(" << msg << ")";
501 mIndent = methodName.size() + 1;
502 } else {
503 LOG(INFO) << "JNI: -> " << mFunctionName << "(" << msg << ")";
504 mIndent = 0;
505 }
506 } else {
507 LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", mIndent, "", mFunctionName, msg.c_str());
508 }
509 }
510
511 // We always do the thorough checks on entry, and never on exit...
512 if (entry) {
513 va_start(ap, fmt0);
514 for (const char* fmt = fmt0; *fmt; ++fmt) {
515 char ch = *fmt;
516 if (ch == 'a') {
517 checkArray(va_arg(ap, jarray));
518 } else if (ch == 'c') {
519 checkInstance(kClass, va_arg(ap, jclass));
520 } else if (ch == 'L') {
521 checkObject(va_arg(ap, jobject));
522 } else if (ch == 'r') {
523 checkReleaseMode(va_arg(ap, jint));
524 } else if (ch == 's') {
525 checkInstance(kString, va_arg(ap, jstring));
526 } else if (ch == 'u') {
527 if ((mFlags & kFlag_Release) != 0) {
528 checkNonNull(va_arg(ap, const char*));
529 } else {
530 bool nullable = ((mFlags & kFlag_NullableUtf) != 0);
531 checkUtfString(va_arg(ap, const char*), nullable);
532 }
533 } else if (ch == 'z') {
534 checkLengthPositive(va_arg(ap, jsize));
535 } else if (strchr("BCISZbfmpEv", ch) != NULL) {
536 va_arg(ap, int); // Skip this argument.
537 } else if (ch == 'D' || ch == 'F') {
538 va_arg(ap, double); // Skip this argument.
539 } else if (ch == 'J') {
540 va_arg(ap, long); // Skip this argument.
541 } else if (ch == '.') {
542 } else {
543 LOG(FATAL) << "unknown check format specifier: " << ch;
544 }
545 }
546 va_end(ap);
547 }
548 }
549
550private:
Elliott Hughesa0957642011-09-02 14:27:33 -0700551 void init(JNIEnv* env, JavaVM* vm, int flags, const char* functionName, bool hasMethod) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700552 mEnv = reinterpret_cast<JNIEnvExt*>(env);
Elliott Hughesa0957642011-09-02 14:27:33 -0700553 mVm = reinterpret_cast<JavaVMExt*>(vm);
Elliott Hughesa2501992011-08-26 19:39:54 -0700554 mFlags = flags;
555 mFunctionName = functionName;
556
557 // Set "hasMethod" to true if we have a valid thread with a method pointer.
558 // We won't have one before attaching a thread, after detaching a thread, or
559 // after destroying the VM.
560 mHasMethod = hasMethod;
561 }
562
563 /*
564 * Verify that "array" is non-NULL and points to an Array object.
565 *
566 * Since we're dealing with objects, switch to "running" mode.
567 */
568 void checkArray(jarray java_array) {
569 if (java_array == NULL) {
570 LOG(ERROR) << "JNI ERROR: received null array";
571 JniAbort();
572 return;
573 }
574
575 ScopedJniThreadState ts(mEnv);
576 Array* a = Decode<Array*>(ts, java_array);
577 if (!Heap::IsHeapAddress(a)) {
578 LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array);
579 JniAbort();
580 } else if (!a->IsArrayInstance()) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700581 LOG(ERROR) << "JNI ERROR: jarray argument has non-array type: " << PrettyTypeOf(a);
Elliott Hughesa2501992011-08-26 19:39:54 -0700582 JniAbort();
583 }
584 }
585
586 void checkLengthPositive(jsize length) {
587 if (length < 0) {
588 LOG(ERROR) << "JNI ERROR: negative jsize: " << length;
589 JniAbort();
590 }
591 }
592
593 /*
594 * Verify that "jobj" is a valid object, and that it's an object that JNI
595 * is allowed to know about. We allow NULL references.
596 *
597 * Switches to "running" mode before performing checks.
598 */
599 void checkObject(jobject java_object) {
600 if (java_object == NULL) {
601 return;
602 }
603
604 ScopedJniThreadState ts(mEnv);
605
606 Object* o = Decode<Object*>(ts, java_object);
607 if (o != NULL && !Heap::IsHeapAddress(o)) {
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700608 // TODO: when we remove work_around_app_jni_bugs, this should be impossible.
Elliott Hughesa2501992011-08-26 19:39:54 -0700609 LOG(ERROR) << "JNI ERROR: native code passing in reference to invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
610 JniAbort();
611 }
612 }
613
614 /*
615 * Verify that the "mode" argument passed to a primitive array Release
616 * function is one of the valid values.
617 */
618 void checkReleaseMode(jint mode) {
619 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
620 LOG(ERROR) << "JNI ERROR: bad value for release mode: " << mode;
621 JniAbort();
622 }
623 }
624
625 void checkThread(int flags) {
626 Thread* self = Thread::Current();
627 if (self == NULL) {
628 LOG(ERROR) << "JNI ERROR: non-VM thread making JNI calls";
629 JniAbort();
630 return;
631 }
632
633 // Get the *correct* JNIEnv by going through our TLS pointer.
634 JNIEnvExt* threadEnv = self->GetJniEnv();
635
636 /*
637 * Verify that the current thread is (a) attached and (b) associated with
638 * this particular instance of JNIEnv.
639 */
640 if (mEnv != threadEnv) {
641 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNIEnv* from thread " << *mEnv->self;
642 // If we're keeping broken code limping along, we need to suppress the abort...
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700643 if (!mEnv->work_around_app_jni_bugs) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700644 JniAbort();
645 return;
646 }
647 }
648
649 /*
650 * Verify that, if this thread previously made a critical "get" call, we
651 * do the corresponding "release" call before we try anything else.
652 */
653 switch (flags & kFlag_CritMask) {
654 case kFlag_CritOkay: // okay to call this method
655 break;
656 case kFlag_CritBad: // not okay to call
657 if (threadEnv->critical) {
658 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNI after critical get";
659 JniAbort();
660 return;
661 }
662 break;
663 case kFlag_CritGet: // this is a "get" call
664 /* don't check here; we allow nested gets */
665 threadEnv->critical++;
666 break;
667 case kFlag_CritRelease: // this is a "release" call
668 threadEnv->critical--;
669 if (threadEnv->critical < 0) {
670 LOG(ERROR) << "JNI ERROR: thread " << *self << " called too many critical releases";
671 JniAbort();
672 return;
673 }
674 break;
675 default:
676 LOG(FATAL) << "bad flags (internal error): " << flags;
677 }
678
679 /*
680 * Verify that, if an exception has been raised, the native code doesn't
681 * make any JNI calls other than the Exception* methods.
682 */
683 if ((flags & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
684 LOG(ERROR) << "JNI ERROR: JNI method called with exception pending";
Elliott Hughese6087632011-09-26 12:18:25 -0700685 LOG(ERROR) << "Pending exception is:";
686 LOG(ERROR) << jniGetStackTrace(mEnv);
Elliott Hughesa2501992011-08-26 19:39:54 -0700687 JniAbort();
688 return;
689 }
690 }
691
692 /*
693 * Verify that "bytes" points to valid "modified UTF-8" data.
694 */
695 void checkUtfString(const char* bytes, bool nullable) {
696 if (bytes == NULL) {
697 if (!nullable) {
698 LOG(ERROR) << "JNI ERROR: non-nullable const char* was NULL";
699 JniAbort();
700 return;
701 }
702 return;
703 }
704
705 const char* errorKind = NULL;
706 uint8_t utf8 = checkUtfBytes(bytes, &errorKind);
707 if (errorKind != NULL) {
708 LOG(ERROR) << "JNI ERROR: input is not valid UTF-8: illegal " << errorKind << " byte " << StringPrintf("%#x", utf8);
709 LOG(ERROR) << " string: '" << bytes << "'";
710 JniAbort();
711 return;
712 }
713 }
714
715 enum InstanceKind {
716 kClass,
717 kDirectByteBuffer,
718 kString,
719 kThrowable,
720 };
721
722 /*
723 * Verify that "jobj" is a valid non-NULL object reference, and points to
724 * an instance of expectedClass.
725 *
726 * Because we're looking at an object on the GC heap, we have to switch
727 * to "running" mode before doing the checks.
728 */
729 void checkInstance(InstanceKind kind, jobject java_object) {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700730 const char* what = NULL;
Elliott Hughesa2501992011-08-26 19:39:54 -0700731 switch (kind) {
732 case kClass:
733 what = "jclass";
734 break;
735 case kDirectByteBuffer:
736 what = "direct ByteBuffer";
737 break;
738 case kString:
739 what = "jstring";
740 break;
741 case kThrowable:
742 what = "jthrowable";
743 break;
744 default:
745 CHECK(false) << static_cast<int>(kind);
746 }
747
748 if (java_object == NULL) {
749 LOG(ERROR) << "JNI ERROR: received null " << what;
750 JniAbort();
751 return;
752 }
753
754 ScopedJniThreadState ts(mEnv);
755 Object* obj = Decode<Object*>(ts, java_object);
756 if (!Heap::IsHeapAddress(obj)) {
757 LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
758 JniAbort();
759 return;
760 }
761
762 bool okay = true;
763 switch (kind) {
764 case kClass:
765 okay = obj->IsClass();
766 break;
767 case kDirectByteBuffer:
768 // TODO
769 break;
770 case kString:
771 okay = obj->IsString();
772 break;
773 case kThrowable:
774 // TODO
775 break;
776 }
777 if (!okay) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700778 LOG(ERROR) << "JNI ERROR: " << what << " has wrong type: " << PrettyTypeOf(obj);
Elliott Hughesa2501992011-08-26 19:39:54 -0700779 JniAbort();
780 }
781 }
782
783 static uint8_t checkUtfBytes(const char* bytes, const char** errorKind) {
784 while (*bytes != '\0') {
785 uint8_t utf8 = *(bytes++);
786 // Switch on the high four bits.
787 switch (utf8 >> 4) {
788 case 0x00:
789 case 0x01:
790 case 0x02:
791 case 0x03:
792 case 0x04:
793 case 0x05:
794 case 0x06:
795 case 0x07:
796 // Bit pattern 0xxx. No need for any extra bytes.
797 break;
798 case 0x08:
799 case 0x09:
800 case 0x0a:
801 case 0x0b:
802 case 0x0f:
803 /*
804 * Bit pattern 10xx or 1111, which are illegal start bytes.
805 * Note: 1111 is valid for normal UTF-8, but not the
806 * modified UTF-8 used here.
807 */
808 *errorKind = "start";
809 return utf8;
810 case 0x0e:
811 // Bit pattern 1110, so there are two additional bytes.
812 utf8 = *(bytes++);
813 if ((utf8 & 0xc0) != 0x80) {
814 *errorKind = "continuation";
815 return utf8;
816 }
817 // Fall through to take care of the final byte.
818 case 0x0c:
819 case 0x0d:
820 // Bit pattern 110x, so there is one additional byte.
821 utf8 = *(bytes++);
822 if ((utf8 & 0xc0) != 0x80) {
823 *errorKind = "continuation";
824 return utf8;
825 }
826 break;
827 }
828 }
829 return 0;
830 }
831
832 void JniAbort() {
833 ::art::JniAbort(mFunctionName);
834 }
835
836 JNIEnvExt* mEnv;
Elliott Hughesa0957642011-09-02 14:27:33 -0700837 JavaVMExt* mVm;
Elliott Hughesa2501992011-08-26 19:39:54 -0700838 const char* mFunctionName;
839 int mFlags;
840 bool mHasMethod;
841 size_t mIndent;
842
843 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
844};
845
846#define CHECK_JNI_ENTRY(flags, types, args...) \
847 ScopedCheck sc(env, flags, __FUNCTION__); \
848 sc.check(true, types, ##args)
849
850#define CHECK_JNI_EXIT(type, exp) ({ \
851 typeof (exp) _rc = (exp); \
852 sc.check(false, type, _rc); \
853 _rc; })
854#define CHECK_JNI_EXIT_VOID() \
855 sc.check(false, "V")
856
857/*
858 * ===========================================================================
859 * Guarded arrays
860 * ===========================================================================
861 */
862
863#define kGuardLen 512 /* must be multiple of 2 */
864#define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */
865#define kGuardMagic 0xffd5aa96
866
867/* this gets tucked in at the start of the buffer; struct size must be even */
868struct GuardedCopy {
869 uint32_t magic;
870 uLong adler;
871 size_t originalLen;
872 const void* originalPtr;
873
874 /* find the GuardedCopy given the pointer into the "live" data */
875 static inline const GuardedCopy* fromData(const void* dataBuf) {
876 return reinterpret_cast<const GuardedCopy*>(actualBuffer(dataBuf));
877 }
878
879 /*
880 * Create an over-sized buffer to hold the contents of "buf". Copy it in,
881 * filling in the area around it with guard data.
882 *
883 * We use a 16-bit pattern to make a rogue memset less likely to elude us.
884 */
885 static void* create(const void* buf, size_t len, bool modOkay) {
886 size_t newLen = actualLength(len);
887 uint8_t* newBuf = debugAlloc(newLen);
888
889 /* fill it in with a pattern */
890 uint16_t* pat = (uint16_t*) newBuf;
891 for (size_t i = 0; i < newLen / 2; i++) {
892 *pat++ = kGuardPattern;
893 }
894
895 /* copy the data in; note "len" could be zero */
896 memcpy(newBuf + kGuardLen / 2, buf, len);
897
898 /* if modification is not expected, grab a checksum */
899 uLong adler = 0;
900 if (!modOkay) {
901 adler = adler32(0L, Z_NULL, 0);
902 adler = adler32(adler, (const Bytef*)buf, len);
903 *(uLong*)newBuf = adler;
904 }
905
906 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
907 pExtra->magic = kGuardMagic;
908 pExtra->adler = adler;
909 pExtra->originalPtr = buf;
910 pExtra->originalLen = len;
911
912 return newBuf + kGuardLen / 2;
913 }
914
915 /*
916 * Free up the guard buffer, scrub it, and return the original pointer.
917 */
918 static void* destroy(void* dataBuf) {
919 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf);
920 void* originalPtr = (void*) pExtra->originalPtr;
921 size_t len = pExtra->originalLen;
922 debugFree(dataBuf, len);
923 return originalPtr;
924 }
925
926 /*
927 * Verify the guard area and, if "modOkay" is false, that the data itself
928 * has not been altered.
929 *
930 * The caller has already checked that "dataBuf" is non-NULL.
931 */
932 static void check(const char* functionName, const void* dataBuf, bool modOkay) {
933 static const uint32_t kMagicCmp = kGuardMagic;
934 const uint8_t* fullBuf = actualBuffer(dataBuf);
935 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf);
936
937 /*
938 * Before we do anything with "pExtra", check the magic number. We
939 * do the check with memcmp rather than "==" in case the pointer is
940 * unaligned. If it points to completely bogus memory we're going
941 * to crash, but there's no easy way around that.
942 */
943 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
944 uint8_t buf[4];
945 memcpy(buf, &pExtra->magic, 4);
946 LOG(ERROR) << StringPrintf("JNI: guard magic does not match "
947 "(found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
948 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
949 JniAbort(functionName);
950 }
951
952 size_t len = pExtra->originalLen;
953
954 /* check bottom half of guard; skip over optional checksum storage */
955 const uint16_t* pat = (uint16_t*) fullBuf;
956 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
957 if (pat[i] != kGuardPattern) {
958 LOG(ERROR) << "JNI: guard pattern(1) disturbed at " << (void*) fullBuf << " + " << (i*2);
959 JniAbort(functionName);
960 }
961 }
962
963 int offset = kGuardLen / 2 + len;
964 if (offset & 0x01) {
965 /* odd byte; expected value depends on endian-ness of host */
966 const uint16_t patSample = kGuardPattern;
967 if (fullBuf[offset] != ((const uint8_t*) &patSample)[1]) {
968 LOG(ERROR) << "JNI: guard pattern disturbed in odd byte after "
969 << (void*) fullBuf << " (+" << offset << ") "
970 << StringPrintf("0x%02x 0x%02x", fullBuf[offset], ((const uint8_t*) &patSample)[1]);
971 JniAbort(functionName);
972 }
973 offset++;
974 }
975
976 /* check top half of guard */
977 pat = (uint16_t*) (fullBuf + offset);
978 for (size_t i = 0; i < kGuardLen / 4; i++) {
979 if (pat[i] != kGuardPattern) {
980 LOG(ERROR) << "JNI: guard pattern(2) disturbed at " << (void*) fullBuf << " + " << (offset + i*2);
981 JniAbort(functionName);
982 }
983 }
984
985 /*
986 * If modification is not expected, verify checksum. Strictly speaking
987 * this is wrong: if we told the client that we made a copy, there's no
988 * reason they can't alter the buffer.
989 */
990 if (!modOkay) {
991 uLong adler = adler32(0L, Z_NULL, 0);
992 adler = adler32(adler, (const Bytef*)dataBuf, len);
993 if (pExtra->adler != adler) {
994 LOG(ERROR) << StringPrintf("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", pExtra->adler, adler, dataBuf);
995 JniAbort(functionName);
996 }
997 }
998 }
999
1000 private:
1001 static uint8_t* debugAlloc(size_t len) {
1002 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1003 if (result == MAP_FAILED) {
1004 PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed";
1005 }
1006 return reinterpret_cast<uint8_t*>(result);
1007 }
1008
1009 static void debugFree(void* dataBuf, size_t len) {
1010 uint8_t* fullBuf = actualBuffer(dataBuf);
1011 size_t totalByteCount = actualLength(len);
1012 // TODO: we could mprotect instead, and keep the allocation around for a while.
1013 // This would be even more expensive, but it might catch more errors.
1014 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
1015 // LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
1016 // }
1017 if (munmap(fullBuf, totalByteCount) != 0) {
1018 PLOG(FATAL) << "munmap(" << (void*) fullBuf << ", " << totalByteCount << ") failed";
1019 }
1020 }
1021
1022 static const uint8_t* actualBuffer(const void* dataBuf) {
1023 return reinterpret_cast<const uint8_t*>(dataBuf) - kGuardLen / 2;
1024 }
1025
1026 static uint8_t* actualBuffer(void* dataBuf) {
1027 return reinterpret_cast<uint8_t*>(dataBuf) - kGuardLen / 2;
1028 }
1029
1030 // Underlying length of a user allocation of 'length' bytes.
1031 static size_t actualLength(size_t length) {
1032 return (length + kGuardLen + 1) & ~0x01;
1033 }
1034};
1035
1036/*
1037 * Create a guarded copy of a primitive array. Modifications to the copied
1038 * data are allowed. Returns a pointer to the copied data.
1039 */
1040void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* isCopy) {
1041 ScopedJniThreadState ts(env);
1042
1043 Array* a = Decode<Array*>(ts, java_array);
1044 size_t byte_count = a->GetLength() * a->GetClass()->GetComponentSize();
Elliott Hughesbf86d042011-08-31 17:53:14 -07001045 void* result = GuardedCopy::create(a->GetRawData(), byte_count, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001046 if (isCopy != NULL) {
1047 *isCopy = JNI_TRUE;
1048 }
1049 return result;
1050}
1051
1052/*
1053 * Perform the array "release" operation, which may or may not copy data
1054 * back into the VM, and may or may not release the underlying storage.
1055 */
1056void ReleaseGuardedPACopy(JNIEnv* env, jarray java_array, void* dataBuf, int mode) {
1057 if (reinterpret_cast<uintptr_t>(dataBuf) == kNoCopyMagic) {
1058 return;
1059 }
1060
1061 ScopedJniThreadState ts(env);
1062 Array* a = Decode<Array*>(ts, java_array);
1063
1064 GuardedCopy::check(__FUNCTION__, dataBuf, true);
1065
1066 if (mode != JNI_ABORT) {
1067 size_t len = GuardedCopy::fromData(dataBuf)->originalLen;
Elliott Hughesbf86d042011-08-31 17:53:14 -07001068 memcpy(a->GetRawData(), dataBuf, len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001069 }
1070 if (mode != JNI_COMMIT) {
1071 GuardedCopy::destroy(dataBuf);
1072 }
1073}
1074
1075/*
1076 * ===========================================================================
1077 * JNI functions
1078 * ===========================================================================
1079 */
1080
1081class CheckJNI {
1082 public:
1083 static jint GetVersion(JNIEnv* env) {
1084 CHECK_JNI_ENTRY(kFlag_Default, "E", env);
1085 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
1086 }
1087
1088 static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf, jsize bufLen) {
1089 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
1090 sc.checkClassName(name);
1091 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
1092 }
1093
1094 static jclass FindClass(JNIEnv* env, const char* name) {
1095 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
1096 sc.checkClassName(name);
1097 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
1098 }
1099
1100 static jclass GetSuperclass(JNIEnv* env, jclass clazz) {
1101 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1102 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz));
1103 }
1104
1105 static jboolean IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) {
1106 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2);
1107 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2));
1108 }
1109
1110 static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
1111 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
1112 // TODO: check that 'field' is a java.lang.reflect.Method.
1113 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
1114 }
1115
1116 static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
1117 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
1118 // TODO: check that 'field' is a java.lang.reflect.Field.
1119 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
1120 }
1121
1122 static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
1123 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, mid, isStatic);
1124 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, mid, isStatic));
1125 }
1126
1127 static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
1128 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fid, isStatic);
1129 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fid, isStatic));
1130 }
1131
1132 static jint Throw(JNIEnv* env, jthrowable obj) {
1133 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1134 // TODO: check that 'obj' is a java.lang.Throwable.
1135 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
1136 }
1137
1138 static jint ThrowNew(JNIEnv* env, jclass clazz, const char* message) {
1139 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message);
1140 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message));
1141 }
1142
1143 static jthrowable ExceptionOccurred(JNIEnv* env) {
1144 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1145 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
1146 }
1147
1148 static void ExceptionDescribe(JNIEnv* env) {
1149 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1150 baseEnv(env)->ExceptionDescribe(env);
1151 CHECK_JNI_EXIT_VOID();
1152 }
1153
1154 static void ExceptionClear(JNIEnv* env) {
1155 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1156 baseEnv(env)->ExceptionClear(env);
1157 CHECK_JNI_EXIT_VOID();
1158 }
1159
1160 static void FatalError(JNIEnv* env, const char* msg) {
1161 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
1162 baseEnv(env)->FatalError(env, msg);
1163 CHECK_JNI_EXIT_VOID();
1164 }
1165
1166 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1167 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
1168 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
1169 }
1170
1171 static jobject PopLocalFrame(JNIEnv* env, jobject res) {
1172 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
1173 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
1174 }
1175
1176 static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
1177 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1178 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
1179 }
1180
1181 static jobject NewLocalRef(JNIEnv* env, jobject ref) {
1182 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
1183 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
1184 }
1185
1186 static void DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
1187 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
1188 if (globalRef != NULL && GetIndirectRefKind(globalRef) != kGlobal) {
1189 LOG(ERROR) << "JNI ERROR: DeleteGlobalRef on " << GetIndirectRefKind(globalRef) << ": " << globalRef;
1190 JniAbort(__FUNCTION__);
1191 } else {
1192 baseEnv(env)->DeleteGlobalRef(env, globalRef);
1193 CHECK_JNI_EXIT_VOID();
1194 }
1195 }
1196
1197 static void DeleteWeakGlobalRef(JNIEnv* env, jweak weakGlobalRef) {
1198 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, weakGlobalRef);
1199 if (weakGlobalRef != NULL && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) {
1200 LOG(ERROR) << "JNI ERROR: DeleteWeakGlobalRef on " << GetIndirectRefKind(weakGlobalRef) << ": " << weakGlobalRef;
1201 JniAbort(__FUNCTION__);
1202 } else {
1203 baseEnv(env)->DeleteWeakGlobalRef(env, weakGlobalRef);
1204 CHECK_JNI_EXIT_VOID();
1205 }
1206 }
1207
1208 static void DeleteLocalRef(JNIEnv* env, jobject localRef) {
1209 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
1210 if (localRef != NULL && GetIndirectRefKind(localRef) != kLocal) {
1211 LOG(ERROR) << "JNI ERROR: DeleteLocalRef on " << GetIndirectRefKind(localRef) << ": " << localRef;
1212 JniAbort(__FUNCTION__);
1213 } else {
1214 baseEnv(env)->DeleteLocalRef(env, localRef);
1215 CHECK_JNI_EXIT_VOID();
1216 }
1217 }
1218
1219 static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
1220 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
1221 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
1222 }
1223
1224 static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
1225 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
1226 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
1227 }
1228
1229 static jobject AllocObject(JNIEnv* env, jclass clazz) {
1230 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1231 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz));
1232 }
1233
1234 static jobject NewObject(JNIEnv* env, jclass clazz, jmethodID mid, ...) {
1235 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1236 va_list args;
1237 va_start(args, mid);
1238 jobject result = baseEnv(env)->NewObjectV(env, clazz, mid, args);
1239 va_end(args);
1240 return CHECK_JNI_EXIT("L", result);
1241 }
1242
1243 static jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) {
1244 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1245 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, mid, args));
1246 }
1247
1248 static jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) {
1249 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1250 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, mid, args));
1251 }
1252
1253 static jclass GetObjectClass(JNIEnv* env, jobject obj) {
1254 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1255 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
1256 }
1257
1258 static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
1259 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz);
1260 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz));
1261 }
1262
1263 static jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1264 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1265 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig));
1266 }
1267
1268 static jfieldID GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1269 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1270 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig));
1271 }
1272
1273 static jmethodID GetStaticMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1274 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1275 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig));
1276 }
1277
1278 static jfieldID GetStaticFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1279 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1280 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig));
1281 }
1282
1283#define FIELD_ACCESSORS(_ctype, _jname, _type) \
1284 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid) { \
1285 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fid); \
1286 sc.checkStaticFieldID(clazz, fid); \
1287 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fid)); \
1288 } \
1289 static _ctype Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid) { \
1290 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fid); \
1291 sc.checkInstanceFieldID(obj, fid); \
1292 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fid)); \
1293 } \
1294 static void SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid, _ctype value) { \
1295 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fid, value); \
1296 sc.checkStaticFieldID(clazz, fid); \
1297 /* "value" arg only used when type == ref */ \
1298 sc.checkFieldType((jobject)(uint32_t)value, fid, _type[0], true); \
1299 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fid, value); \
1300 CHECK_JNI_EXIT_VOID(); \
1301 } \
1302 static void Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid, _ctype value) { \
1303 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fid, value); \
1304 sc.checkInstanceFieldID(obj, fid); \
1305 /* "value" arg only used when type == ref */ \
1306 sc.checkFieldType((jobject)(uint32_t) value, fid, _type[0], false); \
1307 baseEnv(env)->Set##_jname##Field(env, obj, fid, value); \
1308 CHECK_JNI_EXIT_VOID(); \
1309 }
1310
1311FIELD_ACCESSORS(jobject, Object, "L");
1312FIELD_ACCESSORS(jboolean, Boolean, "Z");
1313FIELD_ACCESSORS(jbyte, Byte, "B");
1314FIELD_ACCESSORS(jchar, Char, "C");
1315FIELD_ACCESSORS(jshort, Short, "S");
1316FIELD_ACCESSORS(jint, Int, "I");
1317FIELD_ACCESSORS(jlong, Long, "J");
1318FIELD_ACCESSORS(jfloat, Float, "F");
1319FIELD_ACCESSORS(jdouble, Double, "D");
1320
1321#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
1322 /* Virtual... */ \
1323 static _ctype Call##_jname##Method(JNIEnv* env, jobject obj, \
1324 jmethodID mid, ...) \
1325 { \
1326 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
1327 sc.checkSig(mid, _retsig, false); \
1328 sc.checkVirtualMethod(obj, mid); \
1329 _retdecl; \
1330 va_list args; \
1331 va_start(args, mid); \
1332 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args); \
1333 va_end(args); \
1334 _retok; \
1335 } \
1336 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1337 jmethodID mid, va_list args) \
1338 { \
1339 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
1340 sc.checkSig(mid, _retsig, false); \
1341 sc.checkVirtualMethod(obj, mid); \
1342 _retdecl; \
1343 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args); \
1344 _retok; \
1345 } \
1346 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1347 jmethodID mid, jvalue* args) \
1348 { \
1349 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
1350 sc.checkSig(mid, _retsig, false); \
1351 sc.checkVirtualMethod(obj, mid); \
1352 _retdecl; \
1353 _retasgn baseEnv(env)->Call##_jname##MethodA(env, obj, mid, args); \
1354 _retok; \
1355 } \
1356 /* Non-virtual... */ \
1357 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, \
1358 jobject obj, jclass clazz, jmethodID mid, ...) \
1359 { \
1360 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
1361 sc.checkSig(mid, _retsig, false); \
1362 sc.checkVirtualMethod(obj, mid); \
1363 _retdecl; \
1364 va_list args; \
1365 va_start(args, mid); \
1366 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args); \
1367 va_end(args); \
1368 _retok; \
1369 } \
1370 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, \
1371 jobject obj, jclass clazz, jmethodID mid, va_list args) \
1372 { \
1373 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
1374 sc.checkSig(mid, _retsig, false); \
1375 sc.checkVirtualMethod(obj, mid); \
1376 _retdecl; \
1377 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args); \
1378 _retok; \
1379 } \
1380 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, \
1381 jobject obj, jclass clazz, jmethodID mid, jvalue* args) \
1382 { \
1383 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
1384 sc.checkSig(mid, _retsig, false); \
1385 sc.checkVirtualMethod(obj, mid); \
1386 _retdecl; \
1387 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, mid, args); \
1388 _retok; \
1389 } \
1390 /* Static... */ \
1391 static _ctype CallStatic##_jname##Method(JNIEnv* env, \
1392 jclass clazz, jmethodID mid, ...) \
1393 { \
1394 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
1395 sc.checkSig(mid, _retsig, true); \
1396 sc.checkStaticMethod(clazz, mid); \
1397 _retdecl; \
1398 va_list args; \
1399 va_start(args, mid); \
1400 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args); \
1401 va_end(args); \
1402 _retok; \
1403 } \
1404 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, \
1405 jclass clazz, jmethodID mid, va_list args) \
1406 { \
1407 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
1408 sc.checkSig(mid, _retsig, true); \
1409 sc.checkStaticMethod(clazz, mid); \
1410 _retdecl; \
1411 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args); \
1412 _retok; \
1413 } \
1414 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, \
1415 jclass clazz, jmethodID mid, jvalue* args) \
1416 { \
1417 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
1418 sc.checkSig(mid, _retsig, true); \
1419 sc.checkStaticMethod(clazz, mid); \
1420 _retdecl; \
1421 _retasgn baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, mid, args); \
1422 _retok; \
1423 }
1424
1425#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
1426#define VOID_RETURN CHECK_JNI_EXIT_VOID()
1427
1428CALL(jobject, Object, Object* result, result=(Object*), NON_VOID_RETURN("L", jobject), "L");
1429CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z");
1430CALL(jbyte, Byte, jbyte result, result=, NON_VOID_RETURN("B", jbyte), "B");
1431CALL(jchar, Char, jchar result, result=, NON_VOID_RETURN("C", jchar), "C");
1432CALL(jshort, Short, jshort result, result=, NON_VOID_RETURN("S", jshort), "S");
1433CALL(jint, Int, jint result, result=, NON_VOID_RETURN("I", jint), "I");
1434CALL(jlong, Long, jlong result, result=, NON_VOID_RETURN("J", jlong), "J");
1435CALL(jfloat, Float, jfloat result, result=, NON_VOID_RETURN("F", jfloat), "F");
1436CALL(jdouble, Double, jdouble result, result=, NON_VOID_RETURN("D", jdouble), "D");
1437CALL(void, Void, , , VOID_RETURN, "V");
1438
1439 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
1440 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
1441 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
1442 }
1443
1444 static jsize GetStringLength(JNIEnv* env, jstring string) {
1445 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1446 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
1447 }
1448
1449 static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1450 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, java_string, isCopy);
1451 const jchar* result = baseEnv(env)->GetStringChars(env, java_string, isCopy);
1452 if (sc.forceCopy() && result != NULL) {
1453 ScopedJniThreadState ts(env);
1454 String* s = Decode<String*>(ts, java_string);
1455 int byteCount = s->GetLength() * 2;
1456 result = (const jchar*) GuardedCopy::create(result, byteCount, false);
1457 if (isCopy != NULL) {
1458 *isCopy = JNI_TRUE;
1459 }
1460 }
1461 return CHECK_JNI_EXIT("p", result);
1462 }
1463
1464 static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
1465 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
1466 sc.checkNonNull(chars);
1467 if (sc.forceCopy()) {
1468 GuardedCopy::check(__FUNCTION__, chars, false);
1469 chars = (const jchar*) GuardedCopy::destroy((jchar*)chars);
1470 }
1471 baseEnv(env)->ReleaseStringChars(env, string, chars);
1472 CHECK_JNI_EXIT_VOID();
1473 }
1474
1475 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
1476 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
1477 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
1478 }
1479
1480 static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
1481 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1482 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
1483 }
1484
1485 static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1486 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1487 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
1488 if (sc.forceCopy() && result != NULL) {
1489 result = (const char*) GuardedCopy::create(result, strlen(result) + 1, false);
1490 if (isCopy != NULL) {
1491 *isCopy = JNI_TRUE;
1492 }
1493 }
1494 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
1495 }
1496
1497 static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
1498 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
1499 if (sc.forceCopy()) {
1500 GuardedCopy::check(__FUNCTION__, utf, false);
1501 utf = (const char*) GuardedCopy::destroy((char*)utf);
1502 }
1503 baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
1504 CHECK_JNI_EXIT_VOID();
1505 }
1506
1507 static jsize GetArrayLength(JNIEnv* env, jarray array) {
1508 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
1509 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
1510 }
1511
1512 static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass elementClass, jobject initialElement) {
1513 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
1514 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
1515 }
1516
1517 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
1518 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
1519 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
1520 }
1521
1522 static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
1523 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
1524 baseEnv(env)->SetObjectArrayElement(env, array, index, value);
1525 CHECK_JNI_EXIT_VOID();
1526 }
1527
1528#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
1529 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
1530 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
1531 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
1532 }
1533NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
1534NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
1535NEW_PRIMITIVE_ARRAY(jcharArray, Char);
1536NEW_PRIMITIVE_ARRAY(jshortArray, Short);
1537NEW_PRIMITIVE_ARRAY(jintArray, Int);
1538NEW_PRIMITIVE_ARRAY(jlongArray, Long);
1539NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
1540NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
1541
1542class ForceCopyGetChecker {
1543public:
1544 ForceCopyGetChecker(ScopedCheck& sc, jboolean* isCopy) {
1545 forceCopy = sc.forceCopy();
1546 noCopy = 0;
1547 if (forceCopy && isCopy != NULL) {
1548 /* capture this before the base call tramples on it */
1549 noCopy = *(uint32_t*) isCopy;
1550 }
1551 }
1552
1553 template<typename ResultT>
1554 ResultT check(JNIEnv* env, jarray array, jboolean* isCopy, ResultT result) {
1555 if (forceCopy && result != NULL) {
1556 if (noCopy != kNoCopyMagic) {
1557 result = reinterpret_cast<ResultT>(CreateGuardedPACopy(env, array, isCopy));
1558 }
1559 }
1560 return result;
1561 }
1562
1563 uint32_t noCopy;
1564 bool forceCopy;
1565};
1566
1567#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1568 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, jboolean* isCopy) { \
1569 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
1570 _ctype* result = ForceCopyGetChecker(sc, isCopy).check(env, array, isCopy, baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy)); \
1571 return CHECK_JNI_EXIT("p", result); \
1572 }
1573
1574#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1575 static void Release##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, _ctype* elems, jint mode) { \
1576 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
1577 sc.checkNonNull(elems); \
1578 if (sc.forceCopy()) { \
1579 ReleaseGuardedPACopy(env, array, elems, mode); \
1580 } \
1581 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
1582 CHECK_JNI_EXIT_VOID(); \
1583 }
1584
1585#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1586 static void Get##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
1587 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1588 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
1589 CHECK_JNI_EXIT_VOID(); \
1590 }
1591
1592#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1593 static void Set##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
1594 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1595 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
1596 CHECK_JNI_EXIT_VOID(); \
1597 }
1598
1599#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
1600 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1601 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1602 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
1603 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
1604
1605/* TODO: verify primitive array type matches call type */
1606PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
1607PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
1608PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
1609PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
1610PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
1611PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
1612PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
1613PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
1614
1615 static jint RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) {
1616 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods);
1617 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods));
1618 }
1619
1620 static jint UnregisterNatives(JNIEnv* env, jclass clazz) {
1621 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1622 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz));
1623 }
1624
1625 static jint MonitorEnter(JNIEnv* env, jobject obj) {
1626 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1627 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
1628 }
1629
1630 static jint MonitorExit(JNIEnv* env, jobject obj) {
1631 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
1632 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
1633 }
1634
1635 static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
1636 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
1637 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
1638 }
1639
1640 static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
1641 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1642 baseEnv(env)->GetStringRegion(env, str, start, len, buf);
1643 CHECK_JNI_EXIT_VOID();
1644 }
1645
1646 static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
1647 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1648 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
1649 CHECK_JNI_EXIT_VOID();
1650 }
1651
1652 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
1653 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
1654 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
1655 if (sc.forceCopy() && result != NULL) {
1656 result = CreateGuardedPACopy(env, array, isCopy);
1657 }
1658 return CHECK_JNI_EXIT("p", result);
1659 }
1660
1661 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
1662 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
1663 sc.checkNonNull(carray);
1664 if (sc.forceCopy()) {
1665 ReleaseGuardedPACopy(env, array, carray, mode);
1666 }
1667 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
1668 CHECK_JNI_EXIT_VOID();
1669 }
1670
1671 static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1672 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, java_string, isCopy);
1673 const jchar* result = baseEnv(env)->GetStringCritical(env, java_string, isCopy);
1674 if (sc.forceCopy() && result != NULL) {
1675 ScopedJniThreadState ts(env);
1676 String* s = Decode<String*>(ts, java_string);
1677 int byteCount = s->GetLength() * 2;
1678 result = (const jchar*) GuardedCopy::create(result, byteCount, false);
1679 if (isCopy != NULL) {
1680 *isCopy = JNI_TRUE;
1681 }
1682 }
1683 return CHECK_JNI_EXIT("p", result);
1684 }
1685
1686 static void ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
1687 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
1688 sc.checkNonNull(carray);
1689 if (sc.forceCopy()) {
1690 GuardedCopy::check(__FUNCTION__, carray, false);
1691 carray = (const jchar*) GuardedCopy::destroy((jchar*)carray);
1692 }
1693 baseEnv(env)->ReleaseStringCritical(env, string, carray);
1694 CHECK_JNI_EXIT_VOID();
1695 }
1696
1697 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
1698 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1699 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
1700 }
1701
1702 static jboolean ExceptionCheck(JNIEnv* env) {
1703 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
1704 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
1705 }
1706
1707 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
1708 // Note: we use "Ep" rather than "EL" because this is the one JNI function
1709 // that it's okay to pass an invalid reference to.
1710 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, obj);
1711 // TODO: proper decoding of jobjectRefType!
1712 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
1713 }
1714
1715 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
1716 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
1717 if (address == NULL) {
1718 LOG(ERROR) << "JNI ERROR: non-nullable address is NULL";
1719 JniAbort(__FUNCTION__);
1720 }
1721 if (capacity <= 0) {
1722 LOG(ERROR) << "JNI ERROR: capacity must be greater than 0: " << capacity;
1723 JniAbort(__FUNCTION__);
1724 }
1725 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
1726 }
1727
1728 static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
1729 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1730 // TODO: check that 'buf' is a java.nio.Buffer.
1731 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
1732 }
1733
1734 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
1735 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1736 // TODO: check that 'buf' is a java.nio.Buffer.
1737 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
1738 }
1739
1740 private:
1741 static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
1742 return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions;
1743 }
1744};
1745
1746const JNINativeInterface gCheckNativeInterface = {
1747 NULL, // reserved0.
1748 NULL, // reserved1.
1749 NULL, // reserved2.
1750 NULL, // reserved3.
1751 CheckJNI::GetVersion,
1752 CheckJNI::DefineClass,
1753 CheckJNI::FindClass,
1754 CheckJNI::FromReflectedMethod,
1755 CheckJNI::FromReflectedField,
1756 CheckJNI::ToReflectedMethod,
1757 CheckJNI::GetSuperclass,
1758 CheckJNI::IsAssignableFrom,
1759 CheckJNI::ToReflectedField,
1760 CheckJNI::Throw,
1761 CheckJNI::ThrowNew,
1762 CheckJNI::ExceptionOccurred,
1763 CheckJNI::ExceptionDescribe,
1764 CheckJNI::ExceptionClear,
1765 CheckJNI::FatalError,
1766 CheckJNI::PushLocalFrame,
1767 CheckJNI::PopLocalFrame,
1768 CheckJNI::NewGlobalRef,
1769 CheckJNI::DeleteGlobalRef,
1770 CheckJNI::DeleteLocalRef,
1771 CheckJNI::IsSameObject,
1772 CheckJNI::NewLocalRef,
1773 CheckJNI::EnsureLocalCapacity,
1774 CheckJNI::AllocObject,
1775 CheckJNI::NewObject,
1776 CheckJNI::NewObjectV,
1777 CheckJNI::NewObjectA,
1778 CheckJNI::GetObjectClass,
1779 CheckJNI::IsInstanceOf,
1780 CheckJNI::GetMethodID,
1781 CheckJNI::CallObjectMethod,
1782 CheckJNI::CallObjectMethodV,
1783 CheckJNI::CallObjectMethodA,
1784 CheckJNI::CallBooleanMethod,
1785 CheckJNI::CallBooleanMethodV,
1786 CheckJNI::CallBooleanMethodA,
1787 CheckJNI::CallByteMethod,
1788 CheckJNI::CallByteMethodV,
1789 CheckJNI::CallByteMethodA,
1790 CheckJNI::CallCharMethod,
1791 CheckJNI::CallCharMethodV,
1792 CheckJNI::CallCharMethodA,
1793 CheckJNI::CallShortMethod,
1794 CheckJNI::CallShortMethodV,
1795 CheckJNI::CallShortMethodA,
1796 CheckJNI::CallIntMethod,
1797 CheckJNI::CallIntMethodV,
1798 CheckJNI::CallIntMethodA,
1799 CheckJNI::CallLongMethod,
1800 CheckJNI::CallLongMethodV,
1801 CheckJNI::CallLongMethodA,
1802 CheckJNI::CallFloatMethod,
1803 CheckJNI::CallFloatMethodV,
1804 CheckJNI::CallFloatMethodA,
1805 CheckJNI::CallDoubleMethod,
1806 CheckJNI::CallDoubleMethodV,
1807 CheckJNI::CallDoubleMethodA,
1808 CheckJNI::CallVoidMethod,
1809 CheckJNI::CallVoidMethodV,
1810 CheckJNI::CallVoidMethodA,
1811 CheckJNI::CallNonvirtualObjectMethod,
1812 CheckJNI::CallNonvirtualObjectMethodV,
1813 CheckJNI::CallNonvirtualObjectMethodA,
1814 CheckJNI::CallNonvirtualBooleanMethod,
1815 CheckJNI::CallNonvirtualBooleanMethodV,
1816 CheckJNI::CallNonvirtualBooleanMethodA,
1817 CheckJNI::CallNonvirtualByteMethod,
1818 CheckJNI::CallNonvirtualByteMethodV,
1819 CheckJNI::CallNonvirtualByteMethodA,
1820 CheckJNI::CallNonvirtualCharMethod,
1821 CheckJNI::CallNonvirtualCharMethodV,
1822 CheckJNI::CallNonvirtualCharMethodA,
1823 CheckJNI::CallNonvirtualShortMethod,
1824 CheckJNI::CallNonvirtualShortMethodV,
1825 CheckJNI::CallNonvirtualShortMethodA,
1826 CheckJNI::CallNonvirtualIntMethod,
1827 CheckJNI::CallNonvirtualIntMethodV,
1828 CheckJNI::CallNonvirtualIntMethodA,
1829 CheckJNI::CallNonvirtualLongMethod,
1830 CheckJNI::CallNonvirtualLongMethodV,
1831 CheckJNI::CallNonvirtualLongMethodA,
1832 CheckJNI::CallNonvirtualFloatMethod,
1833 CheckJNI::CallNonvirtualFloatMethodV,
1834 CheckJNI::CallNonvirtualFloatMethodA,
1835 CheckJNI::CallNonvirtualDoubleMethod,
1836 CheckJNI::CallNonvirtualDoubleMethodV,
1837 CheckJNI::CallNonvirtualDoubleMethodA,
1838 CheckJNI::CallNonvirtualVoidMethod,
1839 CheckJNI::CallNonvirtualVoidMethodV,
1840 CheckJNI::CallNonvirtualVoidMethodA,
1841 CheckJNI::GetFieldID,
1842 CheckJNI::GetObjectField,
1843 CheckJNI::GetBooleanField,
1844 CheckJNI::GetByteField,
1845 CheckJNI::GetCharField,
1846 CheckJNI::GetShortField,
1847 CheckJNI::GetIntField,
1848 CheckJNI::GetLongField,
1849 CheckJNI::GetFloatField,
1850 CheckJNI::GetDoubleField,
1851 CheckJNI::SetObjectField,
1852 CheckJNI::SetBooleanField,
1853 CheckJNI::SetByteField,
1854 CheckJNI::SetCharField,
1855 CheckJNI::SetShortField,
1856 CheckJNI::SetIntField,
1857 CheckJNI::SetLongField,
1858 CheckJNI::SetFloatField,
1859 CheckJNI::SetDoubleField,
1860 CheckJNI::GetStaticMethodID,
1861 CheckJNI::CallStaticObjectMethod,
1862 CheckJNI::CallStaticObjectMethodV,
1863 CheckJNI::CallStaticObjectMethodA,
1864 CheckJNI::CallStaticBooleanMethod,
1865 CheckJNI::CallStaticBooleanMethodV,
1866 CheckJNI::CallStaticBooleanMethodA,
1867 CheckJNI::CallStaticByteMethod,
1868 CheckJNI::CallStaticByteMethodV,
1869 CheckJNI::CallStaticByteMethodA,
1870 CheckJNI::CallStaticCharMethod,
1871 CheckJNI::CallStaticCharMethodV,
1872 CheckJNI::CallStaticCharMethodA,
1873 CheckJNI::CallStaticShortMethod,
1874 CheckJNI::CallStaticShortMethodV,
1875 CheckJNI::CallStaticShortMethodA,
1876 CheckJNI::CallStaticIntMethod,
1877 CheckJNI::CallStaticIntMethodV,
1878 CheckJNI::CallStaticIntMethodA,
1879 CheckJNI::CallStaticLongMethod,
1880 CheckJNI::CallStaticLongMethodV,
1881 CheckJNI::CallStaticLongMethodA,
1882 CheckJNI::CallStaticFloatMethod,
1883 CheckJNI::CallStaticFloatMethodV,
1884 CheckJNI::CallStaticFloatMethodA,
1885 CheckJNI::CallStaticDoubleMethod,
1886 CheckJNI::CallStaticDoubleMethodV,
1887 CheckJNI::CallStaticDoubleMethodA,
1888 CheckJNI::CallStaticVoidMethod,
1889 CheckJNI::CallStaticVoidMethodV,
1890 CheckJNI::CallStaticVoidMethodA,
1891 CheckJNI::GetStaticFieldID,
1892 CheckJNI::GetStaticObjectField,
1893 CheckJNI::GetStaticBooleanField,
1894 CheckJNI::GetStaticByteField,
1895 CheckJNI::GetStaticCharField,
1896 CheckJNI::GetStaticShortField,
1897 CheckJNI::GetStaticIntField,
1898 CheckJNI::GetStaticLongField,
1899 CheckJNI::GetStaticFloatField,
1900 CheckJNI::GetStaticDoubleField,
1901 CheckJNI::SetStaticObjectField,
1902 CheckJNI::SetStaticBooleanField,
1903 CheckJNI::SetStaticByteField,
1904 CheckJNI::SetStaticCharField,
1905 CheckJNI::SetStaticShortField,
1906 CheckJNI::SetStaticIntField,
1907 CheckJNI::SetStaticLongField,
1908 CheckJNI::SetStaticFloatField,
1909 CheckJNI::SetStaticDoubleField,
1910 CheckJNI::NewString,
1911 CheckJNI::GetStringLength,
1912 CheckJNI::GetStringChars,
1913 CheckJNI::ReleaseStringChars,
1914 CheckJNI::NewStringUTF,
1915 CheckJNI::GetStringUTFLength,
1916 CheckJNI::GetStringUTFChars,
1917 CheckJNI::ReleaseStringUTFChars,
1918 CheckJNI::GetArrayLength,
1919 CheckJNI::NewObjectArray,
1920 CheckJNI::GetObjectArrayElement,
1921 CheckJNI::SetObjectArrayElement,
1922 CheckJNI::NewBooleanArray,
1923 CheckJNI::NewByteArray,
1924 CheckJNI::NewCharArray,
1925 CheckJNI::NewShortArray,
1926 CheckJNI::NewIntArray,
1927 CheckJNI::NewLongArray,
1928 CheckJNI::NewFloatArray,
1929 CheckJNI::NewDoubleArray,
1930 CheckJNI::GetBooleanArrayElements,
1931 CheckJNI::GetByteArrayElements,
1932 CheckJNI::GetCharArrayElements,
1933 CheckJNI::GetShortArrayElements,
1934 CheckJNI::GetIntArrayElements,
1935 CheckJNI::GetLongArrayElements,
1936 CheckJNI::GetFloatArrayElements,
1937 CheckJNI::GetDoubleArrayElements,
1938 CheckJNI::ReleaseBooleanArrayElements,
1939 CheckJNI::ReleaseByteArrayElements,
1940 CheckJNI::ReleaseCharArrayElements,
1941 CheckJNI::ReleaseShortArrayElements,
1942 CheckJNI::ReleaseIntArrayElements,
1943 CheckJNI::ReleaseLongArrayElements,
1944 CheckJNI::ReleaseFloatArrayElements,
1945 CheckJNI::ReleaseDoubleArrayElements,
1946 CheckJNI::GetBooleanArrayRegion,
1947 CheckJNI::GetByteArrayRegion,
1948 CheckJNI::GetCharArrayRegion,
1949 CheckJNI::GetShortArrayRegion,
1950 CheckJNI::GetIntArrayRegion,
1951 CheckJNI::GetLongArrayRegion,
1952 CheckJNI::GetFloatArrayRegion,
1953 CheckJNI::GetDoubleArrayRegion,
1954 CheckJNI::SetBooleanArrayRegion,
1955 CheckJNI::SetByteArrayRegion,
1956 CheckJNI::SetCharArrayRegion,
1957 CheckJNI::SetShortArrayRegion,
1958 CheckJNI::SetIntArrayRegion,
1959 CheckJNI::SetLongArrayRegion,
1960 CheckJNI::SetFloatArrayRegion,
1961 CheckJNI::SetDoubleArrayRegion,
1962 CheckJNI::RegisterNatives,
1963 CheckJNI::UnregisterNatives,
1964 CheckJNI::MonitorEnter,
1965 CheckJNI::MonitorExit,
1966 CheckJNI::GetJavaVM,
1967 CheckJNI::GetStringRegion,
1968 CheckJNI::GetStringUTFRegion,
1969 CheckJNI::GetPrimitiveArrayCritical,
1970 CheckJNI::ReleasePrimitiveArrayCritical,
1971 CheckJNI::GetStringCritical,
1972 CheckJNI::ReleaseStringCritical,
1973 CheckJNI::NewWeakGlobalRef,
1974 CheckJNI::DeleteWeakGlobalRef,
1975 CheckJNI::ExceptionCheck,
1976 CheckJNI::NewDirectByteBuffer,
1977 CheckJNI::GetDirectBufferAddress,
1978 CheckJNI::GetDirectBufferCapacity,
1979 CheckJNI::GetObjectRefType,
1980};
1981
1982const JNINativeInterface* GetCheckJniNativeInterface() {
1983 return &gCheckNativeInterface;
1984}
1985
1986class CheckJII {
1987public:
1988 static jint DestroyJavaVM(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07001989 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughesa2501992011-08-26 19:39:54 -07001990 sc.check(true, "v", vm);
1991 return CHECK_JNI_EXIT("I", baseVm(vm)->DestroyJavaVM(vm));
1992 }
1993
1994 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07001995 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughesa2501992011-08-26 19:39:54 -07001996 sc.check(true, "vpp", vm, p_env, thr_args);
1997 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
1998 }
1999
2000 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002001 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughesa2501992011-08-26 19:39:54 -07002002 sc.check(true, "vpp", vm, p_env, thr_args);
2003 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
2004 }
2005
2006 static jint DetachCurrentThread(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002007 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughesa2501992011-08-26 19:39:54 -07002008 sc.check(true, "v", vm);
2009 return CHECK_JNI_EXIT("I", baseVm(vm)->DetachCurrentThread(vm));
2010 }
2011
2012 static jint GetEnv(JavaVM* vm, void** env, jint version) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002013 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughesa2501992011-08-26 19:39:54 -07002014 sc.check(true, "v", vm);
2015 return CHECK_JNI_EXIT("I", baseVm(vm)->GetEnv(vm, env, version));
2016 }
2017
2018 private:
2019 static inline const JNIInvokeInterface* baseVm(JavaVM* vm) {
2020 return reinterpret_cast<JavaVMExt*>(vm)->unchecked_functions;
2021 }
2022};
2023
2024const JNIInvokeInterface gCheckInvokeInterface = {
2025 NULL, // reserved0
2026 NULL, // reserved1
2027 NULL, // reserved2
2028 CheckJII::DestroyJavaVM,
2029 CheckJII::AttachCurrentThread,
2030 CheckJII::DetachCurrentThread,
2031 CheckJII::GetEnv,
2032 CheckJII::AttachCurrentThreadAsDaemon
2033};
2034
2035const JNIInvokeInterface* GetCheckJniInvokeInterface() {
2036 return &gCheckInvokeInterface;
2037}
2038
2039} // namespace art