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