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