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