blob: 6dc47f76a23865fdb0007b6d5eaf4a7b44c26c55 [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 Hughesa2501992011-08-26 19:39:54 -070026#include "thread.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070027#include "runtime.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070028
Elliott Hughese6087632011-09-26 12:18:25 -070029#define LIBCORE_CPP_JNI_HELPERS
30#include <JNIHelp.h> // from libcore
31#undef LIBCORE_CPP_JNI_HELPERS
32
Elliott Hughesa2501992011-08-26 19:39:54 -070033namespace art {
34
35void JniAbort(const char* jni_function_name) {
Elliott Hughesa0957642011-09-02 14:27:33 -070036 Thread* self = Thread::Current();
Elliott Hughesd07986f2011-12-06 18:27:45 -080037 Method* current_method = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -070038
Elliott Hughes3b6baaa2011-10-14 19:13:56 -070039 std::ostringstream os;
Elliott Hughese6087632011-09-26 12:18:25 -070040 os << "Aborting because JNI app bug detected (see above for details)";
Elliott Hughesa2501992011-08-26 19:39:54 -070041
42 if (jni_function_name != NULL) {
43 os << "\n in call to " << jni_function_name;
44 }
Elliott Hughesa0957642011-09-02 14:27:33 -070045 // TODO: is this useful given that we're about to dump the calling thread's stack?
46 if (current_method != NULL) {
47 os << "\n from " << PrettyMethod(current_method);
48 }
49 os << "\n";
50 self->Dump(os);
Elliott Hughesa2501992011-08-26 19:39:54 -070051
52 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
53 if (vm->check_jni_abort_hook != NULL) {
54 vm->check_jni_abort_hook(os.str());
55 } else {
56 LOG(FATAL) << os.str();
57 }
58}
59
60/*
61 * ===========================================================================
62 * JNI function helpers
63 * ===========================================================================
64 */
65
Ian Rogers959f8ed2012-02-07 16:33:37 -080066static bool IsSirtLocalRef(JNIEnv* env, jobject localRef) {
67 return GetIndirectRefKind(localRef) == kSirtOrInvalid &&
68 reinterpret_cast<JNIEnvExt*>(env)->self->SirtContains(localRef);
69}
70
Elliott Hughesa2501992011-08-26 19:39:54 -070071template<typename T>
72T Decode(ScopedJniThreadState& ts, jobject obj) {
73 return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
74}
75
Elliott Hughesa2501992011-08-26 19:39:54 -070076/*
77 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
78 * The code deliberately uses an invalid sequence of operations, so we
79 * need to pass it through unmodified. Review that code before making
80 * any changes here.
81 */
82#define kNoCopyMagic 0xd5aab57f
83
84/*
85 * Flags passed into ScopedCheck.
86 */
87#define kFlag_Default 0x0000
88
89#define kFlag_CritBad 0x0000 /* calling while in critical is bad */
90#define kFlag_CritOkay 0x0001 /* ...okay */
91#define kFlag_CritGet 0x0002 /* this is a critical "get" */
92#define kFlag_CritRelease 0x0003 /* this is a critical "release" */
93#define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */
94
95#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */
96#define kFlag_ExcepOkay 0x0004 /* ...okay */
97
98#define kFlag_Release 0x0010 /* are we in a non-critical release function? */
99#define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */
100
101#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */
102
Elliott Hughes485cac42011-12-09 17:49:35 -0800103#define kFlag_ForceTrace 0x80000000 // Add this to a JNI function's flags if you want to trace every call.
104
Elliott Hughesa0957642011-09-02 14:27:33 -0700105static const char* gBuiltInPrefixes[] = {
106 "Landroid/",
107 "Lcom/android/",
108 "Lcom/google/android/",
109 "Ldalvik/",
110 "Ljava/",
111 "Ljavax/",
112 "Llibcore/",
113 "Lorg/apache/harmony/",
114 NULL
115};
116
117bool ShouldTrace(JavaVMExt* vm, const Method* method) {
118 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
119 // when a native method that matches the -Xjnitrace argument calls a JNI function
120 // such as NewByteArray.
121 // If -verbose:third-party-jni is on, we want to log any JNI function calls
122 // made by a third-party native method.
Elliott Hughesf1a5adc2012-02-10 18:09:35 -0800123 std::string className(MethodHelper(method).GetDeclaringClassDescriptor());
124 if (!vm->trace.empty() && className.find(vm->trace) != std::string::npos) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700125 return true;
126 }
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800127 if (VLOG_IS_ON(third_party_jni)) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700128 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
129 // like part of Android.
Elliott Hughesa0957642011-09-02 14:27:33 -0700130 for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) {
Elliott Hughesf1a5adc2012-02-10 18:09:35 -0800131 if (StartsWith(className, gBuiltInPrefixes[i])) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700132 return false;
133 }
134 }
135 return true;
136 }
137 return false;
138}
139
Elliott Hughesa2501992011-08-26 19:39:54 -0700140class ScopedCheck {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800141 public:
Elliott Hughesa2501992011-08-26 19:39:54 -0700142 // For JNIEnv* functions.
143 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700144 Init(env, reinterpret_cast<JNIEnvExt*>(env)->vm, flags, functionName, true);
145 CheckThread(flags);
Elliott Hughesa2501992011-08-26 19:39:54 -0700146 }
147
148 // For JavaVM* functions.
Elliott Hughesa0957642011-09-02 14:27:33 -0700149 explicit ScopedCheck(JavaVM* vm, bool hasMethod, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700150 Init(NULL, vm, kFlag_Invocation, functionName, hasMethod);
Elliott Hughesa2501992011-08-26 19:39:54 -0700151 }
152
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700153 bool ForceCopy() {
Elliott Hughesa2501992011-08-26 19:39:54 -0700154 return Runtime::Current()->GetJavaVM()->force_copy;
155 }
156
157 /*
158 * In some circumstances the VM will screen class names, but it doesn't
159 * for class lookup. When things get bounced through a class loader, they
160 * can actually get normalized a couple of times; as a result, passing in
161 * a class name like "java.lang.Thread" instead of "java/lang/Thread" will
162 * work in some circumstances.
163 *
164 * This is incorrect and could cause strange behavior or compatibility
165 * problems, so we want to screen that out here.
166 *
167 * We expect "fully-qualified" class names, like "java/lang/Thread" or
168 * "[Ljava/lang/Object;".
169 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700170 void CheckClassName(const char* className) {
Elliott Hughes906e6852011-10-28 14:52:10 -0700171 if (!IsValidJniClassName(className)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700172 LOG(ERROR) << "JNI ERROR: illegal class name '" << className << "' (" << function_name_ << ")\n"
Elliott Hughesa2501992011-08-26 19:39:54 -0700173 << " (should be of the form 'java/lang/String', [Ljava/lang/String;' or '[[B')\n";
174 JniAbort();
175 }
176 }
177
178 /*
179 * Verify that the field is of the appropriate type. If the field has an
180 * object type, "java_object" is the object we're trying to assign into it.
181 *
182 * Works for both static and instance fields.
183 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700184 void CheckFieldType(jobject java_object, jfieldID fid, char prim, bool isStatic) {
185 ScopedJniThreadState ts(env_);
186 Field* f = CheckFieldID(fid);
187 if (f == NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700188 return;
189 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800190 Class* field_type = FieldHelper(f).GetType();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700191 if (!field_type->IsPrimitive()) {
192 if (java_object != NULL) {
193 Object* obj = Decode<Object*>(ts, java_object);
194 /*
195 * If java_object is a weak global ref whose referent has been cleared,
196 * obj will be NULL. Otherwise, obj should always be non-NULL
197 * and valid.
198 */
199 if (obj != NULL && !Heap::IsHeapAddress(obj)) {
200 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
Elliott Hughesa2501992011-08-26 19:39:54 -0700201 JniAbort();
202 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700203 } else {
Brian Carlstrom16192862011-09-12 17:50:06 -0700204 if (!obj->InstanceOf(field_type)) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700205 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << PrettyTypeOf(obj);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700206 JniAbort();
207 return;
208 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700209 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700210 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700211 } else if (field_type != Runtime::Current()->GetClassLinker()->FindPrimitiveClass(prim)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700212 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << prim;
213 JniAbort();
214 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700215 }
216
217 if (isStatic && !f->IsStatic()) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700218 if (isStatic) {
219 LOG(ERROR) << "JNI ERROR: accessing non-static field " << PrettyField(f) << " as static";
220 } else {
221 LOG(ERROR) << "JNI ERROR: accessing static field " << PrettyField(f) << " as non-static";
222 }
223 JniAbort();
224 return;
225 }
226 }
227
228 /*
229 * Verify that this instance field ID is valid for this object.
230 *
231 * Assumes "jobj" has already been validated.
232 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700233 void CheckInstanceFieldID(jobject java_object, jfieldID fid) {
234 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700235
236 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700237 if (o == NULL || !Heap::IsHeapAddress(o)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700238 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
239 JniAbort();
240 return;
241 }
242
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700243 Field* f = CheckFieldID(fid);
244 if (f == NULL) {
245 return;
246 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700247 Class* c = o->GetClass();
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800248 FieldHelper fh(f);
249 if (c->FindInstanceField(fh.GetName(), fh.GetTypeDescriptor()) == NULL) {
Elliott Hughes906e6852011-10-28 14:52:10 -0700250 LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f)
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700251 << " not valid for an object of class " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700252 JniAbort();
253 }
254 }
255
256 /*
257 * Verify that the pointer value is non-NULL.
258 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700259 void CheckNonNull(const void* ptr) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700260 if (ptr == NULL) {
261 LOG(ERROR) << "JNI ERROR: invalid null pointer";
262 JniAbort();
263 }
264 }
265
266 /*
267 * Verify that the method's return type matches the type of call.
268 * 'expectedType' will be "L" for all objects, including arrays.
269 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700270 void CheckSig(jmethodID mid, const char* expectedType, bool isStatic) {
271 ScopedJniThreadState ts(env_);
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800272 Method* m = CheckMethodID(mid);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700273 if (m == NULL) {
274 return;
275 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800276 if (*expectedType != MethodHelper(m).GetShorty()[0]) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700277 LOG(ERROR) << "JNI ERROR: the return type of " << function_name_ << " does not match "
278 << PrettyMethod(m);
Elliott Hughesa2501992011-08-26 19:39:54 -0700279 JniAbort();
280 } else if (isStatic && !m->IsStatic()) {
281 if (isStatic) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700282 LOG(ERROR) << "JNI ERROR: calling non-static method "
283 << PrettyMethod(m) << " with " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700284 } else {
Elliott Hughes726079d2011-10-07 18:43:44 -0700285 LOG(ERROR) << "JNI ERROR: calling static method "
286 << PrettyMethod(m) << " with non-static " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700287 }
288 JniAbort();
289 }
290 }
291
292 /*
293 * Verify that this static field ID is valid for this class.
294 *
295 * Assumes "java_class" has already been validated.
296 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700297 void CheckStaticFieldID(jclass java_class, jfieldID fid) {
298 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700299 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700300 const Field* f = CheckFieldID(fid);
301 if (f == NULL) {
302 return;
303 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700304 if (f->GetDeclaringClass() != c) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700305 LOG(ERROR) << "JNI ERROR: static jfieldID " << fid << " not valid for class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700306 JniAbort();
307 }
308 }
309
310 /*
311 * Verify that "mid" is appropriate for "clazz".
312 *
313 * A mismatch isn't dangerous, because the jmethodID defines the class. In
314 * fact, jclazz is unused in the implementation. It's best if we don't
315 * allow bad code in the system though.
316 *
317 * Instances of "jclazz" must be instances of the method's declaring class.
318 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700319 void CheckStaticMethod(jclass java_class, jmethodID mid) {
320 ScopedJniThreadState ts(env_);
321 const Method* m = CheckMethodID(mid);
322 if (m == NULL) {
323 return;
324 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700325 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughesa2501992011-08-26 19:39:54 -0700326 if (!c->IsAssignableFrom(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700327 LOG(ERROR) << "JNI ERROR: can't call static " << PrettyMethod(m) << " on class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700328 JniAbort();
329 }
330 }
331
332 /*
333 * Verify that "mid" is appropriate for "jobj".
334 *
335 * Make sure the object is an instance of the method's declaring class.
336 * (Note the mid might point to a declaration in an interface; this
337 * will be handled automatically by the instanceof check.)
338 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700339 void CheckVirtualMethod(jobject java_object, jmethodID mid) {
340 ScopedJniThreadState ts(env_);
341 const Method* m = CheckMethodID(mid);
342 if (m == NULL) {
343 return;
344 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700345 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesa2501992011-08-26 19:39:54 -0700346 if (!o->InstanceOf(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700347 LOG(ERROR) << "JNI ERROR: can't call " << PrettyMethod(m) << " on instance of " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700348 JniAbort();
349 }
350 }
351
352 /**
353 * The format string is a sequence of the following characters,
354 * and must be followed by arguments of the corresponding types
355 * in the same order.
356 *
357 * Java primitive types:
358 * B - jbyte
359 * C - jchar
360 * D - jdouble
361 * F - jfloat
362 * I - jint
363 * J - jlong
364 * S - jshort
365 * Z - jboolean (shown as true and false)
366 * V - void
367 *
368 * Java reference types:
369 * L - jobject
370 * a - jarray
371 * c - jclass
372 * s - jstring
373 *
374 * JNI types:
375 * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
376 * f - jfieldID
377 * m - jmethodID
378 * p - void*
379 * r - jint (for release mode arguments)
Elliott Hughes78090d12011-10-07 14:31:47 -0700380 * u - const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700381 * z - jsize (for lengths; use i if negative values are okay)
382 * v - JavaVM*
383 * E - JNIEnv*
384 * . - no argument; just print "..." (used for varargs JNI calls)
385 *
386 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
387 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700388 void Check(bool entry, const char* fmt0, ...) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700389 va_list ap;
390
Elliott Hughesa0957642011-09-02 14:27:33 -0700391 const Method* traceMethod = NULL;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800392 if ((!vm_->trace.empty() || VLOG_IS_ON(third_party_jni)) && has_method_) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700393 // We need to guard some of the invocation interface's calls: a bad caller might
394 // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
Elliott Hughesa0957642011-09-02 14:27:33 -0700395 Thread* self = Thread::Current();
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700396 if ((flags_ & kFlag_Invocation) == 0 || self != NULL) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700397 traceMethod = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -0700398 }
399 }
Elliott Hughesa0957642011-09-02 14:27:33 -0700400
Elliott Hughes485cac42011-12-09 17:49:35 -0800401 if (((flags_ & kFlag_ForceTrace) != 0) || (traceMethod != NULL && ShouldTrace(vm_, traceMethod))) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700402 va_start(ap, fmt0);
403 std::string msg;
404 for (const char* fmt = fmt0; *fmt;) {
405 char ch = *fmt++;
406 if (ch == 'B') { // jbyte
407 jbyte b = va_arg(ap, int);
408 if (b >= 0 && b < 10) {
409 StringAppendF(&msg, "%d", b);
410 } else {
411 StringAppendF(&msg, "%#x (%d)", b, b);
412 }
413 } else if (ch == 'C') { // jchar
414 jchar c = va_arg(ap, int);
415 if (c < 0x7f && c >= ' ') {
416 StringAppendF(&msg, "U+%x ('%c')", c, c);
417 } else {
418 StringAppendF(&msg, "U+%x", c);
419 }
420 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
421 StringAppendF(&msg, "%g", va_arg(ap, double));
422 } else if (ch == 'I' || ch == 'S') { // jint, jshort
423 StringAppendF(&msg, "%d", va_arg(ap, int));
424 } else if (ch == 'J') { // jlong
425 StringAppendF(&msg, "%lld", va_arg(ap, jlong));
426 } else if (ch == 'Z') { // jboolean
427 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
428 } else if (ch == 'V') { // void
429 msg += "void";
430 } else if (ch == 'v') { // JavaVM*
431 JavaVM* vm = va_arg(ap, JavaVM*);
432 StringAppendF(&msg, "(JavaVM*)%p", vm);
433 } else if (ch == 'E') { // JNIEnv*
434 JNIEnv* env = va_arg(ap, JNIEnv*);
435 StringAppendF(&msg, "(JNIEnv*)%p", env);
436 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
437 // For logging purposes, these are identical.
438 jobject o = va_arg(ap, jobject);
439 if (o == NULL) {
440 msg += "NULL";
441 } else {
442 StringAppendF(&msg, "%p", o);
443 }
444 } else if (ch == 'b') { // jboolean (JNI-style)
445 jboolean b = va_arg(ap, int);
446 msg += (b ? "JNI_TRUE" : "JNI_FALSE");
447 } else if (ch == 'c') { // jclass
448 jclass jc = va_arg(ap, jclass);
449 Class* c = reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(jc));
450 if (c == NULL) {
451 msg += "NULL";
452 } else if (c == kInvalidIndirectRefObject || !Heap::IsHeapAddress(c)) {
Elliott Hughes485cac42011-12-09 17:49:35 -0800453 StringAppendF(&msg, "INVALID POINTER:%p", jc);
454 } else if (!c->IsClass()) {
455 msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700456 } else {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700457 msg += PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700458 if (!entry) {
459 StringAppendF(&msg, " (%p)", jc);
460 }
461 }
462 } else if (ch == 'f') { // jfieldID
463 jfieldID fid = va_arg(ap, jfieldID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700464 Field* f = reinterpret_cast<Field*>(fid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700465 msg += PrettyField(f);
466 if (!entry) {
467 StringAppendF(&msg, " (%p)", fid);
468 }
469 } else if (ch == 'z') { // non-negative jsize
470 // You might expect jsize to be size_t, but it's not; it's the same as jint.
471 // We only treat this specially so we can do the non-negative check.
472 // TODO: maybe this wasn't worth it?
473 jint i = va_arg(ap, jint);
474 StringAppendF(&msg, "%d", i);
475 } else if (ch == 'm') { // jmethodID
476 jmethodID mid = va_arg(ap, jmethodID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700477 Method* m = reinterpret_cast<Method*>(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700478 msg += PrettyMethod(m);
479 if (!entry) {
480 StringAppendF(&msg, " (%p)", mid);
481 }
482 } else if (ch == 'p') { // void* ("pointer")
483 void* p = va_arg(ap, void*);
484 if (p == NULL) {
485 msg += "NULL";
486 } else {
487 StringAppendF(&msg, "(void*) %p", p);
488 }
489 } else if (ch == 'r') { // jint (release mode)
490 jint releaseMode = va_arg(ap, jint);
491 if (releaseMode == 0) {
492 msg += "0";
493 } else if (releaseMode == JNI_ABORT) {
494 msg += "JNI_ABORT";
495 } else if (releaseMode == JNI_COMMIT) {
496 msg += "JNI_COMMIT";
497 } else {
498 StringAppendF(&msg, "invalid release mode %d", releaseMode);
499 }
Elliott Hughes78090d12011-10-07 14:31:47 -0700500 } else if (ch == 'u') { // const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700501 const char* utf = va_arg(ap, const char*);
502 if (utf == NULL) {
503 msg += "NULL";
504 } else {
505 StringAppendF(&msg, "\"%s\"", utf);
506 }
507 } else if (ch == '.') {
508 msg += "...";
509 } else {
510 LOG(ERROR) << "unknown trace format specifier: " << ch;
511 JniAbort();
512 return;
513 }
514 if (*fmt) {
515 StringAppendF(&msg, ", ");
516 }
517 }
518 va_end(ap);
519
Elliott Hughes485cac42011-12-09 17:49:35 -0800520 if ((flags_ & kFlag_ForceTrace) != 0) {
521 LOG(INFO) << "JNI: call to " << function_name_ << "(" << msg << ")";
522 } else if (entry) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700523 if (has_method_) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700524 std::string methodName(PrettyMethod(traceMethod, false));
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700525 LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
526 indent_ = methodName.size() + 1;
Elliott Hughesa2501992011-08-26 19:39:54 -0700527 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700528 LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
529 indent_ = 0;
Elliott Hughesa2501992011-08-26 19:39:54 -0700530 }
531 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700532 LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
Elliott Hughesa2501992011-08-26 19:39:54 -0700533 }
534 }
535
536 // We always do the thorough checks on entry, and never on exit...
537 if (entry) {
538 va_start(ap, fmt0);
539 for (const char* fmt = fmt0; *fmt; ++fmt) {
540 char ch = *fmt;
541 if (ch == 'a') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700542 CheckArray(va_arg(ap, jarray));
Elliott Hughesa2501992011-08-26 19:39:54 -0700543 } else if (ch == 'c') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700544 CheckInstance(kClass, va_arg(ap, jclass));
Elliott Hughesa2501992011-08-26 19:39:54 -0700545 } else if (ch == 'L') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700546 CheckObject(va_arg(ap, jobject));
Elliott Hughesa2501992011-08-26 19:39:54 -0700547 } else if (ch == 'r') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700548 CheckReleaseMode(va_arg(ap, jint));
Elliott Hughesa2501992011-08-26 19:39:54 -0700549 } else if (ch == 's') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700550 CheckInstance(kString, va_arg(ap, jstring));
Elliott Hughesa2501992011-08-26 19:39:54 -0700551 } else if (ch == 'u') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700552 if ((flags_ & kFlag_Release) != 0) {
553 CheckNonNull(va_arg(ap, const char*));
Elliott Hughesa2501992011-08-26 19:39:54 -0700554 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700555 bool nullable = ((flags_ & kFlag_NullableUtf) != 0);
556 CheckUtfString(va_arg(ap, const char*), nullable);
Elliott Hughesa2501992011-08-26 19:39:54 -0700557 }
558 } else if (ch == 'z') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700559 CheckLengthPositive(va_arg(ap, jsize));
Elliott Hughesa2501992011-08-26 19:39:54 -0700560 } else if (strchr("BCISZbfmpEv", ch) != NULL) {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800561 va_arg(ap, uint32_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700562 } else if (ch == 'D' || ch == 'F') {
563 va_arg(ap, double); // Skip this argument.
564 } else if (ch == 'J') {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800565 va_arg(ap, uint64_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700566 } else if (ch == '.') {
567 } else {
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800568 LOG(FATAL) << "Unknown check format specifier: " << ch;
Elliott Hughesa2501992011-08-26 19:39:54 -0700569 }
570 }
571 va_end(ap);
572 }
573 }
574
Elliott Hughesa92853e2012-02-07 16:09:27 -0800575 enum InstanceKind {
576 kClass,
577 kDirectByteBuffer,
578 kObject,
579 kString,
580 kThrowable,
581 };
582
583 /*
584 * Verify that "jobj" is a valid non-NULL object reference, and points to
585 * an instance of expectedClass.
586 *
587 * Because we're looking at an object on the GC heap, we have to switch
588 * to "running" mode before doing the checks.
589 */
590 bool CheckInstance(InstanceKind kind, jobject java_object) {
591 const char* what = NULL;
592 switch (kind) {
593 case kClass:
594 what = "jclass";
595 break;
596 case kDirectByteBuffer:
597 what = "direct ByteBuffer";
598 break;
599 case kObject:
600 what = "jobject";
601 break;
602 case kString:
603 what = "jstring";
604 break;
605 case kThrowable:
606 what = "jthrowable";
607 break;
608 default:
609 CHECK(false) << static_cast<int>(kind);
610 }
611
612 if (java_object == NULL) {
613 LOG(ERROR) << "JNI ERROR: " << function_name_ << " received null " << what;
614 JniAbort();
615 return false;
616 }
617
618 ScopedJniThreadState ts(env_);
619 Object* obj = Decode<Object*>(ts, java_object);
620 if (!Heap::IsHeapAddress(obj)) {
621 LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
622 JniAbort();
623 return false;
624 }
625
626 bool okay = true;
627 switch (kind) {
628 case kClass:
629 okay = obj->IsClass();
630 break;
631 case kDirectByteBuffer:
632 UNIMPLEMENTED(FATAL);
633 break;
634 case kString:
635 okay = obj->GetClass()->IsStringClass();
636 break;
637 case kThrowable:
638 okay = obj->GetClass()->IsThrowableClass();
639 break;
640 case kObject:
641 break;
642 }
643 if (!okay) {
644 LOG(ERROR) << "JNI ERROR: " << what << " has wrong type: " << PrettyTypeOf(obj);
645 JniAbort();
646 return false;
647 }
648
649 return true;
650 }
651
Elliott Hughesba8eee12012-01-24 20:25:24 -0800652 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700653 void Init(JNIEnv* env, JavaVM* vm, int flags, const char* functionName, bool hasMethod) {
654 env_ = reinterpret_cast<JNIEnvExt*>(env);
655 vm_ = reinterpret_cast<JavaVMExt*>(vm);
656 flags_ = flags;
657 function_name_ = functionName;
Elliott Hughesa2501992011-08-26 19:39:54 -0700658
659 // Set "hasMethod" to true if we have a valid thread with a method pointer.
660 // We won't have one before attaching a thread, after detaching a thread, or
661 // after destroying the VM.
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700662 has_method_ = hasMethod;
Elliott Hughesa2501992011-08-26 19:39:54 -0700663 }
664
665 /*
666 * Verify that "array" is non-NULL and points to an Array object.
667 *
668 * Since we're dealing with objects, switch to "running" mode.
669 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700670 void CheckArray(jarray java_array) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700671 if (java_array == NULL) {
672 LOG(ERROR) << "JNI ERROR: received null array";
673 JniAbort();
674 return;
675 }
676
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700677 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700678 Array* a = Decode<Array*>(ts, java_array);
679 if (!Heap::IsHeapAddress(a)) {
680 LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array);
681 JniAbort();
682 } else if (!a->IsArrayInstance()) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700683 LOG(ERROR) << "JNI ERROR: jarray argument has non-array type: " << PrettyTypeOf(a);
Elliott Hughesa2501992011-08-26 19:39:54 -0700684 JniAbort();
685 }
686 }
687
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700688 void CheckLengthPositive(jsize length) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700689 if (length < 0) {
690 LOG(ERROR) << "JNI ERROR: negative jsize: " << length;
691 JniAbort();
692 }
693 }
694
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700695 Field* CheckFieldID(jfieldID fid) {
696 if (fid == NULL) {
697 LOG(ERROR) << "JNI ERROR: null jfieldID";
698 JniAbort();
699 return NULL;
700 }
701 Field* f = DecodeField(fid);
702 if (!Heap::IsHeapAddress(f)) {
703 LOG(ERROR) << "JNI ERROR: invalid jfieldID: " << fid;
704 JniAbort();
705 return NULL;
706 }
707 return f;
708 }
709
710 Method* CheckMethodID(jmethodID mid) {
711 if (mid == NULL) {
712 LOG(ERROR) << "JNI ERROR: null jmethodID";
713 JniAbort();
714 return NULL;
715 }
716 Method* m = DecodeMethod(mid);
717 if (!Heap::IsHeapAddress(m)) {
718 LOG(ERROR) << "JNI ERROR: invalid jmethodID: " << mid;
719 JniAbort();
720 return NULL;
721 }
722 return m;
723 }
724
Elliott Hughesa2501992011-08-26 19:39:54 -0700725 /*
726 * Verify that "jobj" is a valid object, and that it's an object that JNI
727 * is allowed to know about. We allow NULL references.
728 *
729 * Switches to "running" mode before performing checks.
730 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700731 void CheckObject(jobject java_object) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700732 if (java_object == NULL) {
733 return;
734 }
735
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700736 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700737
738 Object* o = Decode<Object*>(ts, java_object);
739 if (o != NULL && !Heap::IsHeapAddress(o)) {
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700740 // TODO: when we remove work_around_app_jni_bugs, this should be impossible.
Elliott Hughesa2501992011-08-26 19:39:54 -0700741 LOG(ERROR) << "JNI ERROR: native code passing in reference to invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
742 JniAbort();
743 }
744 }
745
746 /*
747 * Verify that the "mode" argument passed to a primitive array Release
748 * function is one of the valid values.
749 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700750 void CheckReleaseMode(jint mode) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700751 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
752 LOG(ERROR) << "JNI ERROR: bad value for release mode: " << mode;
753 JniAbort();
754 }
755 }
756
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700757 void CheckThread(int flags) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700758 Thread* self = Thread::Current();
759 if (self == NULL) {
760 LOG(ERROR) << "JNI ERROR: non-VM thread making JNI calls";
761 JniAbort();
762 return;
763 }
764
765 // Get the *correct* JNIEnv by going through our TLS pointer.
766 JNIEnvExt* threadEnv = self->GetJniEnv();
767
768 /*
769 * Verify that the current thread is (a) attached and (b) associated with
770 * this particular instance of JNIEnv.
771 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700772 if (env_ != threadEnv) {
773 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNIEnv* from thread " << *env_->self;
Elliott Hughesa2501992011-08-26 19:39:54 -0700774 // If we're keeping broken code limping along, we need to suppress the abort...
Elliott Hughesc2dc62d2012-01-17 20:06:12 -0800775 if (!vm_->work_around_app_jni_bugs) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700776 JniAbort();
777 return;
778 }
779 }
780
781 /*
782 * Verify that, if this thread previously made a critical "get" call, we
783 * do the corresponding "release" call before we try anything else.
784 */
785 switch (flags & kFlag_CritMask) {
786 case kFlag_CritOkay: // okay to call this method
787 break;
788 case kFlag_CritBad: // not okay to call
789 if (threadEnv->critical) {
790 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNI after critical get";
791 JniAbort();
792 return;
793 }
794 break;
795 case kFlag_CritGet: // this is a "get" call
796 /* don't check here; we allow nested gets */
797 threadEnv->critical++;
798 break;
799 case kFlag_CritRelease: // this is a "release" call
800 threadEnv->critical--;
801 if (threadEnv->critical < 0) {
802 LOG(ERROR) << "JNI ERROR: thread " << *self << " called too many critical releases";
803 JniAbort();
804 return;
805 }
806 break;
807 default:
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800808 LOG(FATAL) << "Bad flags (internal error): " << flags;
Elliott Hughesa2501992011-08-26 19:39:54 -0700809 }
810
811 /*
812 * Verify that, if an exception has been raised, the native code doesn't
813 * make any JNI calls other than the Exception* methods.
814 */
815 if ((flags & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
Elliott Hughes30646832011-10-13 16:59:46 -0700816 std::string type(PrettyTypeOf(self->GetException()));
817 LOG(ERROR) << "JNI ERROR: JNI " << function_name_ << " called with " << type << " pending";
818 // TODO: write native code that doesn't require allocation for dumping an exception.
819 if (type != "java.lang.OutOfMemoryError") {
820 LOG(ERROR) << "Pending exception is: ";
821 LOG(ERROR) << jniGetStackTrace(env_);
822 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700823 JniAbort();
824 return;
825 }
826 }
827
828 /*
Elliott Hughes78090d12011-10-07 14:31:47 -0700829 * Verify that "bytes" points to valid Modified UTF-8 data.
Elliott Hughesa2501992011-08-26 19:39:54 -0700830 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700831 void CheckUtfString(const char* bytes, bool nullable) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700832 if (bytes == NULL) {
833 if (!nullable) {
834 LOG(ERROR) << "JNI ERROR: non-nullable const char* was NULL";
835 JniAbort();
836 return;
837 }
838 return;
839 }
840
841 const char* errorKind = NULL;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700842 uint8_t utf8 = CheckUtfBytes(bytes, &errorKind);
Elliott Hughesa2501992011-08-26 19:39:54 -0700843 if (errorKind != NULL) {
Elliott Hughes78090d12011-10-07 14:31:47 -0700844 LOG(ERROR) << "JNI ERROR: input is not valid Modified UTF-8: "
845 << "illegal " << errorKind << " byte " << StringPrintf("%#x", utf8) << "\n"
846 << " string: '" << bytes << "'";
Elliott Hughesa2501992011-08-26 19:39:54 -0700847 JniAbort();
848 return;
849 }
850 }
851
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700852 static uint8_t CheckUtfBytes(const char* bytes, const char** errorKind) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700853 while (*bytes != '\0') {
854 uint8_t utf8 = *(bytes++);
855 // Switch on the high four bits.
856 switch (utf8 >> 4) {
857 case 0x00:
858 case 0x01:
859 case 0x02:
860 case 0x03:
861 case 0x04:
862 case 0x05:
863 case 0x06:
864 case 0x07:
865 // Bit pattern 0xxx. No need for any extra bytes.
866 break;
867 case 0x08:
868 case 0x09:
869 case 0x0a:
870 case 0x0b:
871 case 0x0f:
872 /*
873 * Bit pattern 10xx or 1111, which are illegal start bytes.
874 * Note: 1111 is valid for normal UTF-8, but not the
Elliott Hughes78090d12011-10-07 14:31:47 -0700875 * Modified UTF-8 used here.
Elliott Hughesa2501992011-08-26 19:39:54 -0700876 */
877 *errorKind = "start";
878 return utf8;
879 case 0x0e:
880 // Bit pattern 1110, so there are two additional bytes.
881 utf8 = *(bytes++);
882 if ((utf8 & 0xc0) != 0x80) {
883 *errorKind = "continuation";
884 return utf8;
885 }
886 // Fall through to take care of the final byte.
887 case 0x0c:
888 case 0x0d:
889 // Bit pattern 110x, so there is one additional byte.
890 utf8 = *(bytes++);
891 if ((utf8 & 0xc0) != 0x80) {
892 *errorKind = "continuation";
893 return utf8;
894 }
895 break;
896 }
897 }
898 return 0;
899 }
900
901 void JniAbort() {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700902 ::art::JniAbort(function_name_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700903 }
904
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700905 JNIEnvExt* env_;
906 JavaVMExt* vm_;
907 const char* function_name_;
908 int flags_;
909 bool has_method_;
Elliott Hughes92cb4982011-12-16 16:57:28 -0800910 int indent_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700911
912 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
913};
914
915#define CHECK_JNI_ENTRY(flags, types, args...) \
916 ScopedCheck sc(env, flags, __FUNCTION__); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700917 sc.Check(true, types, ##args)
Elliott Hughesa2501992011-08-26 19:39:54 -0700918
919#define CHECK_JNI_EXIT(type, exp) ({ \
Elliott Hughes362f9bc2011-10-17 18:56:41 -0700920 typeof(exp) _rc = (exp); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700921 sc.Check(false, type, _rc); \
Elliott Hughesa2501992011-08-26 19:39:54 -0700922 _rc; })
923#define CHECK_JNI_EXIT_VOID() \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700924 sc.Check(false, "V")
Elliott Hughesa2501992011-08-26 19:39:54 -0700925
926/*
927 * ===========================================================================
928 * Guarded arrays
929 * ===========================================================================
930 */
931
932#define kGuardLen 512 /* must be multiple of 2 */
933#define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */
934#define kGuardMagic 0xffd5aa96
935
936/* this gets tucked in at the start of the buffer; struct size must be even */
937struct GuardedCopy {
938 uint32_t magic;
939 uLong adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700940 size_t original_length;
941 const void* original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700942
943 /* find the GuardedCopy given the pointer into the "live" data */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700944 static inline const GuardedCopy* FromData(const void* dataBuf) {
945 return reinterpret_cast<const GuardedCopy*>(ActualBuffer(dataBuf));
Elliott Hughesa2501992011-08-26 19:39:54 -0700946 }
947
948 /*
949 * Create an over-sized buffer to hold the contents of "buf". Copy it in,
950 * filling in the area around it with guard data.
951 *
952 * We use a 16-bit pattern to make a rogue memset less likely to elude us.
953 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700954 static void* Create(const void* buf, size_t len, bool modOkay) {
955 size_t newLen = ActualLength(len);
956 uint8_t* newBuf = DebugAlloc(newLen);
Elliott Hughesa2501992011-08-26 19:39:54 -0700957
958 /* fill it in with a pattern */
Elliott Hughesba8eee12012-01-24 20:25:24 -0800959 uint16_t* pat = reinterpret_cast<uint16_t*>(newBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -0700960 for (size_t i = 0; i < newLen / 2; i++) {
961 *pat++ = kGuardPattern;
962 }
963
964 /* copy the data in; note "len" could be zero */
965 memcpy(newBuf + kGuardLen / 2, buf, len);
966
967 /* if modification is not expected, grab a checksum */
968 uLong adler = 0;
969 if (!modOkay) {
970 adler = adler32(0L, Z_NULL, 0);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800971 adler = adler32(adler, reinterpret_cast<const Bytef*>(buf), len);
972 *reinterpret_cast<uLong*>(newBuf) = adler;
Elliott Hughesa2501992011-08-26 19:39:54 -0700973 }
974
975 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
976 pExtra->magic = kGuardMagic;
977 pExtra->adler = adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700978 pExtra->original_ptr = buf;
979 pExtra->original_length = len;
Elliott Hughesa2501992011-08-26 19:39:54 -0700980
981 return newBuf + kGuardLen / 2;
982 }
983
984 /*
985 * Free up the guard buffer, scrub it, and return the original pointer.
986 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700987 static void* Destroy(void* dataBuf) {
988 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800989 void* original_ptr = const_cast<void*>(pExtra->original_ptr);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700990 size_t len = pExtra->original_length;
991 DebugFree(dataBuf, len);
992 return original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700993 }
994
995 /*
996 * Verify the guard area and, if "modOkay" is false, that the data itself
997 * has not been altered.
998 *
999 * The caller has already checked that "dataBuf" is non-NULL.
1000 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001001 static void Check(const char* functionName, const void* dataBuf, bool modOkay) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001002 static const uint32_t kMagicCmp = kGuardMagic;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001003 const uint8_t* fullBuf = ActualBuffer(dataBuf);
1004 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001005
1006 /*
1007 * Before we do anything with "pExtra", check the magic number. We
1008 * do the check with memcmp rather than "==" in case the pointer is
1009 * unaligned. If it points to completely bogus memory we're going
1010 * to crash, but there's no easy way around that.
1011 */
1012 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
1013 uint8_t buf[4];
1014 memcpy(buf, &pExtra->magic, 4);
1015 LOG(ERROR) << StringPrintf("JNI: guard magic does not match "
1016 "(found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
1017 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
1018 JniAbort(functionName);
1019 }
1020
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001021 size_t len = pExtra->original_length;
Elliott Hughesa2501992011-08-26 19:39:54 -07001022
1023 /* check bottom half of guard; skip over optional checksum storage */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001024 const uint16_t* pat = reinterpret_cast<const uint16_t*>(fullBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001025 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
1026 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001027 LOG(ERROR) << "JNI: guard pattern(1) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001028 JniAbort(functionName);
1029 }
1030 }
1031
1032 int offset = kGuardLen / 2 + len;
1033 if (offset & 0x01) {
1034 /* odd byte; expected value depends on endian-ness of host */
1035 const uint16_t patSample = kGuardPattern;
Elliott Hughesba8eee12012-01-24 20:25:24 -08001036 if (fullBuf[offset] != reinterpret_cast<const uint8_t*>(&patSample)[1]) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001037 LOG(ERROR) << "JNI: guard pattern disturbed in odd byte after "
Elliott Hughesba8eee12012-01-24 20:25:24 -08001038 << reinterpret_cast<const void*>(fullBuf) << " (+" << offset << ") "
Elliott Hughesa2501992011-08-26 19:39:54 -07001039 << StringPrintf("0x%02x 0x%02x", fullBuf[offset], ((const uint8_t*) &patSample)[1]);
1040 JniAbort(functionName);
1041 }
1042 offset++;
1043 }
1044
1045 /* check top half of guard */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001046 pat = reinterpret_cast<const uint16_t*>(fullBuf + offset);
Elliott Hughesa2501992011-08-26 19:39:54 -07001047 for (size_t i = 0; i < kGuardLen / 4; i++) {
1048 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001049 LOG(ERROR) << "JNI: guard pattern(2) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (offset + i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001050 JniAbort(functionName);
1051 }
1052 }
1053
1054 /*
1055 * If modification is not expected, verify checksum. Strictly speaking
1056 * this is wrong: if we told the client that we made a copy, there's no
1057 * reason they can't alter the buffer.
1058 */
1059 if (!modOkay) {
1060 uLong adler = adler32(0L, Z_NULL, 0);
1061 adler = adler32(adler, (const Bytef*)dataBuf, len);
1062 if (pExtra->adler != adler) {
1063 LOG(ERROR) << StringPrintf("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", pExtra->adler, adler, dataBuf);
1064 JniAbort(functionName);
1065 }
1066 }
1067 }
1068
1069 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001070 static uint8_t* DebugAlloc(size_t len) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001071 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1072 if (result == MAP_FAILED) {
1073 PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed";
1074 }
1075 return reinterpret_cast<uint8_t*>(result);
1076 }
1077
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001078 static void DebugFree(void* dataBuf, size_t len) {
1079 uint8_t* fullBuf = ActualBuffer(dataBuf);
1080 size_t totalByteCount = ActualLength(len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001081 // TODO: we could mprotect instead, and keep the allocation around for a while.
1082 // This would be even more expensive, but it might catch more errors.
1083 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
1084 // LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
1085 // }
1086 if (munmap(fullBuf, totalByteCount) != 0) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001087 PLOG(FATAL) << "munmap(" << reinterpret_cast<void*>(fullBuf) << ", " << totalByteCount << ") failed";
Elliott Hughesa2501992011-08-26 19:39:54 -07001088 }
1089 }
1090
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001091 static const uint8_t* ActualBuffer(const void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001092 return reinterpret_cast<const uint8_t*>(dataBuf) - kGuardLen / 2;
1093 }
1094
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001095 static uint8_t* ActualBuffer(void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001096 return reinterpret_cast<uint8_t*>(dataBuf) - kGuardLen / 2;
1097 }
1098
1099 // Underlying length of a user allocation of 'length' bytes.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001100 static size_t ActualLength(size_t length) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001101 return (length + kGuardLen + 1) & ~0x01;
1102 }
1103};
1104
1105/*
1106 * Create a guarded copy of a primitive array. Modifications to the copied
1107 * data are allowed. Returns a pointer to the copied data.
1108 */
1109void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* isCopy) {
1110 ScopedJniThreadState ts(env);
1111
1112 Array* a = Decode<Array*>(ts, java_array);
Ian Rogersa15e67d2012-02-28 13:51:55 -08001113 size_t component_size = a->GetClass()->GetComponentSize();
1114 size_t byte_count = a->GetLength() * component_size;
1115 void* result = GuardedCopy::Create(a->GetRawData(component_size), byte_count, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001116 if (isCopy != NULL) {
1117 *isCopy = JNI_TRUE;
1118 }
1119 return result;
1120}
1121
1122/*
1123 * Perform the array "release" operation, which may or may not copy data
1124 * back into the VM, and may or may not release the underlying storage.
1125 */
1126void ReleaseGuardedPACopy(JNIEnv* env, jarray java_array, void* dataBuf, int mode) {
1127 if (reinterpret_cast<uintptr_t>(dataBuf) == kNoCopyMagic) {
1128 return;
1129 }
1130
1131 ScopedJniThreadState ts(env);
1132 Array* a = Decode<Array*>(ts, java_array);
1133
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001134 GuardedCopy::Check(__FUNCTION__, dataBuf, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001135
1136 if (mode != JNI_ABORT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001137 size_t len = GuardedCopy::FromData(dataBuf)->original_length;
Ian Rogersa15e67d2012-02-28 13:51:55 -08001138 memcpy(a->GetRawData(a->GetClass()->GetComponentSize()), dataBuf, len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001139 }
1140 if (mode != JNI_COMMIT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001141 GuardedCopy::Destroy(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001142 }
1143}
1144
1145/*
1146 * ===========================================================================
1147 * JNI functions
1148 * ===========================================================================
1149 */
1150
1151class CheckJNI {
1152 public:
1153 static jint GetVersion(JNIEnv* env) {
1154 CHECK_JNI_ENTRY(kFlag_Default, "E", env);
1155 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
1156 }
1157
1158 static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf, jsize bufLen) {
1159 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001160 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001161 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
1162 }
1163
1164 static jclass FindClass(JNIEnv* env, const char* name) {
1165 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001166 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001167 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
1168 }
1169
1170 static jclass GetSuperclass(JNIEnv* env, jclass clazz) {
1171 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1172 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz));
1173 }
1174
1175 static jboolean IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) {
1176 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2);
1177 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2));
1178 }
1179
1180 static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
1181 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
1182 // TODO: check that 'field' is a java.lang.reflect.Method.
1183 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
1184 }
1185
1186 static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
1187 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
1188 // TODO: check that 'field' is a java.lang.reflect.Field.
1189 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
1190 }
1191
1192 static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
1193 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, mid, isStatic);
1194 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, mid, isStatic));
1195 }
1196
1197 static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
1198 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fid, isStatic);
1199 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fid, isStatic));
1200 }
1201
1202 static jint Throw(JNIEnv* env, jthrowable obj) {
1203 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1204 // TODO: check that 'obj' is a java.lang.Throwable.
1205 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
1206 }
1207
1208 static jint ThrowNew(JNIEnv* env, jclass clazz, const char* message) {
1209 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message);
1210 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message));
1211 }
1212
1213 static jthrowable ExceptionOccurred(JNIEnv* env) {
1214 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1215 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
1216 }
1217
1218 static void ExceptionDescribe(JNIEnv* env) {
1219 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1220 baseEnv(env)->ExceptionDescribe(env);
1221 CHECK_JNI_EXIT_VOID();
1222 }
1223
1224 static void ExceptionClear(JNIEnv* env) {
1225 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1226 baseEnv(env)->ExceptionClear(env);
1227 CHECK_JNI_EXIT_VOID();
1228 }
1229
1230 static void FatalError(JNIEnv* env, const char* msg) {
1231 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
1232 baseEnv(env)->FatalError(env, msg);
1233 CHECK_JNI_EXIT_VOID();
1234 }
1235
1236 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1237 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
1238 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
1239 }
1240
1241 static jobject PopLocalFrame(JNIEnv* env, jobject res) {
1242 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
1243 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
1244 }
1245
1246 static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
1247 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1248 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
1249 }
1250
1251 static jobject NewLocalRef(JNIEnv* env, jobject ref) {
1252 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
1253 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
1254 }
1255
1256 static void DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
1257 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
1258 if (globalRef != NULL && GetIndirectRefKind(globalRef) != kGlobal) {
1259 LOG(ERROR) << "JNI ERROR: DeleteGlobalRef on " << GetIndirectRefKind(globalRef) << ": " << globalRef;
1260 JniAbort(__FUNCTION__);
1261 } else {
1262 baseEnv(env)->DeleteGlobalRef(env, globalRef);
1263 CHECK_JNI_EXIT_VOID();
1264 }
1265 }
1266
1267 static void DeleteWeakGlobalRef(JNIEnv* env, jweak weakGlobalRef) {
1268 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, weakGlobalRef);
1269 if (weakGlobalRef != NULL && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) {
1270 LOG(ERROR) << "JNI ERROR: DeleteWeakGlobalRef on " << GetIndirectRefKind(weakGlobalRef) << ": " << weakGlobalRef;
1271 JniAbort(__FUNCTION__);
1272 } else {
1273 baseEnv(env)->DeleteWeakGlobalRef(env, weakGlobalRef);
1274 CHECK_JNI_EXIT_VOID();
1275 }
1276 }
1277
1278 static void DeleteLocalRef(JNIEnv* env, jobject localRef) {
1279 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
Ian Rogers959f8ed2012-02-07 16:33:37 -08001280 if (localRef != NULL && GetIndirectRefKind(localRef) != kLocal && !IsSirtLocalRef(env, localRef)) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001281 LOG(ERROR) << "JNI ERROR: DeleteLocalRef on " << GetIndirectRefKind(localRef) << ": " << localRef;
1282 JniAbort(__FUNCTION__);
1283 } else {
1284 baseEnv(env)->DeleteLocalRef(env, localRef);
1285 CHECK_JNI_EXIT_VOID();
1286 }
1287 }
1288
1289 static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
1290 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
1291 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
1292 }
1293
1294 static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
1295 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
1296 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
1297 }
1298
1299 static jobject AllocObject(JNIEnv* env, jclass clazz) {
1300 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1301 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz));
1302 }
1303
1304 static jobject NewObject(JNIEnv* env, jclass clazz, jmethodID mid, ...) {
1305 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1306 va_list args;
1307 va_start(args, mid);
1308 jobject result = baseEnv(env)->NewObjectV(env, clazz, mid, args);
1309 va_end(args);
1310 return CHECK_JNI_EXIT("L", result);
1311 }
1312
1313 static jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) {
1314 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1315 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, mid, args));
1316 }
1317
1318 static jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) {
1319 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid);
1320 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, mid, args));
1321 }
1322
1323 static jclass GetObjectClass(JNIEnv* env, jobject obj) {
1324 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1325 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
1326 }
1327
1328 static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
1329 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz);
1330 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz));
1331 }
1332
1333 static jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1334 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1335 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig));
1336 }
1337
1338 static jfieldID GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1339 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1340 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig));
1341 }
1342
1343 static jmethodID GetStaticMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1344 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1345 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig));
1346 }
1347
1348 static jfieldID GetStaticFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1349 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1350 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig));
1351 }
1352
1353#define FIELD_ACCESSORS(_ctype, _jname, _type) \
1354 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid) { \
1355 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001356 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001357 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fid)); \
1358 } \
1359 static _ctype Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid) { \
1360 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001361 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001362 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fid)); \
1363 } \
1364 static void SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fid, _ctype value) { \
1365 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001366 sc.CheckStaticFieldID(clazz, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001367 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001368 sc.CheckFieldType((jobject)(uint32_t)value, fid, _type[0], true); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001369 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fid, value); \
1370 CHECK_JNI_EXIT_VOID(); \
1371 } \
1372 static void Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid, _ctype value) { \
1373 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001374 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001375 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001376 sc.CheckFieldType((jobject)(uint32_t) value, fid, _type[0], false); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001377 baseEnv(env)->Set##_jname##Field(env, obj, fid, value); \
1378 CHECK_JNI_EXIT_VOID(); \
1379 }
1380
1381FIELD_ACCESSORS(jobject, Object, "L");
1382FIELD_ACCESSORS(jboolean, Boolean, "Z");
1383FIELD_ACCESSORS(jbyte, Byte, "B");
1384FIELD_ACCESSORS(jchar, Char, "C");
1385FIELD_ACCESSORS(jshort, Short, "S");
1386FIELD_ACCESSORS(jint, Int, "I");
1387FIELD_ACCESSORS(jlong, Long, "J");
1388FIELD_ACCESSORS(jfloat, Float, "F");
1389FIELD_ACCESSORS(jdouble, Double, "D");
1390
1391#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
1392 /* Virtual... */ \
1393 static _ctype Call##_jname##Method(JNIEnv* env, jobject obj, \
1394 jmethodID mid, ...) \
1395 { \
1396 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001397 sc.CheckSig(mid, _retsig, false); \
1398 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001399 _retdecl; \
1400 va_list args; \
1401 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001402 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001403 va_end(args); \
1404 _retok; \
1405 } \
1406 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1407 jmethodID mid, va_list args) \
1408 { \
1409 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001410 sc.CheckSig(mid, _retsig, false); \
1411 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001412 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001413 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001414 _retok; \
1415 } \
1416 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1417 jmethodID mid, jvalue* args) \
1418 { \
1419 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001420 sc.CheckSig(mid, _retsig, false); \
1421 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001422 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001423 _retasgn(baseEnv(env)->Call##_jname##MethodA(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001424 _retok; \
1425 } \
1426 /* Non-virtual... */ \
1427 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, \
1428 jobject obj, jclass clazz, jmethodID mid, ...) \
1429 { \
1430 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001431 sc.CheckSig(mid, _retsig, false); \
1432 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001433 _retdecl; \
1434 va_list args; \
1435 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001436 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001437 va_end(args); \
1438 _retok; \
1439 } \
1440 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, \
1441 jobject obj, jclass clazz, jmethodID mid, va_list args) \
1442 { \
1443 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001444 sc.CheckSig(mid, _retsig, false); \
1445 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001446 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001447 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001448 _retok; \
1449 } \
1450 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, \
1451 jobject obj, jclass clazz, jmethodID mid, jvalue* args) \
1452 { \
1453 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001454 sc.CheckSig(mid, _retsig, false); \
1455 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001456 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001457 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001458 _retok; \
1459 } \
1460 /* Static... */ \
1461 static _ctype CallStatic##_jname##Method(JNIEnv* env, \
1462 jclass clazz, jmethodID mid, ...) \
1463 { \
1464 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001465 sc.CheckSig(mid, _retsig, true); \
1466 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001467 _retdecl; \
1468 va_list args; \
1469 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001470 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001471 va_end(args); \
1472 _retok; \
1473 } \
1474 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, \
1475 jclass clazz, jmethodID mid, va_list args) \
1476 { \
1477 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001478 sc.CheckSig(mid, _retsig, true); \
1479 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001480 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001481 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001482 _retok; \
1483 } \
1484 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, \
1485 jclass clazz, jmethodID mid, jvalue* args) \
1486 { \
1487 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001488 sc.CheckSig(mid, _retsig, true); \
1489 sc.CheckStaticMethod(clazz, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001490 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001491 _retasgn(baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001492 _retok; \
1493 }
1494
1495#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
1496#define VOID_RETURN CHECK_JNI_EXIT_VOID()
1497
Elliott Hughesba8eee12012-01-24 20:25:24 -08001498CALL(jobject, Object, Object* result, result = reinterpret_cast<Object*>, NON_VOID_RETURN("L", jobject), "L");
1499CALL(jboolean, Boolean, jboolean result, result =, NON_VOID_RETURN("Z", jboolean), "Z");
1500CALL(jbyte, Byte, jbyte result, result =, NON_VOID_RETURN("B", jbyte), "B");
1501CALL(jchar, Char, jchar result, result =, NON_VOID_RETURN("C", jchar), "C");
1502CALL(jshort, Short, jshort result, result =, NON_VOID_RETURN("S", jshort), "S");
1503CALL(jint, Int, jint result, result =, NON_VOID_RETURN("I", jint), "I");
1504CALL(jlong, Long, jlong result, result =, NON_VOID_RETURN("J", jlong), "J");
1505CALL(jfloat, Float, jfloat result, result =, NON_VOID_RETURN("F", jfloat), "F");
1506CALL(jdouble, Double, jdouble result, result =, NON_VOID_RETURN("D", jdouble), "D");
Elliott Hughesa2501992011-08-26 19:39:54 -07001507CALL(void, Void, , , VOID_RETURN, "V");
1508
1509 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
1510 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
1511 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
1512 }
1513
1514 static jsize GetStringLength(JNIEnv* env, jstring string) {
1515 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1516 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
1517 }
1518
1519 static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1520 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, java_string, isCopy);
1521 const jchar* result = baseEnv(env)->GetStringChars(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001522 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001523 ScopedJniThreadState ts(env);
1524 String* s = Decode<String*>(ts, java_string);
1525 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001526 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001527 if (isCopy != NULL) {
1528 *isCopy = JNI_TRUE;
1529 }
1530 }
1531 return CHECK_JNI_EXIT("p", result);
1532 }
1533
1534 static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
1535 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001536 sc.CheckNonNull(chars);
1537 if (sc.ForceCopy()) {
1538 GuardedCopy::Check(__FUNCTION__, chars, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001539 chars = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(chars)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001540 }
1541 baseEnv(env)->ReleaseStringChars(env, string, chars);
1542 CHECK_JNI_EXIT_VOID();
1543 }
1544
1545 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
1546 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
1547 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
1548 }
1549
1550 static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
1551 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1552 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
1553 }
1554
1555 static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1556 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1557 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001558 if (sc.ForceCopy() && result != NULL) {
1559 result = (const char*) GuardedCopy::Create(result, strlen(result) + 1, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001560 if (isCopy != NULL) {
1561 *isCopy = JNI_TRUE;
1562 }
1563 }
1564 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
1565 }
1566
1567 static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
1568 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001569 if (sc.ForceCopy()) {
1570 GuardedCopy::Check(__FUNCTION__, utf, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001571 utf = reinterpret_cast<const char*>(GuardedCopy::Destroy(const_cast<char*>(utf)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001572 }
1573 baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
1574 CHECK_JNI_EXIT_VOID();
1575 }
1576
1577 static jsize GetArrayLength(JNIEnv* env, jarray array) {
1578 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
1579 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
1580 }
1581
1582 static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass elementClass, jobject initialElement) {
1583 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
1584 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
1585 }
1586
1587 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
1588 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
1589 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
1590 }
1591
1592 static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
1593 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
1594 baseEnv(env)->SetObjectArrayElement(env, array, index, value);
1595 CHECK_JNI_EXIT_VOID();
1596 }
1597
1598#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
1599 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
1600 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
1601 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
1602 }
1603NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
1604NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
1605NEW_PRIMITIVE_ARRAY(jcharArray, Char);
1606NEW_PRIMITIVE_ARRAY(jshortArray, Short);
1607NEW_PRIMITIVE_ARRAY(jintArray, Int);
1608NEW_PRIMITIVE_ARRAY(jlongArray, Long);
1609NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
1610NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
1611
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001612struct ForceCopyGetChecker {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001613 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07001614 ForceCopyGetChecker(ScopedCheck& sc, jboolean* isCopy) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001615 force_copy = sc.ForceCopy();
1616 no_copy = 0;
1617 if (force_copy && isCopy != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001618 /* capture this before the base call tramples on it */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001619 no_copy = *reinterpret_cast<uint32_t*>(isCopy);
Elliott Hughesa2501992011-08-26 19:39:54 -07001620 }
1621 }
1622
1623 template<typename ResultT>
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001624 ResultT Check(JNIEnv* env, jarray array, jboolean* isCopy, ResultT result) {
1625 if (force_copy && result != NULL) {
1626 if (no_copy != kNoCopyMagic) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001627 result = reinterpret_cast<ResultT>(CreateGuardedPACopy(env, array, isCopy));
1628 }
1629 }
1630 return result;
1631 }
1632
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001633 uint32_t no_copy;
1634 bool force_copy;
Elliott Hughesa2501992011-08-26 19:39:54 -07001635};
1636
1637#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1638 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, jboolean* isCopy) { \
1639 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001640 _ctype* result = ForceCopyGetChecker(sc, isCopy).Check(env, array, isCopy, baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001641 return CHECK_JNI_EXIT("p", result); \
1642 }
1643
1644#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1645 static void Release##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, _ctype* elems, jint mode) { \
1646 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001647 sc.CheckNonNull(elems); \
1648 if (sc.ForceCopy()) { \
Elliott Hughesa2501992011-08-26 19:39:54 -07001649 ReleaseGuardedPACopy(env, array, elems, mode); \
1650 } \
1651 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
1652 CHECK_JNI_EXIT_VOID(); \
1653 }
1654
1655#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1656 static void Get##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
1657 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1658 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
1659 CHECK_JNI_EXIT_VOID(); \
1660 }
1661
1662#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1663 static void Set##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
1664 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1665 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
1666 CHECK_JNI_EXIT_VOID(); \
1667 }
1668
1669#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
1670 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1671 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1672 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
1673 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
1674
1675/* TODO: verify primitive array type matches call type */
1676PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
1677PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
1678PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
1679PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
1680PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
1681PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
1682PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
1683PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
1684
1685 static jint RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) {
1686 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods);
1687 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods));
1688 }
1689
1690 static jint UnregisterNatives(JNIEnv* env, jclass clazz) {
1691 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1692 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz));
1693 }
1694
1695 static jint MonitorEnter(JNIEnv* env, jobject obj) {
1696 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
Elliott Hughesa92853e2012-02-07 16:09:27 -08001697 if (!sc.CheckInstance(ScopedCheck::kObject, obj)) {
1698 return JNI_ERR; // Only for jni_internal_test. Real code will have aborted already.
1699 }
Elliott Hughesa2501992011-08-26 19:39:54 -07001700 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
1701 }
1702
1703 static jint MonitorExit(JNIEnv* env, jobject obj) {
1704 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
Elliott Hughesa92853e2012-02-07 16:09:27 -08001705 if (!sc.CheckInstance(ScopedCheck::kObject, obj)) {
1706 return JNI_ERR; // Only for jni_internal_test. Real code will have aborted already.
1707 }
Elliott Hughesa2501992011-08-26 19:39:54 -07001708 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
1709 }
1710
1711 static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
1712 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
1713 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
1714 }
1715
1716 static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
1717 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1718 baseEnv(env)->GetStringRegion(env, str, start, len, buf);
1719 CHECK_JNI_EXIT_VOID();
1720 }
1721
1722 static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
1723 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1724 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
1725 CHECK_JNI_EXIT_VOID();
1726 }
1727
1728 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
1729 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
1730 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001731 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001732 result = CreateGuardedPACopy(env, array, isCopy);
1733 }
1734 return CHECK_JNI_EXIT("p", result);
1735 }
1736
1737 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
1738 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001739 sc.CheckNonNull(carray);
1740 if (sc.ForceCopy()) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001741 ReleaseGuardedPACopy(env, array, carray, mode);
1742 }
1743 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
1744 CHECK_JNI_EXIT_VOID();
1745 }
1746
1747 static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1748 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, java_string, isCopy);
1749 const jchar* result = baseEnv(env)->GetStringCritical(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001750 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001751 ScopedJniThreadState ts(env);
1752 String* s = Decode<String*>(ts, java_string);
1753 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001754 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001755 if (isCopy != NULL) {
1756 *isCopy = JNI_TRUE;
1757 }
1758 }
1759 return CHECK_JNI_EXIT("p", result);
1760 }
1761
1762 static void ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
1763 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001764 sc.CheckNonNull(carray);
1765 if (sc.ForceCopy()) {
1766 GuardedCopy::Check(__FUNCTION__, carray, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001767 carray = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(carray)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001768 }
1769 baseEnv(env)->ReleaseStringCritical(env, string, carray);
1770 CHECK_JNI_EXIT_VOID();
1771 }
1772
1773 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
1774 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1775 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
1776 }
1777
1778 static jboolean ExceptionCheck(JNIEnv* env) {
1779 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
1780 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
1781 }
1782
1783 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
1784 // Note: we use "Ep" rather than "EL" because this is the one JNI function
1785 // that it's okay to pass an invalid reference to.
1786 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, obj);
1787 // TODO: proper decoding of jobjectRefType!
1788 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
1789 }
1790
1791 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
1792 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
1793 if (address == NULL) {
1794 LOG(ERROR) << "JNI ERROR: non-nullable address is NULL";
1795 JniAbort(__FUNCTION__);
1796 }
1797 if (capacity <= 0) {
1798 LOG(ERROR) << "JNI ERROR: capacity must be greater than 0: " << capacity;
1799 JniAbort(__FUNCTION__);
1800 }
1801 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
1802 }
1803
1804 static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
1805 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1806 // TODO: check that 'buf' is a java.nio.Buffer.
1807 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
1808 }
1809
1810 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
1811 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1812 // TODO: check that 'buf' is a java.nio.Buffer.
1813 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
1814 }
1815
1816 private:
1817 static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
1818 return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions;
1819 }
1820};
1821
1822const JNINativeInterface gCheckNativeInterface = {
1823 NULL, // reserved0.
1824 NULL, // reserved1.
1825 NULL, // reserved2.
1826 NULL, // reserved3.
1827 CheckJNI::GetVersion,
1828 CheckJNI::DefineClass,
1829 CheckJNI::FindClass,
1830 CheckJNI::FromReflectedMethod,
1831 CheckJNI::FromReflectedField,
1832 CheckJNI::ToReflectedMethod,
1833 CheckJNI::GetSuperclass,
1834 CheckJNI::IsAssignableFrom,
1835 CheckJNI::ToReflectedField,
1836 CheckJNI::Throw,
1837 CheckJNI::ThrowNew,
1838 CheckJNI::ExceptionOccurred,
1839 CheckJNI::ExceptionDescribe,
1840 CheckJNI::ExceptionClear,
1841 CheckJNI::FatalError,
1842 CheckJNI::PushLocalFrame,
1843 CheckJNI::PopLocalFrame,
1844 CheckJNI::NewGlobalRef,
1845 CheckJNI::DeleteGlobalRef,
1846 CheckJNI::DeleteLocalRef,
1847 CheckJNI::IsSameObject,
1848 CheckJNI::NewLocalRef,
1849 CheckJNI::EnsureLocalCapacity,
1850 CheckJNI::AllocObject,
1851 CheckJNI::NewObject,
1852 CheckJNI::NewObjectV,
1853 CheckJNI::NewObjectA,
1854 CheckJNI::GetObjectClass,
1855 CheckJNI::IsInstanceOf,
1856 CheckJNI::GetMethodID,
1857 CheckJNI::CallObjectMethod,
1858 CheckJNI::CallObjectMethodV,
1859 CheckJNI::CallObjectMethodA,
1860 CheckJNI::CallBooleanMethod,
1861 CheckJNI::CallBooleanMethodV,
1862 CheckJNI::CallBooleanMethodA,
1863 CheckJNI::CallByteMethod,
1864 CheckJNI::CallByteMethodV,
1865 CheckJNI::CallByteMethodA,
1866 CheckJNI::CallCharMethod,
1867 CheckJNI::CallCharMethodV,
1868 CheckJNI::CallCharMethodA,
1869 CheckJNI::CallShortMethod,
1870 CheckJNI::CallShortMethodV,
1871 CheckJNI::CallShortMethodA,
1872 CheckJNI::CallIntMethod,
1873 CheckJNI::CallIntMethodV,
1874 CheckJNI::CallIntMethodA,
1875 CheckJNI::CallLongMethod,
1876 CheckJNI::CallLongMethodV,
1877 CheckJNI::CallLongMethodA,
1878 CheckJNI::CallFloatMethod,
1879 CheckJNI::CallFloatMethodV,
1880 CheckJNI::CallFloatMethodA,
1881 CheckJNI::CallDoubleMethod,
1882 CheckJNI::CallDoubleMethodV,
1883 CheckJNI::CallDoubleMethodA,
1884 CheckJNI::CallVoidMethod,
1885 CheckJNI::CallVoidMethodV,
1886 CheckJNI::CallVoidMethodA,
1887 CheckJNI::CallNonvirtualObjectMethod,
1888 CheckJNI::CallNonvirtualObjectMethodV,
1889 CheckJNI::CallNonvirtualObjectMethodA,
1890 CheckJNI::CallNonvirtualBooleanMethod,
1891 CheckJNI::CallNonvirtualBooleanMethodV,
1892 CheckJNI::CallNonvirtualBooleanMethodA,
1893 CheckJNI::CallNonvirtualByteMethod,
1894 CheckJNI::CallNonvirtualByteMethodV,
1895 CheckJNI::CallNonvirtualByteMethodA,
1896 CheckJNI::CallNonvirtualCharMethod,
1897 CheckJNI::CallNonvirtualCharMethodV,
1898 CheckJNI::CallNonvirtualCharMethodA,
1899 CheckJNI::CallNonvirtualShortMethod,
1900 CheckJNI::CallNonvirtualShortMethodV,
1901 CheckJNI::CallNonvirtualShortMethodA,
1902 CheckJNI::CallNonvirtualIntMethod,
1903 CheckJNI::CallNonvirtualIntMethodV,
1904 CheckJNI::CallNonvirtualIntMethodA,
1905 CheckJNI::CallNonvirtualLongMethod,
1906 CheckJNI::CallNonvirtualLongMethodV,
1907 CheckJNI::CallNonvirtualLongMethodA,
1908 CheckJNI::CallNonvirtualFloatMethod,
1909 CheckJNI::CallNonvirtualFloatMethodV,
1910 CheckJNI::CallNonvirtualFloatMethodA,
1911 CheckJNI::CallNonvirtualDoubleMethod,
1912 CheckJNI::CallNonvirtualDoubleMethodV,
1913 CheckJNI::CallNonvirtualDoubleMethodA,
1914 CheckJNI::CallNonvirtualVoidMethod,
1915 CheckJNI::CallNonvirtualVoidMethodV,
1916 CheckJNI::CallNonvirtualVoidMethodA,
1917 CheckJNI::GetFieldID,
1918 CheckJNI::GetObjectField,
1919 CheckJNI::GetBooleanField,
1920 CheckJNI::GetByteField,
1921 CheckJNI::GetCharField,
1922 CheckJNI::GetShortField,
1923 CheckJNI::GetIntField,
1924 CheckJNI::GetLongField,
1925 CheckJNI::GetFloatField,
1926 CheckJNI::GetDoubleField,
1927 CheckJNI::SetObjectField,
1928 CheckJNI::SetBooleanField,
1929 CheckJNI::SetByteField,
1930 CheckJNI::SetCharField,
1931 CheckJNI::SetShortField,
1932 CheckJNI::SetIntField,
1933 CheckJNI::SetLongField,
1934 CheckJNI::SetFloatField,
1935 CheckJNI::SetDoubleField,
1936 CheckJNI::GetStaticMethodID,
1937 CheckJNI::CallStaticObjectMethod,
1938 CheckJNI::CallStaticObjectMethodV,
1939 CheckJNI::CallStaticObjectMethodA,
1940 CheckJNI::CallStaticBooleanMethod,
1941 CheckJNI::CallStaticBooleanMethodV,
1942 CheckJNI::CallStaticBooleanMethodA,
1943 CheckJNI::CallStaticByteMethod,
1944 CheckJNI::CallStaticByteMethodV,
1945 CheckJNI::CallStaticByteMethodA,
1946 CheckJNI::CallStaticCharMethod,
1947 CheckJNI::CallStaticCharMethodV,
1948 CheckJNI::CallStaticCharMethodA,
1949 CheckJNI::CallStaticShortMethod,
1950 CheckJNI::CallStaticShortMethodV,
1951 CheckJNI::CallStaticShortMethodA,
1952 CheckJNI::CallStaticIntMethod,
1953 CheckJNI::CallStaticIntMethodV,
1954 CheckJNI::CallStaticIntMethodA,
1955 CheckJNI::CallStaticLongMethod,
1956 CheckJNI::CallStaticLongMethodV,
1957 CheckJNI::CallStaticLongMethodA,
1958 CheckJNI::CallStaticFloatMethod,
1959 CheckJNI::CallStaticFloatMethodV,
1960 CheckJNI::CallStaticFloatMethodA,
1961 CheckJNI::CallStaticDoubleMethod,
1962 CheckJNI::CallStaticDoubleMethodV,
1963 CheckJNI::CallStaticDoubleMethodA,
1964 CheckJNI::CallStaticVoidMethod,
1965 CheckJNI::CallStaticVoidMethodV,
1966 CheckJNI::CallStaticVoidMethodA,
1967 CheckJNI::GetStaticFieldID,
1968 CheckJNI::GetStaticObjectField,
1969 CheckJNI::GetStaticBooleanField,
1970 CheckJNI::GetStaticByteField,
1971 CheckJNI::GetStaticCharField,
1972 CheckJNI::GetStaticShortField,
1973 CheckJNI::GetStaticIntField,
1974 CheckJNI::GetStaticLongField,
1975 CheckJNI::GetStaticFloatField,
1976 CheckJNI::GetStaticDoubleField,
1977 CheckJNI::SetStaticObjectField,
1978 CheckJNI::SetStaticBooleanField,
1979 CheckJNI::SetStaticByteField,
1980 CheckJNI::SetStaticCharField,
1981 CheckJNI::SetStaticShortField,
1982 CheckJNI::SetStaticIntField,
1983 CheckJNI::SetStaticLongField,
1984 CheckJNI::SetStaticFloatField,
1985 CheckJNI::SetStaticDoubleField,
1986 CheckJNI::NewString,
1987 CheckJNI::GetStringLength,
1988 CheckJNI::GetStringChars,
1989 CheckJNI::ReleaseStringChars,
1990 CheckJNI::NewStringUTF,
1991 CheckJNI::GetStringUTFLength,
1992 CheckJNI::GetStringUTFChars,
1993 CheckJNI::ReleaseStringUTFChars,
1994 CheckJNI::GetArrayLength,
1995 CheckJNI::NewObjectArray,
1996 CheckJNI::GetObjectArrayElement,
1997 CheckJNI::SetObjectArrayElement,
1998 CheckJNI::NewBooleanArray,
1999 CheckJNI::NewByteArray,
2000 CheckJNI::NewCharArray,
2001 CheckJNI::NewShortArray,
2002 CheckJNI::NewIntArray,
2003 CheckJNI::NewLongArray,
2004 CheckJNI::NewFloatArray,
2005 CheckJNI::NewDoubleArray,
2006 CheckJNI::GetBooleanArrayElements,
2007 CheckJNI::GetByteArrayElements,
2008 CheckJNI::GetCharArrayElements,
2009 CheckJNI::GetShortArrayElements,
2010 CheckJNI::GetIntArrayElements,
2011 CheckJNI::GetLongArrayElements,
2012 CheckJNI::GetFloatArrayElements,
2013 CheckJNI::GetDoubleArrayElements,
2014 CheckJNI::ReleaseBooleanArrayElements,
2015 CheckJNI::ReleaseByteArrayElements,
2016 CheckJNI::ReleaseCharArrayElements,
2017 CheckJNI::ReleaseShortArrayElements,
2018 CheckJNI::ReleaseIntArrayElements,
2019 CheckJNI::ReleaseLongArrayElements,
2020 CheckJNI::ReleaseFloatArrayElements,
2021 CheckJNI::ReleaseDoubleArrayElements,
2022 CheckJNI::GetBooleanArrayRegion,
2023 CheckJNI::GetByteArrayRegion,
2024 CheckJNI::GetCharArrayRegion,
2025 CheckJNI::GetShortArrayRegion,
2026 CheckJNI::GetIntArrayRegion,
2027 CheckJNI::GetLongArrayRegion,
2028 CheckJNI::GetFloatArrayRegion,
2029 CheckJNI::GetDoubleArrayRegion,
2030 CheckJNI::SetBooleanArrayRegion,
2031 CheckJNI::SetByteArrayRegion,
2032 CheckJNI::SetCharArrayRegion,
2033 CheckJNI::SetShortArrayRegion,
2034 CheckJNI::SetIntArrayRegion,
2035 CheckJNI::SetLongArrayRegion,
2036 CheckJNI::SetFloatArrayRegion,
2037 CheckJNI::SetDoubleArrayRegion,
2038 CheckJNI::RegisterNatives,
2039 CheckJNI::UnregisterNatives,
2040 CheckJNI::MonitorEnter,
2041 CheckJNI::MonitorExit,
2042 CheckJNI::GetJavaVM,
2043 CheckJNI::GetStringRegion,
2044 CheckJNI::GetStringUTFRegion,
2045 CheckJNI::GetPrimitiveArrayCritical,
2046 CheckJNI::ReleasePrimitiveArrayCritical,
2047 CheckJNI::GetStringCritical,
2048 CheckJNI::ReleaseStringCritical,
2049 CheckJNI::NewWeakGlobalRef,
2050 CheckJNI::DeleteWeakGlobalRef,
2051 CheckJNI::ExceptionCheck,
2052 CheckJNI::NewDirectByteBuffer,
2053 CheckJNI::GetDirectBufferAddress,
2054 CheckJNI::GetDirectBufferCapacity,
2055 CheckJNI::GetObjectRefType,
2056};
2057
2058const JNINativeInterface* GetCheckJniNativeInterface() {
2059 return &gCheckNativeInterface;
2060}
2061
2062class CheckJII {
Elliott Hughesba8eee12012-01-24 20:25:24 -08002063 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07002064 static jint DestroyJavaVM(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002065 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002066 sc.Check(true, "v", vm);
2067 return CHECK_JNI_EXIT("I", BaseVm(vm)->DestroyJavaVM(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002068 }
2069
2070 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002071 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002072 sc.Check(true, "vpp", vm, p_env, thr_args);
2073 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002074 }
2075
2076 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002077 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002078 sc.Check(true, "vpp", vm, p_env, thr_args);
2079 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002080 }
2081
2082 static jint DetachCurrentThread(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002083 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002084 sc.Check(true, "v", vm);
2085 return CHECK_JNI_EXIT("I", BaseVm(vm)->DetachCurrentThread(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002086 }
2087
2088 static jint GetEnv(JavaVM* vm, void** env, jint version) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002089 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002090 sc.Check(true, "v", vm);
2091 return CHECK_JNI_EXIT("I", BaseVm(vm)->GetEnv(vm, env, version));
Elliott Hughesa2501992011-08-26 19:39:54 -07002092 }
2093
2094 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002095 static inline const JNIInvokeInterface* BaseVm(JavaVM* vm) {
Elliott Hughesa2501992011-08-26 19:39:54 -07002096 return reinterpret_cast<JavaVMExt*>(vm)->unchecked_functions;
2097 }
2098};
2099
2100const JNIInvokeInterface gCheckInvokeInterface = {
2101 NULL, // reserved0
2102 NULL, // reserved1
2103 NULL, // reserved2
2104 CheckJII::DestroyJavaVM,
2105 CheckJII::AttachCurrentThread,
2106 CheckJII::DetachCurrentThread,
2107 CheckJII::GetEnv,
2108 CheckJII::AttachCurrentThreadAsDaemon
2109};
2110
2111const JNIInvokeInterface* GetCheckJniInvokeInterface() {
2112 return &gCheckInvokeInterface;
2113}
2114
2115} // namespace art