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