blob: b8a492de16ca6b2e9c1a94cf4d42d6c94acd433c [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"
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080024#include "object_utils.h"
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -070025#include "scoped_jni_thread_state.h"
Elliott Hughesb3bd5f02012-03-08 21:05:27 -080026#include "space.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070027#include "thread.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070028#include "runtime.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070029
Elliott Hughese6087632011-09-26 12:18:25 -070030#define LIBCORE_CPP_JNI_HELPERS
31#include <JNIHelp.h> // from libcore
32#undef LIBCORE_CPP_JNI_HELPERS
33
Elliott Hughesa2501992011-08-26 19:39:54 -070034namespace art {
35
36void JniAbort(const char* jni_function_name) {
Elliott Hughesa0957642011-09-02 14:27:33 -070037 Thread* self = Thread::Current();
Elliott Hughesd07986f2011-12-06 18:27:45 -080038 Method* current_method = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -070039
Elliott Hughes3b6baaa2011-10-14 19:13:56 -070040 std::ostringstream os;
Elliott Hughese6087632011-09-26 12:18:25 -070041 os << "Aborting because JNI app bug detected (see above for details)";
Elliott Hughesa2501992011-08-26 19:39:54 -070042
43 if (jni_function_name != NULL) {
44 os << "\n in call to " << jni_function_name;
45 }
Elliott Hughesa0957642011-09-02 14:27:33 -070046 // TODO: is this useful given that we're about to dump the calling thread's stack?
47 if (current_method != NULL) {
48 os << "\n from " << PrettyMethod(current_method);
49 }
50 os << "\n";
51 self->Dump(os);
Elliott Hughesa2501992011-08-26 19:39:54 -070052
53 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
54 if (vm->check_jni_abort_hook != NULL) {
55 vm->check_jni_abort_hook(os.str());
56 } else {
57 LOG(FATAL) << os.str();
58 }
59}
60
61/*
62 * ===========================================================================
63 * JNI function helpers
64 * ===========================================================================
65 */
66
Ian Rogers959f8ed2012-02-07 16:33:37 -080067static bool IsSirtLocalRef(JNIEnv* env, jobject localRef) {
68 return GetIndirectRefKind(localRef) == kSirtOrInvalid &&
69 reinterpret_cast<JNIEnvExt*>(env)->self->SirtContains(localRef);
70}
71
Elliott Hughesa2501992011-08-26 19:39:54 -070072template<typename T>
73T Decode(ScopedJniThreadState& ts, jobject obj) {
74 return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
75}
76
Elliott Hughesa2501992011-08-26 19:39:54 -070077/*
78 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
79 * The code deliberately uses an invalid sequence of operations, so we
80 * need to pass it through unmodified. Review that code before making
81 * any changes here.
82 */
83#define kNoCopyMagic 0xd5aab57f
84
85/*
86 * Flags passed into ScopedCheck.
87 */
88#define kFlag_Default 0x0000
89
90#define kFlag_CritBad 0x0000 /* calling while in critical is bad */
91#define kFlag_CritOkay 0x0001 /* ...okay */
92#define kFlag_CritGet 0x0002 /* this is a critical "get" */
93#define kFlag_CritRelease 0x0003 /* this is a critical "release" */
94#define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */
95
96#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */
97#define kFlag_ExcepOkay 0x0004 /* ...okay */
98
99#define kFlag_Release 0x0010 /* are we in a non-critical release function? */
100#define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */
101
102#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */
103
Elliott Hughes485cac42011-12-09 17:49:35 -0800104#define kFlag_ForceTrace 0x80000000 // Add this to a JNI function's flags if you want to trace every call.
105
Elliott Hughesa0957642011-09-02 14:27:33 -0700106static const char* gBuiltInPrefixes[] = {
107 "Landroid/",
108 "Lcom/android/",
109 "Lcom/google/android/",
110 "Ldalvik/",
111 "Ljava/",
112 "Ljavax/",
113 "Llibcore/",
114 "Lorg/apache/harmony/",
115 NULL
116};
117
118bool ShouldTrace(JavaVMExt* vm, const Method* method) {
119 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
120 // when a native method that matches the -Xjnitrace argument calls a JNI function
121 // such as NewByteArray.
122 // If -verbose:third-party-jni is on, we want to log any JNI function calls
123 // made by a third-party native method.
Elliott Hughesf1a5adc2012-02-10 18:09:35 -0800124 std::string className(MethodHelper(method).GetDeclaringClassDescriptor());
125 if (!vm->trace.empty() && className.find(vm->trace) != std::string::npos) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700126 return true;
127 }
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800128 if (VLOG_IS_ON(third_party_jni)) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700129 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
130 // like part of Android.
Elliott Hughesa0957642011-09-02 14:27:33 -0700131 for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) {
Elliott Hughesf1a5adc2012-02-10 18:09:35 -0800132 if (StartsWith(className, gBuiltInPrefixes[i])) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700133 return false;
134 }
135 }
136 return true;
137 }
138 return false;
139}
140
Elliott Hughesa2501992011-08-26 19:39:54 -0700141class ScopedCheck {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800142 public:
Elliott Hughesa2501992011-08-26 19:39:54 -0700143 // For JNIEnv* functions.
144 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700145 Init(env, reinterpret_cast<JNIEnvExt*>(env)->vm, flags, functionName, true);
146 CheckThread(flags);
Elliott Hughesa2501992011-08-26 19:39:54 -0700147 }
148
149 // For JavaVM* functions.
Elliott Hughesa0957642011-09-02 14:27:33 -0700150 explicit ScopedCheck(JavaVM* vm, bool hasMethod, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700151 Init(NULL, vm, kFlag_Invocation, functionName, hasMethod);
Elliott Hughesa2501992011-08-26 19:39:54 -0700152 }
153
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700154 bool ForceCopy() {
Elliott Hughesa2501992011-08-26 19:39:54 -0700155 return Runtime::Current()->GetJavaVM()->force_copy;
156 }
157
158 /*
159 * In some circumstances the VM will screen class names, but it doesn't
160 * for class lookup. When things get bounced through a class loader, they
161 * can actually get normalized a couple of times; as a result, passing in
162 * a class name like "java.lang.Thread" instead of "java/lang/Thread" will
163 * work in some circumstances.
164 *
165 * This is incorrect and could cause strange behavior or compatibility
166 * problems, so we want to screen that out here.
167 *
168 * We expect "fully-qualified" class names, like "java/lang/Thread" or
169 * "[Ljava/lang/Object;".
170 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700171 void CheckClassName(const char* className) {
Elliott Hughes906e6852011-10-28 14:52:10 -0700172 if (!IsValidJniClassName(className)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700173 LOG(ERROR) << "JNI ERROR: illegal class name '" << className << "' (" << function_name_ << ")\n"
Elliott Hughesa2501992011-08-26 19:39:54 -0700174 << " (should be of the form 'java/lang/String', [Ljava/lang/String;' or '[[B')\n";
175 JniAbort();
176 }
177 }
178
179 /*
180 * Verify that the field is of the appropriate type. If the field has an
181 * object type, "java_object" is the object we're trying to assign into it.
182 *
183 * Works for both static and instance fields.
184 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700185 void CheckFieldType(jobject java_object, jfieldID fid, char prim, bool isStatic) {
186 ScopedJniThreadState ts(env_);
187 Field* f = CheckFieldID(fid);
188 if (f == NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700189 return;
190 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800191 Class* field_type = FieldHelper(f).GetType();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700192 if (!field_type->IsPrimitive()) {
193 if (java_object != NULL) {
194 Object* obj = Decode<Object*>(ts, java_object);
195 /*
196 * If java_object is a weak global ref whose referent has been cleared,
197 * obj will be NULL. Otherwise, obj should always be non-NULL
198 * and valid.
199 */
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800200 if (obj != NULL && !Runtime::Current()->GetHeap()->IsHeapAddress(obj)) {
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700201 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
Elliott Hughesa2501992011-08-26 19:39:54 -0700202 JniAbort();
203 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700204 } else {
Brian Carlstrom16192862011-09-12 17:50:06 -0700205 if (!obj->InstanceOf(field_type)) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700206 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << PrettyTypeOf(obj);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700207 JniAbort();
208 return;
209 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700210 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700211 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700212 } else if (field_type != Runtime::Current()->GetClassLinker()->FindPrimitiveClass(prim)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700213 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << prim;
214 JniAbort();
215 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700216 }
217
218 if (isStatic && !f->IsStatic()) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700219 if (isStatic) {
220 LOG(ERROR) << "JNI ERROR: accessing non-static field " << PrettyField(f) << " as static";
221 } else {
222 LOG(ERROR) << "JNI ERROR: accessing static field " << PrettyField(f) << " as non-static";
223 }
224 JniAbort();
225 return;
226 }
227 }
228
229 /*
230 * Verify that this instance field ID is valid for this object.
231 *
232 * Assumes "jobj" has already been validated.
233 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700234 void CheckInstanceFieldID(jobject java_object, jfieldID fid) {
235 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700236
237 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800238 if (o == NULL || !Runtime::Current()->GetHeap()->IsHeapAddress(o)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700239 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
240 JniAbort();
241 return;
242 }
243
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700244 Field* f = CheckFieldID(fid);
245 if (f == NULL) {
246 return;
247 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700248 Class* c = o->GetClass();
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800249 FieldHelper fh(f);
250 if (c->FindInstanceField(fh.GetName(), fh.GetTypeDescriptor()) == NULL) {
Elliott Hughes906e6852011-10-28 14:52:10 -0700251 LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f)
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700252 << " not valid for an object of class " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700253 JniAbort();
254 }
255 }
256
257 /*
258 * Verify that the pointer value is non-NULL.
259 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700260 void CheckNonNull(const void* ptr) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700261 if (ptr == NULL) {
262 LOG(ERROR) << "JNI ERROR: invalid null pointer";
263 JniAbort();
264 }
265 }
266
267 /*
268 * Verify that the method's return type matches the type of call.
269 * 'expectedType' will be "L" for all objects, including arrays.
270 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700271 void CheckSig(jmethodID mid, const char* expectedType, bool isStatic) {
272 ScopedJniThreadState ts(env_);
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800273 Method* m = CheckMethodID(mid);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700274 if (m == NULL) {
275 return;
276 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800277 if (*expectedType != MethodHelper(m).GetShorty()[0]) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700278 LOG(ERROR) << "JNI ERROR: the return type of " << function_name_ << " does not match "
279 << PrettyMethod(m);
Elliott Hughesa2501992011-08-26 19:39:54 -0700280 JniAbort();
281 } else if (isStatic && !m->IsStatic()) {
282 if (isStatic) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700283 LOG(ERROR) << "JNI ERROR: calling non-static method "
284 << PrettyMethod(m) << " with " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700285 } else {
Elliott Hughes726079d2011-10-07 18:43:44 -0700286 LOG(ERROR) << "JNI ERROR: calling static method "
287 << PrettyMethod(m) << " with non-static " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700288 }
289 JniAbort();
290 }
291 }
292
293 /*
294 * Verify that this static field ID is valid for this class.
295 *
296 * Assumes "java_class" has already been validated.
297 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700298 void CheckStaticFieldID(jclass java_class, jfieldID fid) {
299 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700300 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700301 const Field* f = CheckFieldID(fid);
302 if (f == NULL) {
303 return;
304 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700305 if (f->GetDeclaringClass() != c) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700306 LOG(ERROR) << "JNI ERROR: static jfieldID " << fid << " not valid for class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700307 JniAbort();
308 }
309 }
310
311 /*
312 * Verify that "mid" is appropriate for "clazz".
313 *
314 * A mismatch isn't dangerous, because the jmethodID defines the class. In
315 * fact, jclazz is unused in the implementation. It's best if we don't
316 * allow bad code in the system though.
317 *
318 * Instances of "jclazz" must be instances of the method's declaring class.
319 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700320 void CheckStaticMethod(jclass java_class, jmethodID mid) {
321 ScopedJniThreadState ts(env_);
322 const Method* m = CheckMethodID(mid);
323 if (m == NULL) {
324 return;
325 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700326 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughesa2501992011-08-26 19:39:54 -0700327 if (!c->IsAssignableFrom(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700328 LOG(ERROR) << "JNI ERROR: can't call static " << PrettyMethod(m) << " on class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700329 JniAbort();
330 }
331 }
332
333 /*
334 * Verify that "mid" is appropriate for "jobj".
335 *
336 * Make sure the object is an instance of the method's declaring class.
337 * (Note the mid might point to a declaration in an interface; this
338 * will be handled automatically by the instanceof check.)
339 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700340 void CheckVirtualMethod(jobject java_object, jmethodID mid) {
341 ScopedJniThreadState ts(env_);
342 const Method* m = CheckMethodID(mid);
343 if (m == NULL) {
344 return;
345 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700346 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesa2501992011-08-26 19:39:54 -0700347 if (!o->InstanceOf(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700348 LOG(ERROR) << "JNI ERROR: can't call " << PrettyMethod(m) << " on instance of " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700349 JniAbort();
350 }
351 }
352
353 /**
354 * The format string is a sequence of the following characters,
355 * and must be followed by arguments of the corresponding types
356 * in the same order.
357 *
358 * Java primitive types:
359 * B - jbyte
360 * C - jchar
361 * D - jdouble
362 * F - jfloat
363 * I - jint
364 * J - jlong
365 * S - jshort
366 * Z - jboolean (shown as true and false)
367 * V - void
368 *
369 * Java reference types:
370 * L - jobject
371 * a - jarray
372 * c - jclass
373 * s - jstring
374 *
375 * JNI types:
376 * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
377 * f - jfieldID
378 * m - jmethodID
379 * p - void*
380 * r - jint (for release mode arguments)
Elliott Hughes78090d12011-10-07 14:31:47 -0700381 * u - const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700382 * z - jsize (for lengths; use i if negative values are okay)
383 * v - JavaVM*
384 * E - JNIEnv*
385 * . - no argument; just print "..." (used for varargs JNI calls)
386 *
387 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
388 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700389 void Check(bool entry, const char* fmt0, ...) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700390 va_list ap;
391
Elliott Hughesa0957642011-09-02 14:27:33 -0700392 const Method* traceMethod = NULL;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800393 if ((!vm_->trace.empty() || VLOG_IS_ON(third_party_jni)) && has_method_) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700394 // We need to guard some of the invocation interface's calls: a bad caller might
395 // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
Elliott Hughesa0957642011-09-02 14:27:33 -0700396 Thread* self = Thread::Current();
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700397 if ((flags_ & kFlag_Invocation) == 0 || self != NULL) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700398 traceMethod = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -0700399 }
400 }
Elliott Hughesa0957642011-09-02 14:27:33 -0700401
Elliott Hughes485cac42011-12-09 17:49:35 -0800402 if (((flags_ & kFlag_ForceTrace) != 0) || (traceMethod != NULL && ShouldTrace(vm_, traceMethod))) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700403 va_start(ap, fmt0);
404 std::string msg;
405 for (const char* fmt = fmt0; *fmt;) {
406 char ch = *fmt++;
407 if (ch == 'B') { // jbyte
408 jbyte b = va_arg(ap, int);
409 if (b >= 0 && b < 10) {
410 StringAppendF(&msg, "%d", b);
411 } else {
412 StringAppendF(&msg, "%#x (%d)", b, b);
413 }
414 } else if (ch == 'C') { // jchar
415 jchar c = va_arg(ap, int);
416 if (c < 0x7f && c >= ' ') {
417 StringAppendF(&msg, "U+%x ('%c')", c, c);
418 } else {
419 StringAppendF(&msg, "U+%x", c);
420 }
421 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
422 StringAppendF(&msg, "%g", va_arg(ap, double));
423 } else if (ch == 'I' || ch == 'S') { // jint, jshort
424 StringAppendF(&msg, "%d", va_arg(ap, int));
425 } else if (ch == 'J') { // jlong
426 StringAppendF(&msg, "%lld", va_arg(ap, jlong));
427 } else if (ch == 'Z') { // jboolean
428 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
429 } else if (ch == 'V') { // void
430 msg += "void";
431 } else if (ch == 'v') { // JavaVM*
432 JavaVM* vm = va_arg(ap, JavaVM*);
433 StringAppendF(&msg, "(JavaVM*)%p", vm);
434 } else if (ch == 'E') { // JNIEnv*
435 JNIEnv* env = va_arg(ap, JNIEnv*);
436 StringAppendF(&msg, "(JNIEnv*)%p", env);
437 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
438 // For logging purposes, these are identical.
439 jobject o = va_arg(ap, jobject);
440 if (o == NULL) {
441 msg += "NULL";
442 } else {
443 StringAppendF(&msg, "%p", o);
444 }
445 } else if (ch == 'b') { // jboolean (JNI-style)
446 jboolean b = va_arg(ap, int);
447 msg += (b ? "JNI_TRUE" : "JNI_FALSE");
448 } else if (ch == 'c') { // jclass
449 jclass jc = va_arg(ap, jclass);
450 Class* c = reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(jc));
451 if (c == NULL) {
452 msg += "NULL";
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800453 } else if (c == kInvalidIndirectRefObject || !Runtime::Current()->GetHeap()->IsHeapAddress(c)) {
Elliott Hughes485cac42011-12-09 17:49:35 -0800454 StringAppendF(&msg, "INVALID POINTER:%p", jc);
455 } else if (!c->IsClass()) {
456 msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700457 } else {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700458 msg += PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700459 if (!entry) {
460 StringAppendF(&msg, " (%p)", jc);
461 }
462 }
463 } else if (ch == 'f') { // jfieldID
464 jfieldID fid = va_arg(ap, jfieldID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700465 Field* f = reinterpret_cast<Field*>(fid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700466 msg += PrettyField(f);
467 if (!entry) {
468 StringAppendF(&msg, " (%p)", fid);
469 }
470 } else if (ch == 'z') { // non-negative jsize
471 // You might expect jsize to be size_t, but it's not; it's the same as jint.
472 // We only treat this specially so we can do the non-negative check.
473 // TODO: maybe this wasn't worth it?
474 jint i = va_arg(ap, jint);
475 StringAppendF(&msg, "%d", i);
476 } else if (ch == 'm') { // jmethodID
477 jmethodID mid = va_arg(ap, jmethodID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700478 Method* m = reinterpret_cast<Method*>(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700479 msg += PrettyMethod(m);
480 if (!entry) {
481 StringAppendF(&msg, " (%p)", mid);
482 }
483 } else if (ch == 'p') { // void* ("pointer")
484 void* p = va_arg(ap, void*);
485 if (p == NULL) {
486 msg += "NULL";
487 } else {
488 StringAppendF(&msg, "(void*) %p", p);
489 }
490 } else if (ch == 'r') { // jint (release mode)
491 jint releaseMode = va_arg(ap, jint);
492 if (releaseMode == 0) {
493 msg += "0";
494 } else if (releaseMode == JNI_ABORT) {
495 msg += "JNI_ABORT";
496 } else if (releaseMode == JNI_COMMIT) {
497 msg += "JNI_COMMIT";
498 } else {
499 StringAppendF(&msg, "invalid release mode %d", releaseMode);
500 }
Elliott Hughes78090d12011-10-07 14:31:47 -0700501 } else if (ch == 'u') { // const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700502 const char* utf = va_arg(ap, const char*);
503 if (utf == NULL) {
504 msg += "NULL";
505 } else {
506 StringAppendF(&msg, "\"%s\"", utf);
507 }
508 } else if (ch == '.') {
509 msg += "...";
510 } else {
511 LOG(ERROR) << "unknown trace format specifier: " << ch;
512 JniAbort();
513 return;
514 }
515 if (*fmt) {
516 StringAppendF(&msg, ", ");
517 }
518 }
519 va_end(ap);
520
Elliott Hughes485cac42011-12-09 17:49:35 -0800521 if ((flags_ & kFlag_ForceTrace) != 0) {
522 LOG(INFO) << "JNI: call to " << function_name_ << "(" << msg << ")";
523 } else if (entry) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700524 if (has_method_) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700525 std::string methodName(PrettyMethod(traceMethod, false));
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700526 LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
527 indent_ = methodName.size() + 1;
Elliott Hughesa2501992011-08-26 19:39:54 -0700528 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700529 LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
530 indent_ = 0;
Elliott Hughesa2501992011-08-26 19:39:54 -0700531 }
532 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700533 LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
Elliott Hughesa2501992011-08-26 19:39:54 -0700534 }
535 }
536
537 // We always do the thorough checks on entry, and never on exit...
538 if (entry) {
539 va_start(ap, fmt0);
540 for (const char* fmt = fmt0; *fmt; ++fmt) {
541 char ch = *fmt;
542 if (ch == 'a') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700543 CheckArray(va_arg(ap, jarray));
Elliott Hughesa2501992011-08-26 19:39:54 -0700544 } else if (ch == 'c') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700545 CheckInstance(kClass, va_arg(ap, jclass));
Elliott Hughesa2501992011-08-26 19:39:54 -0700546 } else if (ch == 'L') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700547 CheckObject(va_arg(ap, jobject));
Elliott Hughesa2501992011-08-26 19:39:54 -0700548 } else if (ch == 'r') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700549 CheckReleaseMode(va_arg(ap, jint));
Elliott Hughesa2501992011-08-26 19:39:54 -0700550 } else if (ch == 's') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700551 CheckInstance(kString, va_arg(ap, jstring));
Elliott Hughesa2501992011-08-26 19:39:54 -0700552 } else if (ch == 'u') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700553 if ((flags_ & kFlag_Release) != 0) {
554 CheckNonNull(va_arg(ap, const char*));
Elliott Hughesa2501992011-08-26 19:39:54 -0700555 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700556 bool nullable = ((flags_ & kFlag_NullableUtf) != 0);
557 CheckUtfString(va_arg(ap, const char*), nullable);
Elliott Hughesa2501992011-08-26 19:39:54 -0700558 }
559 } else if (ch == 'z') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700560 CheckLengthPositive(va_arg(ap, jsize));
Elliott Hughesa2501992011-08-26 19:39:54 -0700561 } else if (strchr("BCISZbfmpEv", ch) != NULL) {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800562 va_arg(ap, uint32_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700563 } else if (ch == 'D' || ch == 'F') {
564 va_arg(ap, double); // Skip this argument.
565 } else if (ch == 'J') {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800566 va_arg(ap, uint64_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700567 } else if (ch == '.') {
568 } else {
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800569 LOG(FATAL) << "Unknown check format specifier: " << ch;
Elliott Hughesa2501992011-08-26 19:39:54 -0700570 }
571 }
572 va_end(ap);
573 }
574 }
575
Elliott Hughesa92853e2012-02-07 16:09:27 -0800576 enum InstanceKind {
577 kClass,
578 kDirectByteBuffer,
579 kObject,
580 kString,
581 kThrowable,
582 };
583
584 /*
585 * Verify that "jobj" is a valid non-NULL object reference, and points to
586 * an instance of expectedClass.
587 *
588 * Because we're looking at an object on the GC heap, we have to switch
589 * to "running" mode before doing the checks.
590 */
591 bool CheckInstance(InstanceKind kind, jobject java_object) {
592 const char* what = NULL;
593 switch (kind) {
594 case kClass:
595 what = "jclass";
596 break;
597 case kDirectByteBuffer:
598 what = "direct ByteBuffer";
599 break;
600 case kObject:
601 what = "jobject";
602 break;
603 case kString:
604 what = "jstring";
605 break;
606 case kThrowable:
607 what = "jthrowable";
608 break;
609 default:
610 CHECK(false) << static_cast<int>(kind);
611 }
612
613 if (java_object == NULL) {
614 LOG(ERROR) << "JNI ERROR: " << function_name_ << " received null " << what;
615 JniAbort();
616 return false;
617 }
618
619 ScopedJniThreadState ts(env_);
620 Object* obj = Decode<Object*>(ts, java_object);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800621 if (!Runtime::Current()->GetHeap()->IsHeapAddress(obj)) {
622 LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": "
623 << java_object << " (" << obj << ")";
Elliott Hughesa92853e2012-02-07 16:09:27 -0800624 JniAbort();
625 return false;
626 }
627
628 bool okay = true;
629 switch (kind) {
630 case kClass:
631 okay = obj->IsClass();
632 break;
633 case kDirectByteBuffer:
634 UNIMPLEMENTED(FATAL);
635 break;
636 case kString:
637 okay = obj->GetClass()->IsStringClass();
638 break;
639 case kThrowable:
640 okay = obj->GetClass()->IsThrowableClass();
641 break;
642 case kObject:
643 break;
644 }
645 if (!okay) {
646 LOG(ERROR) << "JNI ERROR: " << what << " has wrong type: " << PrettyTypeOf(obj);
647 JniAbort();
648 return false;
649 }
650
651 return true;
652 }
653
Elliott Hughesba8eee12012-01-24 20:25:24 -0800654 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700655 void Init(JNIEnv* env, JavaVM* vm, int flags, const char* functionName, bool hasMethod) {
656 env_ = reinterpret_cast<JNIEnvExt*>(env);
657 vm_ = reinterpret_cast<JavaVMExt*>(vm);
658 flags_ = flags;
659 function_name_ = functionName;
Elliott Hughesa2501992011-08-26 19:39:54 -0700660
661 // Set "hasMethod" to true if we have a valid thread with a method pointer.
662 // We won't have one before attaching a thread, after detaching a thread, or
663 // after destroying the VM.
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700664 has_method_ = hasMethod;
Elliott Hughesa2501992011-08-26 19:39:54 -0700665 }
666
667 /*
668 * Verify that "array" is non-NULL and points to an Array object.
669 *
670 * Since we're dealing with objects, switch to "running" mode.
671 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700672 void CheckArray(jarray java_array) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700673 if (java_array == NULL) {
674 LOG(ERROR) << "JNI ERROR: received null array";
675 JniAbort();
676 return;
677 }
678
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700679 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700680 Array* a = Decode<Array*>(ts, java_array);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800681 if (!Runtime::Current()->GetHeap()->IsHeapAddress(a)) {
682 LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array) << " (" << a << ")";
Elliott Hughesa2501992011-08-26 19:39:54 -0700683 JniAbort();
684 } else if (!a->IsArrayInstance()) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700685 LOG(ERROR) << "JNI ERROR: jarray argument has non-array type: " << PrettyTypeOf(a);
Elliott Hughesa2501992011-08-26 19:39:54 -0700686 JniAbort();
687 }
688 }
689
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700690 void CheckLengthPositive(jsize length) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700691 if (length < 0) {
692 LOG(ERROR) << "JNI ERROR: negative jsize: " << length;
693 JniAbort();
694 }
695 }
696
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700697 Field* CheckFieldID(jfieldID fid) {
698 if (fid == NULL) {
699 LOG(ERROR) << "JNI ERROR: null jfieldID";
700 JniAbort();
701 return NULL;
702 }
703 Field* f = DecodeField(fid);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800704 if (!Runtime::Current()->GetHeap()->IsHeapAddress(f)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700705 LOG(ERROR) << "JNI ERROR: invalid jfieldID: " << fid;
706 JniAbort();
707 return NULL;
708 }
709 return f;
710 }
711
712 Method* CheckMethodID(jmethodID mid) {
713 if (mid == NULL) {
714 LOG(ERROR) << "JNI ERROR: null jmethodID";
715 JniAbort();
716 return NULL;
717 }
718 Method* m = DecodeMethod(mid);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800719 if (!Runtime::Current()->GetHeap()->IsHeapAddress(m)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700720 LOG(ERROR) << "JNI ERROR: invalid jmethodID: " << mid;
721 JniAbort();
722 return NULL;
723 }
724 return m;
725 }
726
Elliott Hughesa2501992011-08-26 19:39:54 -0700727 /*
728 * Verify that "jobj" is a valid object, and that it's an object that JNI
729 * is allowed to know about. We allow NULL references.
730 *
731 * Switches to "running" mode before performing checks.
732 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700733 void CheckObject(jobject java_object) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700734 if (java_object == NULL) {
735 return;
736 }
737
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700738 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700739
740 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800741 if (o != NULL && !Runtime::Current()->GetHeap()->IsHeapAddress(o)) {
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700742 // TODO: when we remove work_around_app_jni_bugs, this should be impossible.
Elliott Hughesa2501992011-08-26 19:39:54 -0700743 LOG(ERROR) << "JNI ERROR: native code passing in reference to invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
744 JniAbort();
745 }
746 }
747
748 /*
749 * Verify that the "mode" argument passed to a primitive array Release
750 * function is one of the valid values.
751 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700752 void CheckReleaseMode(jint mode) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700753 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
754 LOG(ERROR) << "JNI ERROR: bad value for release mode: " << mode;
755 JniAbort();
756 }
757 }
758
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700759 void CheckThread(int flags) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700760 Thread* self = Thread::Current();
761 if (self == NULL) {
762 LOG(ERROR) << "JNI ERROR: non-VM thread making JNI calls";
763 JniAbort();
764 return;
765 }
766
767 // Get the *correct* JNIEnv by going through our TLS pointer.
768 JNIEnvExt* threadEnv = self->GetJniEnv();
769
770 /*
771 * Verify that the current thread is (a) attached and (b) associated with
772 * this particular instance of JNIEnv.
773 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700774 if (env_ != threadEnv) {
775 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNIEnv* from thread " << *env_->self;
Elliott Hughesa2501992011-08-26 19:39:54 -0700776 // If we're keeping broken code limping along, we need to suppress the abort...
Elliott Hughesc2dc62d2012-01-17 20:06:12 -0800777 if (!vm_->work_around_app_jni_bugs) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700778 JniAbort();
779 return;
780 }
781 }
782
783 /*
784 * Verify that, if this thread previously made a critical "get" call, we
785 * do the corresponding "release" call before we try anything else.
786 */
787 switch (flags & kFlag_CritMask) {
788 case kFlag_CritOkay: // okay to call this method
789 break;
790 case kFlag_CritBad: // not okay to call
791 if (threadEnv->critical) {
792 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNI after critical get";
793 JniAbort();
794 return;
795 }
796 break;
797 case kFlag_CritGet: // this is a "get" call
798 /* don't check here; we allow nested gets */
799 threadEnv->critical++;
800 break;
801 case kFlag_CritRelease: // this is a "release" call
802 threadEnv->critical--;
803 if (threadEnv->critical < 0) {
804 LOG(ERROR) << "JNI ERROR: thread " << *self << " called too many critical releases";
805 JniAbort();
806 return;
807 }
808 break;
809 default:
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800810 LOG(FATAL) << "Bad flags (internal error): " << flags;
Elliott Hughesa2501992011-08-26 19:39:54 -0700811 }
812
813 /*
814 * Verify that, if an exception has been raised, the native code doesn't
815 * make any JNI calls other than the Exception* methods.
816 */
817 if ((flags & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
Elliott Hughes30646832011-10-13 16:59:46 -0700818 std::string type(PrettyTypeOf(self->GetException()));
819 LOG(ERROR) << "JNI ERROR: JNI " << function_name_ << " called with " << type << " pending";
820 // TODO: write native code that doesn't require allocation for dumping an exception.
821 if (type != "java.lang.OutOfMemoryError") {
822 LOG(ERROR) << "Pending exception is: ";
823 LOG(ERROR) << jniGetStackTrace(env_);
824 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700825 JniAbort();
826 return;
827 }
828 }
829
830 /*
Elliott Hughes78090d12011-10-07 14:31:47 -0700831 * Verify that "bytes" points to valid Modified UTF-8 data.
Elliott Hughesa2501992011-08-26 19:39:54 -0700832 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700833 void CheckUtfString(const char* bytes, bool nullable) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700834 if (bytes == NULL) {
835 if (!nullable) {
836 LOG(ERROR) << "JNI ERROR: non-nullable const char* was NULL";
837 JniAbort();
838 return;
839 }
840 return;
841 }
842
843 const char* errorKind = NULL;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700844 uint8_t utf8 = CheckUtfBytes(bytes, &errorKind);
Elliott Hughesa2501992011-08-26 19:39:54 -0700845 if (errorKind != NULL) {
Elliott Hughes78090d12011-10-07 14:31:47 -0700846 LOG(ERROR) << "JNI ERROR: input is not valid Modified UTF-8: "
847 << "illegal " << errorKind << " byte " << StringPrintf("%#x", utf8) << "\n"
848 << " string: '" << bytes << "'";
Elliott Hughesa2501992011-08-26 19:39:54 -0700849 JniAbort();
850 return;
851 }
852 }
853
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700854 static uint8_t CheckUtfBytes(const char* bytes, const char** errorKind) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700855 while (*bytes != '\0') {
856 uint8_t utf8 = *(bytes++);
857 // Switch on the high four bits.
858 switch (utf8 >> 4) {
859 case 0x00:
860 case 0x01:
861 case 0x02:
862 case 0x03:
863 case 0x04:
864 case 0x05:
865 case 0x06:
866 case 0x07:
867 // Bit pattern 0xxx. No need for any extra bytes.
868 break;
869 case 0x08:
870 case 0x09:
871 case 0x0a:
872 case 0x0b:
873 case 0x0f:
874 /*
875 * Bit pattern 10xx or 1111, which are illegal start bytes.
876 * Note: 1111 is valid for normal UTF-8, but not the
Elliott Hughes78090d12011-10-07 14:31:47 -0700877 * Modified UTF-8 used here.
Elliott Hughesa2501992011-08-26 19:39:54 -0700878 */
879 *errorKind = "start";
880 return utf8;
881 case 0x0e:
882 // Bit pattern 1110, so there are two additional bytes.
883 utf8 = *(bytes++);
884 if ((utf8 & 0xc0) != 0x80) {
885 *errorKind = "continuation";
886 return utf8;
887 }
888 // Fall through to take care of the final byte.
889 case 0x0c:
890 case 0x0d:
891 // Bit pattern 110x, so there is one additional byte.
892 utf8 = *(bytes++);
893 if ((utf8 & 0xc0) != 0x80) {
894 *errorKind = "continuation";
895 return utf8;
896 }
897 break;
898 }
899 }
900 return 0;
901 }
902
903 void JniAbort() {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700904 ::art::JniAbort(function_name_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700905 }
906
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700907 JNIEnvExt* env_;
908 JavaVMExt* vm_;
909 const char* function_name_;
910 int flags_;
911 bool has_method_;
Elliott Hughes92cb4982011-12-16 16:57:28 -0800912 int indent_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700913
914 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
915};
916
917#define CHECK_JNI_ENTRY(flags, types, args...) \
918 ScopedCheck sc(env, flags, __FUNCTION__); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700919 sc.Check(true, types, ##args)
Elliott Hughesa2501992011-08-26 19:39:54 -0700920
921#define CHECK_JNI_EXIT(type, exp) ({ \
Elliott Hughes362f9bc2011-10-17 18:56:41 -0700922 typeof(exp) _rc = (exp); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700923 sc.Check(false, type, _rc); \
Elliott Hughesa2501992011-08-26 19:39:54 -0700924 _rc; })
925#define CHECK_JNI_EXIT_VOID() \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700926 sc.Check(false, "V")
Elliott Hughesa2501992011-08-26 19:39:54 -0700927
928/*
929 * ===========================================================================
930 * Guarded arrays
931 * ===========================================================================
932 */
933
934#define kGuardLen 512 /* must be multiple of 2 */
935#define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */
936#define kGuardMagic 0xffd5aa96
937
938/* this gets tucked in at the start of the buffer; struct size must be even */
939struct GuardedCopy {
940 uint32_t magic;
941 uLong adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700942 size_t original_length;
943 const void* original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700944
945 /* find the GuardedCopy given the pointer into the "live" data */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700946 static inline const GuardedCopy* FromData(const void* dataBuf) {
947 return reinterpret_cast<const GuardedCopy*>(ActualBuffer(dataBuf));
Elliott Hughesa2501992011-08-26 19:39:54 -0700948 }
949
950 /*
951 * Create an over-sized buffer to hold the contents of "buf". Copy it in,
952 * filling in the area around it with guard data.
953 *
954 * We use a 16-bit pattern to make a rogue memset less likely to elude us.
955 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700956 static void* Create(const void* buf, size_t len, bool modOkay) {
957 size_t newLen = ActualLength(len);
958 uint8_t* newBuf = DebugAlloc(newLen);
Elliott Hughesa2501992011-08-26 19:39:54 -0700959
960 /* fill it in with a pattern */
Elliott Hughesba8eee12012-01-24 20:25:24 -0800961 uint16_t* pat = reinterpret_cast<uint16_t*>(newBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -0700962 for (size_t i = 0; i < newLen / 2; i++) {
963 *pat++ = kGuardPattern;
964 }
965
966 /* copy the data in; note "len" could be zero */
967 memcpy(newBuf + kGuardLen / 2, buf, len);
968
969 /* if modification is not expected, grab a checksum */
970 uLong adler = 0;
971 if (!modOkay) {
972 adler = adler32(0L, Z_NULL, 0);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800973 adler = adler32(adler, reinterpret_cast<const Bytef*>(buf), len);
974 *reinterpret_cast<uLong*>(newBuf) = adler;
Elliott Hughesa2501992011-08-26 19:39:54 -0700975 }
976
977 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
978 pExtra->magic = kGuardMagic;
979 pExtra->adler = adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700980 pExtra->original_ptr = buf;
981 pExtra->original_length = len;
Elliott Hughesa2501992011-08-26 19:39:54 -0700982
983 return newBuf + kGuardLen / 2;
984 }
985
986 /*
987 * Free up the guard buffer, scrub it, and return the original pointer.
988 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700989 static void* Destroy(void* dataBuf) {
990 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800991 void* original_ptr = const_cast<void*>(pExtra->original_ptr);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700992 size_t len = pExtra->original_length;
993 DebugFree(dataBuf, len);
994 return original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700995 }
996
997 /*
998 * Verify the guard area and, if "modOkay" is false, that the data itself
999 * has not been altered.
1000 *
1001 * The caller has already checked that "dataBuf" is non-NULL.
1002 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001003 static void Check(const char* functionName, const void* dataBuf, bool modOkay) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001004 static const uint32_t kMagicCmp = kGuardMagic;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001005 const uint8_t* fullBuf = ActualBuffer(dataBuf);
1006 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001007
1008 /*
1009 * Before we do anything with "pExtra", check the magic number. We
1010 * do the check with memcmp rather than "==" in case the pointer is
1011 * unaligned. If it points to completely bogus memory we're going
1012 * to crash, but there's no easy way around that.
1013 */
1014 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
1015 uint8_t buf[4];
1016 memcpy(buf, &pExtra->magic, 4);
1017 LOG(ERROR) << StringPrintf("JNI: guard magic does not match "
1018 "(found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
1019 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
1020 JniAbort(functionName);
1021 }
1022
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001023 size_t len = pExtra->original_length;
Elliott Hughesa2501992011-08-26 19:39:54 -07001024
1025 /* check bottom half of guard; skip over optional checksum storage */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001026 const uint16_t* pat = reinterpret_cast<const uint16_t*>(fullBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001027 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
1028 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001029 LOG(ERROR) << "JNI: guard pattern(1) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001030 JniAbort(functionName);
1031 }
1032 }
1033
1034 int offset = kGuardLen / 2 + len;
1035 if (offset & 0x01) {
1036 /* odd byte; expected value depends on endian-ness of host */
1037 const uint16_t patSample = kGuardPattern;
Elliott Hughesba8eee12012-01-24 20:25:24 -08001038 if (fullBuf[offset] != reinterpret_cast<const uint8_t*>(&patSample)[1]) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001039 LOG(ERROR) << "JNI: guard pattern disturbed in odd byte after "
Elliott Hughesba8eee12012-01-24 20:25:24 -08001040 << reinterpret_cast<const void*>(fullBuf) << " (+" << offset << ") "
Elliott Hughesa2501992011-08-26 19:39:54 -07001041 << StringPrintf("0x%02x 0x%02x", fullBuf[offset], ((const uint8_t*) &patSample)[1]);
1042 JniAbort(functionName);
1043 }
1044 offset++;
1045 }
1046
1047 /* check top half of guard */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001048 pat = reinterpret_cast<const uint16_t*>(fullBuf + offset);
Elliott Hughesa2501992011-08-26 19:39:54 -07001049 for (size_t i = 0; i < kGuardLen / 4; i++) {
1050 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001051 LOG(ERROR) << "JNI: guard pattern(2) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (offset + i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001052 JniAbort(functionName);
1053 }
1054 }
1055
1056 /*
1057 * If modification is not expected, verify checksum. Strictly speaking
1058 * this is wrong: if we told the client that we made a copy, there's no
1059 * reason they can't alter the buffer.
1060 */
1061 if (!modOkay) {
1062 uLong adler = adler32(0L, Z_NULL, 0);
1063 adler = adler32(adler, (const Bytef*)dataBuf, len);
1064 if (pExtra->adler != adler) {
1065 LOG(ERROR) << StringPrintf("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", pExtra->adler, adler, dataBuf);
1066 JniAbort(functionName);
1067 }
1068 }
1069 }
1070
1071 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001072 static uint8_t* DebugAlloc(size_t len) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001073 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1074 if (result == MAP_FAILED) {
1075 PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed";
1076 }
1077 return reinterpret_cast<uint8_t*>(result);
1078 }
1079
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001080 static void DebugFree(void* dataBuf, size_t len) {
1081 uint8_t* fullBuf = ActualBuffer(dataBuf);
1082 size_t totalByteCount = ActualLength(len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001083 // TODO: we could mprotect instead, and keep the allocation around for a while.
1084 // This would be even more expensive, but it might catch more errors.
1085 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
1086 // LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
1087 // }
1088 if (munmap(fullBuf, totalByteCount) != 0) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001089 PLOG(FATAL) << "munmap(" << reinterpret_cast<void*>(fullBuf) << ", " << totalByteCount << ") failed";
Elliott Hughesa2501992011-08-26 19:39:54 -07001090 }
1091 }
1092
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001093 static const uint8_t* ActualBuffer(const void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001094 return reinterpret_cast<const uint8_t*>(dataBuf) - kGuardLen / 2;
1095 }
1096
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001097 static uint8_t* ActualBuffer(void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001098 return reinterpret_cast<uint8_t*>(dataBuf) - kGuardLen / 2;
1099 }
1100
1101 // Underlying length of a user allocation of 'length' bytes.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001102 static size_t ActualLength(size_t length) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001103 return (length + kGuardLen + 1) & ~0x01;
1104 }
1105};
1106
1107/*
1108 * Create a guarded copy of a primitive array. Modifications to the copied
1109 * data are allowed. Returns a pointer to the copied data.
1110 */
1111void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* isCopy) {
1112 ScopedJniThreadState ts(env);
1113
1114 Array* a = Decode<Array*>(ts, java_array);
Ian Rogersa15e67d2012-02-28 13:51:55 -08001115 size_t component_size = a->GetClass()->GetComponentSize();
1116 size_t byte_count = a->GetLength() * component_size;
1117 void* result = GuardedCopy::Create(a->GetRawData(component_size), byte_count, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001118 if (isCopy != NULL) {
1119 *isCopy = JNI_TRUE;
1120 }
1121 return result;
1122}
1123
1124/*
1125 * Perform the array "release" operation, which may or may not copy data
1126 * back into the VM, and may or may not release the underlying storage.
1127 */
1128void ReleaseGuardedPACopy(JNIEnv* env, jarray java_array, void* dataBuf, int mode) {
1129 if (reinterpret_cast<uintptr_t>(dataBuf) == kNoCopyMagic) {
1130 return;
1131 }
1132
1133 ScopedJniThreadState ts(env);
1134 Array* a = Decode<Array*>(ts, java_array);
1135
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001136 GuardedCopy::Check(__FUNCTION__, dataBuf, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001137
1138 if (mode != JNI_ABORT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001139 size_t len = GuardedCopy::FromData(dataBuf)->original_length;
Ian Rogersa15e67d2012-02-28 13:51:55 -08001140 memcpy(a->GetRawData(a->GetClass()->GetComponentSize()), dataBuf, len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001141 }
1142 if (mode != JNI_COMMIT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001143 GuardedCopy::Destroy(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001144 }
1145}
1146
1147/*
1148 * ===========================================================================
1149 * JNI functions
1150 * ===========================================================================
1151 */
1152
1153class CheckJNI {
1154 public:
1155 static jint GetVersion(JNIEnv* env) {
1156 CHECK_JNI_ENTRY(kFlag_Default, "E", env);
1157 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
1158 }
1159
1160 static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf, jsize bufLen) {
1161 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001162 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001163 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
1164 }
1165
1166 static jclass FindClass(JNIEnv* env, const char* name) {
1167 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001168 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001169 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
1170 }
1171
1172 static jclass GetSuperclass(JNIEnv* env, jclass clazz) {
1173 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1174 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz));
1175 }
1176
1177 static jboolean IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) {
1178 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2);
1179 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2));
1180 }
1181
1182 static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
1183 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
1184 // TODO: check that 'field' is a java.lang.reflect.Method.
1185 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
1186 }
1187
1188 static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
1189 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
1190 // TODO: check that 'field' is a java.lang.reflect.Field.
1191 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
1192 }
1193
1194 static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
1195 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, mid, isStatic);
1196 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, mid, isStatic));
1197 }
1198
1199 static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
1200 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fid, isStatic);
1201 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fid, isStatic));
1202 }
1203
1204 static jint Throw(JNIEnv* env, jthrowable obj) {
1205 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1206 // TODO: check that 'obj' is a java.lang.Throwable.
1207 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
1208 }
1209
1210 static jint ThrowNew(JNIEnv* env, jclass clazz, const char* message) {
1211 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message);
1212 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message));
1213 }
1214
1215 static jthrowable ExceptionOccurred(JNIEnv* env) {
1216 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1217 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
1218 }
1219
1220 static void ExceptionDescribe(JNIEnv* env) {
1221 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1222 baseEnv(env)->ExceptionDescribe(env);
1223 CHECK_JNI_EXIT_VOID();
1224 }
1225
1226 static void ExceptionClear(JNIEnv* env) {
1227 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1228 baseEnv(env)->ExceptionClear(env);
1229 CHECK_JNI_EXIT_VOID();
1230 }
1231
1232 static void FatalError(JNIEnv* env, const char* msg) {
1233 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
1234 baseEnv(env)->FatalError(env, msg);
1235 CHECK_JNI_EXIT_VOID();
1236 }
1237
1238 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1239 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
1240 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
1241 }
1242
1243 static jobject PopLocalFrame(JNIEnv* env, jobject res) {
1244 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
1245 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
1246 }
1247
1248 static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
1249 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1250 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
1251 }
1252
1253 static jobject NewLocalRef(JNIEnv* env, jobject ref) {
1254 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
1255 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
1256 }
1257
1258 static void DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
1259 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
1260 if (globalRef != NULL && GetIndirectRefKind(globalRef) != kGlobal) {
1261 LOG(ERROR) << "JNI ERROR: DeleteGlobalRef on " << GetIndirectRefKind(globalRef) << ": " << globalRef;
1262 JniAbort(__FUNCTION__);
1263 } else {
1264 baseEnv(env)->DeleteGlobalRef(env, globalRef);
1265 CHECK_JNI_EXIT_VOID();
1266 }
1267 }
1268
1269 static void DeleteWeakGlobalRef(JNIEnv* env, jweak weakGlobalRef) {
1270 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, weakGlobalRef);
1271 if (weakGlobalRef != NULL && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) {
1272 LOG(ERROR) << "JNI ERROR: DeleteWeakGlobalRef on " << GetIndirectRefKind(weakGlobalRef) << ": " << weakGlobalRef;
1273 JniAbort(__FUNCTION__);
1274 } else {
1275 baseEnv(env)->DeleteWeakGlobalRef(env, weakGlobalRef);
1276 CHECK_JNI_EXIT_VOID();
1277 }
1278 }
1279
1280 static void DeleteLocalRef(JNIEnv* env, jobject localRef) {
1281 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
Ian Rogers959f8ed2012-02-07 16:33:37 -08001282 if (localRef != NULL && GetIndirectRefKind(localRef) != kLocal && !IsSirtLocalRef(env, localRef)) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001283 LOG(ERROR) << "JNI ERROR: DeleteLocalRef on " << GetIndirectRefKind(localRef) << ": " << localRef;
1284 JniAbort(__FUNCTION__);
1285 } else {
1286 baseEnv(env)->DeleteLocalRef(env, localRef);
1287 CHECK_JNI_EXIT_VOID();
1288 }
1289 }
1290
1291 static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
1292 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
1293 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
1294 }
1295
1296 static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
1297 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
1298 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
1299 }
1300
1301 static jobject AllocObject(JNIEnv* env, jclass clazz) {
1302 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1303 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz));
1304 }
1305
1306 static jobject NewObject(JNIEnv* env, jclass clazz, jmethodID mid, ...) {
1307 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1308 va_list args;
1309 va_start(args, mid);
1310 jobject result = baseEnv(env)->NewObjectV(env, clazz, mid, args);
1311 va_end(args);
1312 return CHECK_JNI_EXIT("L", result);
1313 }
1314
1315 static jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) {
1316 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1317 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, mid, args));
1318 }
1319
1320 static jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) {
1321 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1322 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, mid, args));
1323 }
1324
1325 static jclass GetObjectClass(JNIEnv* env, jobject obj) {
1326 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1327 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
1328 }
1329
1330 static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
1331 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz);
1332 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz));
1333 }
1334
1335 static jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1336 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1337 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig));
1338 }
1339
1340 static jfieldID GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1341 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1342 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig));
1343 }
1344
1345 static jmethodID GetStaticMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1346 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1347 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig));
1348 }
1349
1350 static jfieldID GetStaticFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1351 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1352 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig));
1353 }
1354
1355#define FIELD_ACCESSORS(_ctype, _jname, _type) \
1356 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid) { \
1357 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001358 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001359 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fid)); \
1360 } \
1361 static _ctype Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid) { \
1362 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001363 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001364 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fid)); \
1365 } \
1366 static void SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid, _ctype value) { \
1367 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001368 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001369 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001370 sc.CheckFieldType((jobject)(uint32_t)value, fid, _type[0], true); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001371 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fid, value); \
1372 CHECK_JNI_EXIT_VOID(); \
1373 } \
1374 static void Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid, _ctype value) { \
1375 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001376 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001377 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001378 sc.CheckFieldType((jobject)(uint32_t) value, fid, _type[0], false); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001379 baseEnv(env)->Set##_jname##Field(env, obj, fid, value); \
1380 CHECK_JNI_EXIT_VOID(); \
1381 }
1382
1383FIELD_ACCESSORS(jobject, Object, "L");
1384FIELD_ACCESSORS(jboolean, Boolean, "Z");
1385FIELD_ACCESSORS(jbyte, Byte, "B");
1386FIELD_ACCESSORS(jchar, Char, "C");
1387FIELD_ACCESSORS(jshort, Short, "S");
1388FIELD_ACCESSORS(jint, Int, "I");
1389FIELD_ACCESSORS(jlong, Long, "J");
1390FIELD_ACCESSORS(jfloat, Float, "F");
1391FIELD_ACCESSORS(jdouble, Double, "D");
1392
1393#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
1394 /* Virtual... */ \
1395 static _ctype Call##_jname##Method(JNIEnv* env, jobject obj, \
1396 jmethodID mid, ...) \
1397 { \
1398 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001399 sc.CheckSig(mid, _retsig, false); \
1400 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001401 _retdecl; \
1402 va_list args; \
1403 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001404 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001405 va_end(args); \
1406 _retok; \
1407 } \
1408 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1409 jmethodID mid, va_list args) \
1410 { \
1411 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001412 sc.CheckSig(mid, _retsig, false); \
1413 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001414 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001415 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001416 _retok; \
1417 } \
1418 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1419 jmethodID mid, jvalue* args) \
1420 { \
1421 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001422 sc.CheckSig(mid, _retsig, false); \
1423 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001424 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001425 _retasgn(baseEnv(env)->Call##_jname##MethodA(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001426 _retok; \
1427 } \
1428 /* Non-virtual... */ \
1429 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, \
1430 jobject obj, jclass clazz, jmethodID mid, ...) \
1431 { \
1432 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001433 sc.CheckSig(mid, _retsig, false); \
1434 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001435 _retdecl; \
1436 va_list args; \
1437 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001438 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001439 va_end(args); \
1440 _retok; \
1441 } \
1442 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, \
1443 jobject obj, jclass clazz, jmethodID mid, va_list args) \
1444 { \
1445 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001446 sc.CheckSig(mid, _retsig, false); \
1447 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001448 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001449 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001450 _retok; \
1451 } \
1452 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, \
1453 jobject obj, jclass clazz, jmethodID mid, jvalue* args) \
1454 { \
1455 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001456 sc.CheckSig(mid, _retsig, false); \
1457 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001458 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001459 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001460 _retok; \
1461 } \
1462 /* Static... */ \
1463 static _ctype CallStatic##_jname##Method(JNIEnv* env, \
1464 jclass clazz, jmethodID mid, ...) \
1465 { \
1466 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001467 sc.CheckSig(mid, _retsig, true); \
1468 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001469 _retdecl; \
1470 va_list args; \
1471 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001472 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001473 va_end(args); \
1474 _retok; \
1475 } \
1476 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, \
1477 jclass clazz, jmethodID mid, va_list args) \
1478 { \
1479 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001480 sc.CheckSig(mid, _retsig, true); \
1481 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001482 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001483 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001484 _retok; \
1485 } \
1486 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, \
1487 jclass clazz, jmethodID mid, jvalue* args) \
1488 { \
1489 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001490 sc.CheckSig(mid, _retsig, true); \
1491 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001492 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001493 _retasgn(baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001494 _retok; \
1495 }
1496
1497#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
1498#define VOID_RETURN CHECK_JNI_EXIT_VOID()
1499
Elliott Hughesba8eee12012-01-24 20:25:24 -08001500CALL(jobject, Object, Object* result, result = reinterpret_cast<Object*>, NON_VOID_RETURN("L", jobject), "L");
1501CALL(jboolean, Boolean, jboolean result, result =, NON_VOID_RETURN("Z", jboolean), "Z");
1502CALL(jbyte, Byte, jbyte result, result =, NON_VOID_RETURN("B", jbyte), "B");
1503CALL(jchar, Char, jchar result, result =, NON_VOID_RETURN("C", jchar), "C");
1504CALL(jshort, Short, jshort result, result =, NON_VOID_RETURN("S", jshort), "S");
1505CALL(jint, Int, jint result, result =, NON_VOID_RETURN("I", jint), "I");
1506CALL(jlong, Long, jlong result, result =, NON_VOID_RETURN("J", jlong), "J");
1507CALL(jfloat, Float, jfloat result, result =, NON_VOID_RETURN("F", jfloat), "F");
1508CALL(jdouble, Double, jdouble result, result =, NON_VOID_RETURN("D", jdouble), "D");
Elliott Hughesa2501992011-08-26 19:39:54 -07001509CALL(void, Void, , , VOID_RETURN, "V");
1510
1511 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
1512 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
1513 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
1514 }
1515
1516 static jsize GetStringLength(JNIEnv* env, jstring string) {
1517 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1518 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
1519 }
1520
1521 static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1522 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, java_string, isCopy);
1523 const jchar* result = baseEnv(env)->GetStringChars(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001524 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001525 ScopedJniThreadState ts(env);
1526 String* s = Decode<String*>(ts, java_string);
1527 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001528 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001529 if (isCopy != NULL) {
1530 *isCopy = JNI_TRUE;
1531 }
1532 }
1533 return CHECK_JNI_EXIT("p", result);
1534 }
1535
1536 static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
1537 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001538 sc.CheckNonNull(chars);
1539 if (sc.ForceCopy()) {
1540 GuardedCopy::Check(__FUNCTION__, chars, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001541 chars = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(chars)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001542 }
1543 baseEnv(env)->ReleaseStringChars(env, string, chars);
1544 CHECK_JNI_EXIT_VOID();
1545 }
1546
1547 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
1548 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
1549 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
1550 }
1551
1552 static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
1553 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1554 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
1555 }
1556
1557 static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1558 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1559 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001560 if (sc.ForceCopy() && result != NULL) {
1561 result = (const char*) GuardedCopy::Create(result, strlen(result) + 1, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001562 if (isCopy != NULL) {
1563 *isCopy = JNI_TRUE;
1564 }
1565 }
1566 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
1567 }
1568
1569 static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
1570 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001571 if (sc.ForceCopy()) {
1572 GuardedCopy::Check(__FUNCTION__, utf, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001573 utf = reinterpret_cast<const char*>(GuardedCopy::Destroy(const_cast<char*>(utf)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001574 }
1575 baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
1576 CHECK_JNI_EXIT_VOID();
1577 }
1578
1579 static jsize GetArrayLength(JNIEnv* env, jarray array) {
1580 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
1581 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
1582 }
1583
1584 static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass elementClass, jobject initialElement) {
1585 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
1586 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
1587 }
1588
1589 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
1590 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
1591 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
1592 }
1593
1594 static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
1595 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
1596 baseEnv(env)->SetObjectArrayElement(env, array, index, value);
1597 CHECK_JNI_EXIT_VOID();
1598 }
1599
1600#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
1601 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
1602 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
1603 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
1604 }
1605NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
1606NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
1607NEW_PRIMITIVE_ARRAY(jcharArray, Char);
1608NEW_PRIMITIVE_ARRAY(jshortArray, Short);
1609NEW_PRIMITIVE_ARRAY(jintArray, Int);
1610NEW_PRIMITIVE_ARRAY(jlongArray, Long);
1611NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
1612NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
1613
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001614struct ForceCopyGetChecker {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001615 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07001616 ForceCopyGetChecker(ScopedCheck& sc, jboolean* isCopy) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001617 force_copy = sc.ForceCopy();
1618 no_copy = 0;
1619 if (force_copy && isCopy != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001620 /* capture this before the base call tramples on it */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001621 no_copy = *reinterpret_cast<uint32_t*>(isCopy);
Elliott Hughesa2501992011-08-26 19:39:54 -07001622 }
1623 }
1624
1625 template<typename ResultT>
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001626 ResultT Check(JNIEnv* env, jarray array, jboolean* isCopy, ResultT result) {
1627 if (force_copy && result != NULL) {
1628 if (no_copy != kNoCopyMagic) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001629 result = reinterpret_cast<ResultT>(CreateGuardedPACopy(env, array, isCopy));
1630 }
1631 }
1632 return result;
1633 }
1634
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001635 uint32_t no_copy;
1636 bool force_copy;
Elliott Hughesa2501992011-08-26 19:39:54 -07001637};
1638
1639#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1640 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, jboolean* isCopy) { \
1641 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001642 _ctype* result = ForceCopyGetChecker(sc, isCopy).Check(env, array, isCopy, baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001643 return CHECK_JNI_EXIT("p", result); \
1644 }
1645
1646#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1647 static void Release##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, _ctype* elems, jint mode) { \
1648 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001649 sc.CheckNonNull(elems); \
1650 if (sc.ForceCopy()) { \
Elliott Hughesa2501992011-08-26 19:39:54 -07001651 ReleaseGuardedPACopy(env, array, elems, mode); \
1652 } \
1653 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
1654 CHECK_JNI_EXIT_VOID(); \
1655 }
1656
1657#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1658 static void Get##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
1659 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1660 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
1661 CHECK_JNI_EXIT_VOID(); \
1662 }
1663
1664#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1665 static void Set##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
1666 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1667 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
1668 CHECK_JNI_EXIT_VOID(); \
1669 }
1670
1671#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
1672 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1673 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1674 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
1675 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
1676
1677/* TODO: verify primitive array type matches call type */
1678PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
1679PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
1680PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
1681PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
1682PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
1683PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
1684PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
1685PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
1686
1687 static jint RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) {
1688 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods);
1689 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods));
1690 }
1691
1692 static jint UnregisterNatives(JNIEnv* env, jclass clazz) {
1693 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1694 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz));
1695 }
1696
1697 static jint MonitorEnter(JNIEnv* env, jobject obj) {
1698 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
Elliott Hughesa92853e2012-02-07 16:09:27 -08001699 if (!sc.CheckInstance(ScopedCheck::kObject, obj)) {
1700 return JNI_ERR; // Only for jni_internal_test. Real code will have aborted already.
1701 }
Elliott Hughesa2501992011-08-26 19:39:54 -07001702 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
1703 }
1704
1705 static jint MonitorExit(JNIEnv* env, jobject obj) {
1706 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
Elliott Hughesa92853e2012-02-07 16:09:27 -08001707 if (!sc.CheckInstance(ScopedCheck::kObject, obj)) {
1708 return JNI_ERR; // Only for jni_internal_test. Real code will have aborted already.
1709 }
Elliott Hughesa2501992011-08-26 19:39:54 -07001710 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
1711 }
1712
1713 static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
1714 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
1715 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
1716 }
1717
1718 static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
1719 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1720 baseEnv(env)->GetStringRegion(env, str, start, len, buf);
1721 CHECK_JNI_EXIT_VOID();
1722 }
1723
1724 static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
1725 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1726 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
1727 CHECK_JNI_EXIT_VOID();
1728 }
1729
1730 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
1731 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
1732 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001733 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001734 result = CreateGuardedPACopy(env, array, isCopy);
1735 }
1736 return CHECK_JNI_EXIT("p", result);
1737 }
1738
1739 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
1740 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001741 sc.CheckNonNull(carray);
1742 if (sc.ForceCopy()) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001743 ReleaseGuardedPACopy(env, array, carray, mode);
1744 }
1745 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
1746 CHECK_JNI_EXIT_VOID();
1747 }
1748
1749 static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1750 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, java_string, isCopy);
1751 const jchar* result = baseEnv(env)->GetStringCritical(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001752 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001753 ScopedJniThreadState ts(env);
1754 String* s = Decode<String*>(ts, java_string);
1755 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001756 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001757 if (isCopy != NULL) {
1758 *isCopy = JNI_TRUE;
1759 }
1760 }
1761 return CHECK_JNI_EXIT("p", result);
1762 }
1763
1764 static void ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
1765 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001766 sc.CheckNonNull(carray);
1767 if (sc.ForceCopy()) {
1768 GuardedCopy::Check(__FUNCTION__, carray, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001769 carray = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(carray)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001770 }
1771 baseEnv(env)->ReleaseStringCritical(env, string, carray);
1772 CHECK_JNI_EXIT_VOID();
1773 }
1774
1775 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
1776 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1777 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
1778 }
1779
1780 static jboolean ExceptionCheck(JNIEnv* env) {
1781 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
1782 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
1783 }
1784
1785 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
1786 // Note: we use "Ep" rather than "EL" because this is the one JNI function
1787 // that it's okay to pass an invalid reference to.
1788 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, obj);
1789 // TODO: proper decoding of jobjectRefType!
1790 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
1791 }
1792
1793 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
1794 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
1795 if (address == NULL) {
1796 LOG(ERROR) << "JNI ERROR: non-nullable address is NULL";
1797 JniAbort(__FUNCTION__);
1798 }
1799 if (capacity <= 0) {
1800 LOG(ERROR) << "JNI ERROR: capacity must be greater than 0: " << capacity;
1801 JniAbort(__FUNCTION__);
1802 }
1803 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
1804 }
1805
1806 static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
1807 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1808 // TODO: check that 'buf' is a java.nio.Buffer.
1809 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
1810 }
1811
1812 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
1813 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1814 // TODO: check that 'buf' is a java.nio.Buffer.
1815 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
1816 }
1817
1818 private:
1819 static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
1820 return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions;
1821 }
1822};
1823
1824const JNINativeInterface gCheckNativeInterface = {
1825 NULL, // reserved0.
1826 NULL, // reserved1.
1827 NULL, // reserved2.
1828 NULL, // reserved3.
1829 CheckJNI::GetVersion,
1830 CheckJNI::DefineClass,
1831 CheckJNI::FindClass,
1832 CheckJNI::FromReflectedMethod,
1833 CheckJNI::FromReflectedField,
1834 CheckJNI::ToReflectedMethod,
1835 CheckJNI::GetSuperclass,
1836 CheckJNI::IsAssignableFrom,
1837 CheckJNI::ToReflectedField,
1838 CheckJNI::Throw,
1839 CheckJNI::ThrowNew,
1840 CheckJNI::ExceptionOccurred,
1841 CheckJNI::ExceptionDescribe,
1842 CheckJNI::ExceptionClear,
1843 CheckJNI::FatalError,
1844 CheckJNI::PushLocalFrame,
1845 CheckJNI::PopLocalFrame,
1846 CheckJNI::NewGlobalRef,
1847 CheckJNI::DeleteGlobalRef,
1848 CheckJNI::DeleteLocalRef,
1849 CheckJNI::IsSameObject,
1850 CheckJNI::NewLocalRef,
1851 CheckJNI::EnsureLocalCapacity,
1852 CheckJNI::AllocObject,
1853 CheckJNI::NewObject,
1854 CheckJNI::NewObjectV,
1855 CheckJNI::NewObjectA,
1856 CheckJNI::GetObjectClass,
1857 CheckJNI::IsInstanceOf,
1858 CheckJNI::GetMethodID,
1859 CheckJNI::CallObjectMethod,
1860 CheckJNI::CallObjectMethodV,
1861 CheckJNI::CallObjectMethodA,
1862 CheckJNI::CallBooleanMethod,
1863 CheckJNI::CallBooleanMethodV,
1864 CheckJNI::CallBooleanMethodA,
1865 CheckJNI::CallByteMethod,
1866 CheckJNI::CallByteMethodV,
1867 CheckJNI::CallByteMethodA,
1868 CheckJNI::CallCharMethod,
1869 CheckJNI::CallCharMethodV,
1870 CheckJNI::CallCharMethodA,
1871 CheckJNI::CallShortMethod,
1872 CheckJNI::CallShortMethodV,
1873 CheckJNI::CallShortMethodA,
1874 CheckJNI::CallIntMethod,
1875 CheckJNI::CallIntMethodV,
1876 CheckJNI::CallIntMethodA,
1877 CheckJNI::CallLongMethod,
1878 CheckJNI::CallLongMethodV,
1879 CheckJNI::CallLongMethodA,
1880 CheckJNI::CallFloatMethod,
1881 CheckJNI::CallFloatMethodV,
1882 CheckJNI::CallFloatMethodA,
1883 CheckJNI::CallDoubleMethod,
1884 CheckJNI::CallDoubleMethodV,
1885 CheckJNI::CallDoubleMethodA,
1886 CheckJNI::CallVoidMethod,
1887 CheckJNI::CallVoidMethodV,
1888 CheckJNI::CallVoidMethodA,
1889 CheckJNI::CallNonvirtualObjectMethod,
1890 CheckJNI::CallNonvirtualObjectMethodV,
1891 CheckJNI::CallNonvirtualObjectMethodA,
1892 CheckJNI::CallNonvirtualBooleanMethod,
1893 CheckJNI::CallNonvirtualBooleanMethodV,
1894 CheckJNI::CallNonvirtualBooleanMethodA,
1895 CheckJNI::CallNonvirtualByteMethod,
1896 CheckJNI::CallNonvirtualByteMethodV,
1897 CheckJNI::CallNonvirtualByteMethodA,
1898 CheckJNI::CallNonvirtualCharMethod,
1899 CheckJNI::CallNonvirtualCharMethodV,
1900 CheckJNI::CallNonvirtualCharMethodA,
1901 CheckJNI::CallNonvirtualShortMethod,
1902 CheckJNI::CallNonvirtualShortMethodV,
1903 CheckJNI::CallNonvirtualShortMethodA,
1904 CheckJNI::CallNonvirtualIntMethod,
1905 CheckJNI::CallNonvirtualIntMethodV,
1906 CheckJNI::CallNonvirtualIntMethodA,
1907 CheckJNI::CallNonvirtualLongMethod,
1908 CheckJNI::CallNonvirtualLongMethodV,
1909 CheckJNI::CallNonvirtualLongMethodA,
1910 CheckJNI::CallNonvirtualFloatMethod,
1911 CheckJNI::CallNonvirtualFloatMethodV,
1912 CheckJNI::CallNonvirtualFloatMethodA,
1913 CheckJNI::CallNonvirtualDoubleMethod,
1914 CheckJNI::CallNonvirtualDoubleMethodV,
1915 CheckJNI::CallNonvirtualDoubleMethodA,
1916 CheckJNI::CallNonvirtualVoidMethod,
1917 CheckJNI::CallNonvirtualVoidMethodV,
1918 CheckJNI::CallNonvirtualVoidMethodA,
1919 CheckJNI::GetFieldID,
1920 CheckJNI::GetObjectField,
1921 CheckJNI::GetBooleanField,
1922 CheckJNI::GetByteField,
1923 CheckJNI::GetCharField,
1924 CheckJNI::GetShortField,
1925 CheckJNI::GetIntField,
1926 CheckJNI::GetLongField,
1927 CheckJNI::GetFloatField,
1928 CheckJNI::GetDoubleField,
1929 CheckJNI::SetObjectField,
1930 CheckJNI::SetBooleanField,
1931 CheckJNI::SetByteField,
1932 CheckJNI::SetCharField,
1933 CheckJNI::SetShortField,
1934 CheckJNI::SetIntField,
1935 CheckJNI::SetLongField,
1936 CheckJNI::SetFloatField,
1937 CheckJNI::SetDoubleField,
1938 CheckJNI::GetStaticMethodID,
1939 CheckJNI::CallStaticObjectMethod,
1940 CheckJNI::CallStaticObjectMethodV,
1941 CheckJNI::CallStaticObjectMethodA,
1942 CheckJNI::CallStaticBooleanMethod,
1943 CheckJNI::CallStaticBooleanMethodV,
1944 CheckJNI::CallStaticBooleanMethodA,
1945 CheckJNI::CallStaticByteMethod,
1946 CheckJNI::CallStaticByteMethodV,
1947 CheckJNI::CallStaticByteMethodA,
1948 CheckJNI::CallStaticCharMethod,
1949 CheckJNI::CallStaticCharMethodV,
1950 CheckJNI::CallStaticCharMethodA,
1951 CheckJNI::CallStaticShortMethod,
1952 CheckJNI::CallStaticShortMethodV,
1953 CheckJNI::CallStaticShortMethodA,
1954 CheckJNI::CallStaticIntMethod,
1955 CheckJNI::CallStaticIntMethodV,
1956 CheckJNI::CallStaticIntMethodA,
1957 CheckJNI::CallStaticLongMethod,
1958 CheckJNI::CallStaticLongMethodV,
1959 CheckJNI::CallStaticLongMethodA,
1960 CheckJNI::CallStaticFloatMethod,
1961 CheckJNI::CallStaticFloatMethodV,
1962 CheckJNI::CallStaticFloatMethodA,
1963 CheckJNI::CallStaticDoubleMethod,
1964 CheckJNI::CallStaticDoubleMethodV,
1965 CheckJNI::CallStaticDoubleMethodA,
1966 CheckJNI::CallStaticVoidMethod,
1967 CheckJNI::CallStaticVoidMethodV,
1968 CheckJNI::CallStaticVoidMethodA,
1969 CheckJNI::GetStaticFieldID,
1970 CheckJNI::GetStaticObjectField,
1971 CheckJNI::GetStaticBooleanField,
1972 CheckJNI::GetStaticByteField,
1973 CheckJNI::GetStaticCharField,
1974 CheckJNI::GetStaticShortField,
1975 CheckJNI::GetStaticIntField,
1976 CheckJNI::GetStaticLongField,
1977 CheckJNI::GetStaticFloatField,
1978 CheckJNI::GetStaticDoubleField,
1979 CheckJNI::SetStaticObjectField,
1980 CheckJNI::SetStaticBooleanField,
1981 CheckJNI::SetStaticByteField,
1982 CheckJNI::SetStaticCharField,
1983 CheckJNI::SetStaticShortField,
1984 CheckJNI::SetStaticIntField,
1985 CheckJNI::SetStaticLongField,
1986 CheckJNI::SetStaticFloatField,
1987 CheckJNI::SetStaticDoubleField,
1988 CheckJNI::NewString,
1989 CheckJNI::GetStringLength,
1990 CheckJNI::GetStringChars,
1991 CheckJNI::ReleaseStringChars,
1992 CheckJNI::NewStringUTF,
1993 CheckJNI::GetStringUTFLength,
1994 CheckJNI::GetStringUTFChars,
1995 CheckJNI::ReleaseStringUTFChars,
1996 CheckJNI::GetArrayLength,
1997 CheckJNI::NewObjectArray,
1998 CheckJNI::GetObjectArrayElement,
1999 CheckJNI::SetObjectArrayElement,
2000 CheckJNI::NewBooleanArray,
2001 CheckJNI::NewByteArray,
2002 CheckJNI::NewCharArray,
2003 CheckJNI::NewShortArray,
2004 CheckJNI::NewIntArray,
2005 CheckJNI::NewLongArray,
2006 CheckJNI::NewFloatArray,
2007 CheckJNI::NewDoubleArray,
2008 CheckJNI::GetBooleanArrayElements,
2009 CheckJNI::GetByteArrayElements,
2010 CheckJNI::GetCharArrayElements,
2011 CheckJNI::GetShortArrayElements,
2012 CheckJNI::GetIntArrayElements,
2013 CheckJNI::GetLongArrayElements,
2014 CheckJNI::GetFloatArrayElements,
2015 CheckJNI::GetDoubleArrayElements,
2016 CheckJNI::ReleaseBooleanArrayElements,
2017 CheckJNI::ReleaseByteArrayElements,
2018 CheckJNI::ReleaseCharArrayElements,
2019 CheckJNI::ReleaseShortArrayElements,
2020 CheckJNI::ReleaseIntArrayElements,
2021 CheckJNI::ReleaseLongArrayElements,
2022 CheckJNI::ReleaseFloatArrayElements,
2023 CheckJNI::ReleaseDoubleArrayElements,
2024 CheckJNI::GetBooleanArrayRegion,
2025 CheckJNI::GetByteArrayRegion,
2026 CheckJNI::GetCharArrayRegion,
2027 CheckJNI::GetShortArrayRegion,
2028 CheckJNI::GetIntArrayRegion,
2029 CheckJNI::GetLongArrayRegion,
2030 CheckJNI::GetFloatArrayRegion,
2031 CheckJNI::GetDoubleArrayRegion,
2032 CheckJNI::SetBooleanArrayRegion,
2033 CheckJNI::SetByteArrayRegion,
2034 CheckJNI::SetCharArrayRegion,
2035 CheckJNI::SetShortArrayRegion,
2036 CheckJNI::SetIntArrayRegion,
2037 CheckJNI::SetLongArrayRegion,
2038 CheckJNI::SetFloatArrayRegion,
2039 CheckJNI::SetDoubleArrayRegion,
2040 CheckJNI::RegisterNatives,
2041 CheckJNI::UnregisterNatives,
2042 CheckJNI::MonitorEnter,
2043 CheckJNI::MonitorExit,
2044 CheckJNI::GetJavaVM,
2045 CheckJNI::GetStringRegion,
2046 CheckJNI::GetStringUTFRegion,
2047 CheckJNI::GetPrimitiveArrayCritical,
2048 CheckJNI::ReleasePrimitiveArrayCritical,
2049 CheckJNI::GetStringCritical,
2050 CheckJNI::ReleaseStringCritical,
2051 CheckJNI::NewWeakGlobalRef,
2052 CheckJNI::DeleteWeakGlobalRef,
2053 CheckJNI::ExceptionCheck,
2054 CheckJNI::NewDirectByteBuffer,
2055 CheckJNI::GetDirectBufferAddress,
2056 CheckJNI::GetDirectBufferCapacity,
2057 CheckJNI::GetObjectRefType,
2058};
2059
2060const JNINativeInterface* GetCheckJniNativeInterface() {
2061 return &gCheckNativeInterface;
2062}
2063
2064class CheckJII {
Elliott Hughesba8eee12012-01-24 20:25:24 -08002065 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07002066 static jint DestroyJavaVM(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002067 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002068 sc.Check(true, "v", vm);
2069 return CHECK_JNI_EXIT("I", BaseVm(vm)->DestroyJavaVM(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002070 }
2071
2072 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002073 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002074 sc.Check(true, "vpp", vm, p_env, thr_args);
2075 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002076 }
2077
2078 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002079 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002080 sc.Check(true, "vpp", vm, p_env, thr_args);
2081 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002082 }
2083
2084 static jint DetachCurrentThread(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002085 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002086 sc.Check(true, "v", vm);
2087 return CHECK_JNI_EXIT("I", BaseVm(vm)->DetachCurrentThread(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002088 }
2089
2090 static jint GetEnv(JavaVM* vm, void** env, jint version) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002091 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002092 sc.Check(true, "v", vm);
2093 return CHECK_JNI_EXIT("I", BaseVm(vm)->GetEnv(vm, env, version));
Elliott Hughesa2501992011-08-26 19:39:54 -07002094 }
2095
2096 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002097 static inline const JNIInvokeInterface* BaseVm(JavaVM* vm) {
Elliott Hughesa2501992011-08-26 19:39:54 -07002098 return reinterpret_cast<JavaVMExt*>(vm)->unchecked_functions;
2099 }
2100};
2101
2102const JNIInvokeInterface gCheckInvokeInterface = {
2103 NULL, // reserved0
2104 NULL, // reserved1
2105 NULL, // reserved2
2106 CheckJII::DestroyJavaVM,
2107 CheckJII::AttachCurrentThread,
2108 CheckJII::DetachCurrentThread,
2109 CheckJII::GetEnv,
2110 CheckJII::AttachCurrentThreadAsDaemon
2111};
2112
2113const JNIInvokeInterface* GetCheckJniInvokeInterface() {
2114 return &gCheckInvokeInterface;
2115}
2116
2117} // namespace art