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