blob: fb7fa02c126ca761e86722a4f7fcab53495d7eda [file] [log] [blame]
Elliott Hughesa2501992011-08-26 19:39:54 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jni_internal.h"
18
19#include <sys/mman.h>
20#include <zlib.h>
21
22#include "class_linker.h"
23#include "logging.h"
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080024#include "object_utils.h"
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -070025#include "scoped_jni_thread_state.h"
Elliott Hughesb3bd5f02012-03-08 21:05:27 -080026#include "space.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070027#include "thread.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070028#include "runtime.h"
Elliott Hughesa2501992011-08-26 19:39:54 -070029
Elliott Hughese6087632011-09-26 12:18:25 -070030#define LIBCORE_CPP_JNI_HELPERS
31#include <JNIHelp.h> // from libcore
32#undef LIBCORE_CPP_JNI_HELPERS
33
Elliott Hughesa2501992011-08-26 19:39:54 -070034namespace art {
35
36void JniAbort(const char* jni_function_name) {
Elliott Hughesa0957642011-09-02 14:27:33 -070037 Thread* self = Thread::Current();
Elliott Hughesd07986f2011-12-06 18:27:45 -080038 Method* current_method = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -070039
Elliott Hughes3b6baaa2011-10-14 19:13:56 -070040 std::ostringstream os;
Elliott Hughese6087632011-09-26 12:18:25 -070041 os << "Aborting because JNI app bug detected (see above for details)";
Elliott Hughesa2501992011-08-26 19:39:54 -070042
43 if (jni_function_name != NULL) {
44 os << "\n in call to " << jni_function_name;
45 }
Elliott Hughesa0957642011-09-02 14:27:33 -070046 // TODO: is this useful given that we're about to dump the calling thread's stack?
47 if (current_method != NULL) {
48 os << "\n from " << PrettyMethod(current_method);
49 }
50 os << "\n";
51 self->Dump(os);
Elliott Hughesa2501992011-08-26 19:39:54 -070052
53 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
54 if (vm->check_jni_abort_hook != NULL) {
Elliott Hughesb264f082012-04-06 17:10:10 -070055 vm->check_jni_abort_hook(vm->check_jni_abort_hook_data, os.str());
Elliott Hughesa2501992011-08-26 19:39:54 -070056 } else {
Elliott Hughes34e06962012-04-09 13:55:55 -070057 self->SetState(kNative); // Ensure that we get a native stack trace for this thread.
Elliott Hughesa2501992011-08-26 19:39:54 -070058 LOG(FATAL) << os.str();
59 }
60}
61
62/*
63 * ===========================================================================
64 * JNI function helpers
65 * ===========================================================================
66 */
67
Ian Rogers959f8ed2012-02-07 16:33:37 -080068static bool IsSirtLocalRef(JNIEnv* env, jobject localRef) {
69 return GetIndirectRefKind(localRef) == kSirtOrInvalid &&
TDYa12728f1a142012-03-15 21:51:52 -070070 reinterpret_cast<JNIEnvExt*>(env)->self->StackReferencesContain(localRef);
Ian Rogers959f8ed2012-02-07 16:33:37 -080071}
72
Elliott Hughesa2501992011-08-26 19:39:54 -070073template<typename T>
74T Decode(ScopedJniThreadState& ts, jobject obj) {
75 return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
76}
77
Elliott Hughesa2501992011-08-26 19:39:54 -070078/*
79 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
80 * The code deliberately uses an invalid sequence of operations, so we
81 * need to pass it through unmodified. Review that code before making
82 * any changes here.
83 */
84#define kNoCopyMagic 0xd5aab57f
85
86/*
87 * Flags passed into ScopedCheck.
88 */
89#define kFlag_Default 0x0000
90
91#define kFlag_CritBad 0x0000 /* calling while in critical is bad */
92#define kFlag_CritOkay 0x0001 /* ...okay */
93#define kFlag_CritGet 0x0002 /* this is a critical "get" */
94#define kFlag_CritRelease 0x0003 /* this is a critical "release" */
95#define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */
96
97#define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */
98#define kFlag_ExcepOkay 0x0004 /* ...okay */
99
100#define kFlag_Release 0x0010 /* are we in a non-critical release function? */
101#define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */
102
103#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */
104
Elliott Hughes485cac42011-12-09 17:49:35 -0800105#define kFlag_ForceTrace 0x80000000 // Add this to a JNI function's flags if you want to trace every call.
106
Elliott Hughesa0957642011-09-02 14:27:33 -0700107static const char* gBuiltInPrefixes[] = {
108 "Landroid/",
109 "Lcom/android/",
110 "Lcom/google/android/",
111 "Ldalvik/",
112 "Ljava/",
113 "Ljavax/",
114 "Llibcore/",
115 "Lorg/apache/harmony/",
116 NULL
117};
118
119bool ShouldTrace(JavaVMExt* vm, const Method* method) {
120 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
121 // when a native method that matches the -Xjnitrace argument calls a JNI function
122 // such as NewByteArray.
123 // If -verbose:third-party-jni is on, we want to log any JNI function calls
124 // made by a third-party native method.
Elliott Hughes81ff3182012-03-23 20:35:56 -0700125 std::string class_name(MethodHelper(method).GetDeclaringClassDescriptor());
126 if (!vm->trace.empty() && class_name.find(vm->trace) != std::string::npos) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700127 return true;
128 }
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800129 if (VLOG_IS_ON(third_party_jni)) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700130 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
131 // like part of Android.
Elliott Hughesa0957642011-09-02 14:27:33 -0700132 for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) {
Elliott Hughes81ff3182012-03-23 20:35:56 -0700133 if (StartsWith(class_name, gBuiltInPrefixes[i])) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700134 return false;
135 }
136 }
137 return true;
138 }
139 return false;
140}
141
Elliott Hughesa2501992011-08-26 19:39:54 -0700142class ScopedCheck {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800143 public:
Elliott Hughesa2501992011-08-26 19:39:54 -0700144 // For JNIEnv* functions.
145 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700146 Init(env, reinterpret_cast<JNIEnvExt*>(env)->vm, flags, functionName, true);
147 CheckThread(flags);
Elliott Hughesa2501992011-08-26 19:39:54 -0700148 }
149
150 // For JavaVM* functions.
Elliott Hughes81ff3182012-03-23 20:35:56 -0700151 explicit ScopedCheck(JavaVM* vm, bool has_method, const char* functionName) {
152 Init(NULL, vm, kFlag_Invocation, functionName, has_method);
Elliott Hughesa2501992011-08-26 19:39:54 -0700153 }
154
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700155 bool ForceCopy() {
Elliott Hughesa2501992011-08-26 19:39:54 -0700156 return Runtime::Current()->GetJavaVM()->force_copy;
157 }
158
Elliott Hughes81ff3182012-03-23 20:35:56 -0700159 // Checks that 'class_name' is a valid "fully-qualified" JNI class name, like "java/lang/Thread"
160 // or "[Ljava/lang/Object;". A ClassLoader can actually normalize class names a couple of
161 // times, so using "java.lang.Thread" instead of "java/lang/Thread" might work in some
162 // circumstances, but this is incorrect.
163 void CheckClassName(const char* class_name) {
164 if (!IsValidJniClassName(class_name)) {
165 LOG(ERROR) << "JNI ERROR: illegal class name '" << class_name << "' (" << function_name_ << ")\n"
Elliott Hughesa2501992011-08-26 19:39:54 -0700166 << " (should be of the form 'java/lang/String', [Ljava/lang/String;' or '[[B')\n";
167 JniAbort();
168 }
169 }
170
171 /*
172 * Verify that the field is of the appropriate type. If the field has an
173 * object type, "java_object" is the object we're trying to assign into it.
174 *
175 * Works for both static and instance fields.
176 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700177 void CheckFieldType(jobject java_object, jfieldID fid, char prim, bool isStatic) {
178 ScopedJniThreadState ts(env_);
179 Field* f = CheckFieldID(fid);
180 if (f == NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700181 return;
182 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800183 Class* field_type = FieldHelper(f).GetType();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700184 if (!field_type->IsPrimitive()) {
185 if (java_object != NULL) {
186 Object* obj = Decode<Object*>(ts, java_object);
187 /*
188 * If java_object is a weak global ref whose referent has been cleared,
189 * obj will be NULL. Otherwise, obj should always be non-NULL
190 * and valid.
191 */
Elliott Hughes88c5c352012-03-15 18:49:48 -0700192 if (!Runtime::Current()->GetHeap()->IsHeapAddress(obj)) {
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700193 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
Elliott Hughesa2501992011-08-26 19:39:54 -0700194 JniAbort();
195 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700196 } else {
Brian Carlstrom16192862011-09-12 17:50:06 -0700197 if (!obj->InstanceOf(field_type)) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700198 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << PrettyTypeOf(obj);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700199 JniAbort();
200 return;
201 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700202 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700203 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700204 } else if (field_type != Runtime::Current()->GetClassLinker()->FindPrimitiveClass(prim)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700205 LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << prim;
206 JniAbort();
207 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700208 }
209
210 if (isStatic && !f->IsStatic()) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700211 if (isStatic) {
212 LOG(ERROR) << "JNI ERROR: accessing non-static field " << PrettyField(f) << " as static";
213 } else {
214 LOG(ERROR) << "JNI ERROR: accessing static field " << PrettyField(f) << " as non-static";
215 }
216 JniAbort();
217 return;
218 }
219 }
220
221 /*
222 * Verify that this instance field ID is valid for this object.
223 *
224 * Assumes "jobj" has already been validated.
225 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700226 void CheckInstanceFieldID(jobject java_object, jfieldID fid) {
227 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700228
229 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800230 if (o == NULL || !Runtime::Current()->GetHeap()->IsHeapAddress(o)) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700231 LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
232 JniAbort();
233 return;
234 }
235
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700236 Field* f = CheckFieldID(fid);
237 if (f == NULL) {
238 return;
239 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700240 Class* c = o->GetClass();
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800241 FieldHelper fh(f);
242 if (c->FindInstanceField(fh.GetName(), fh.GetTypeDescriptor()) == NULL) {
Elliott Hughes906e6852011-10-28 14:52:10 -0700243 LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f)
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700244 << " not valid for an object of class " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700245 JniAbort();
246 }
247 }
248
249 /*
250 * Verify that the pointer value is non-NULL.
251 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700252 void CheckNonNull(const void* ptr) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700253 if (ptr == NULL) {
254 LOG(ERROR) << "JNI ERROR: invalid null pointer";
255 JniAbort();
256 }
257 }
258
259 /*
260 * Verify that the method's return type matches the type of call.
261 * 'expectedType' will be "L" for all objects, including arrays.
262 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700263 void CheckSig(jmethodID mid, const char* expectedType, bool isStatic) {
264 ScopedJniThreadState ts(env_);
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800265 Method* m = CheckMethodID(mid);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700266 if (m == NULL) {
267 return;
268 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800269 if (*expectedType != MethodHelper(m).GetShorty()[0]) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700270 LOG(ERROR) << "JNI ERROR: the return type of " << function_name_ << " does not match "
271 << PrettyMethod(m);
Elliott Hughesa2501992011-08-26 19:39:54 -0700272 JniAbort();
273 } else if (isStatic && !m->IsStatic()) {
274 if (isStatic) {
Elliott Hughes726079d2011-10-07 18:43:44 -0700275 LOG(ERROR) << "JNI ERROR: calling non-static method "
276 << PrettyMethod(m) << " with " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700277 } else {
Elliott Hughes726079d2011-10-07 18:43:44 -0700278 LOG(ERROR) << "JNI ERROR: calling static method "
279 << PrettyMethod(m) << " with non-static " << function_name_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700280 }
281 JniAbort();
282 }
283 }
284
285 /*
286 * Verify that this static field ID is valid for this class.
287 *
288 * Assumes "java_class" has already been validated.
289 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700290 void CheckStaticFieldID(jclass java_class, jfieldID fid) {
291 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700292 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700293 const Field* f = CheckFieldID(fid);
294 if (f == NULL) {
295 return;
296 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700297 if (f->GetDeclaringClass() != c) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700298 LOG(ERROR) << "JNI ERROR: static jfieldID " << fid << " not valid for class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700299 JniAbort();
300 }
301 }
302
303 /*
Elliott Hughese84278b2012-03-22 10:06:53 -0700304 * Verify that "mid" is appropriate for "java_class".
Elliott Hughesa2501992011-08-26 19:39:54 -0700305 *
306 * A mismatch isn't dangerous, because the jmethodID defines the class. In
Elliott Hughese84278b2012-03-22 10:06:53 -0700307 * fact, java_class is unused in the implementation. It's best if we don't
Elliott Hughesa2501992011-08-26 19:39:54 -0700308 * allow bad code in the system though.
309 *
Elliott Hughese84278b2012-03-22 10:06:53 -0700310 * Instances of "java_class" must be instances of the method's declaring class.
Elliott Hughesa2501992011-08-26 19:39:54 -0700311 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700312 void CheckStaticMethod(jclass java_class, jmethodID mid) {
313 ScopedJniThreadState ts(env_);
314 const Method* m = CheckMethodID(mid);
315 if (m == NULL) {
316 return;
317 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700318 Class* c = Decode<Class*>(ts, java_class);
Elliott Hughesa2501992011-08-26 19:39:54 -0700319 if (!c->IsAssignableFrom(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700320 LOG(ERROR) << "JNI ERROR: can't call static " << PrettyMethod(m) << " on class " << PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700321 JniAbort();
322 }
323 }
324
325 /*
326 * Verify that "mid" is appropriate for "jobj".
327 *
328 * Make sure the object is an instance of the method's declaring class.
329 * (Note the mid might point to a declaration in an interface; this
330 * will be handled automatically by the instanceof check.)
331 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700332 void CheckVirtualMethod(jobject java_object, jmethodID mid) {
333 ScopedJniThreadState ts(env_);
334 const Method* m = CheckMethodID(mid);
335 if (m == NULL) {
336 return;
337 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700338 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughesa2501992011-08-26 19:39:54 -0700339 if (!o->InstanceOf(m->GetDeclaringClass())) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700340 LOG(ERROR) << "JNI ERROR: can't call " << PrettyMethod(m) << " on instance of " << PrettyTypeOf(o);
Elliott Hughesa2501992011-08-26 19:39:54 -0700341 JniAbort();
342 }
343 }
344
345 /**
346 * The format string is a sequence of the following characters,
347 * and must be followed by arguments of the corresponding types
348 * in the same order.
349 *
350 * Java primitive types:
351 * B - jbyte
352 * C - jchar
353 * D - jdouble
354 * F - jfloat
355 * I - jint
356 * J - jlong
357 * S - jshort
358 * Z - jboolean (shown as true and false)
359 * V - void
360 *
361 * Java reference types:
362 * L - jobject
363 * a - jarray
364 * c - jclass
365 * s - jstring
366 *
367 * JNI types:
368 * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
369 * f - jfieldID
370 * m - jmethodID
371 * p - void*
372 * r - jint (for release mode arguments)
Elliott Hughes78090d12011-10-07 14:31:47 -0700373 * u - const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700374 * z - jsize (for lengths; use i if negative values are okay)
375 * v - JavaVM*
376 * E - JNIEnv*
377 * . - no argument; just print "..." (used for varargs JNI calls)
378 *
379 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
380 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700381 void Check(bool entry, const char* fmt0, ...) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700382 va_list ap;
383
Elliott Hughesa0957642011-09-02 14:27:33 -0700384 const Method* traceMethod = NULL;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800385 if ((!vm_->trace.empty() || VLOG_IS_ON(third_party_jni)) && has_method_) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700386 // We need to guard some of the invocation interface's calls: a bad caller might
387 // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
Elliott Hughesa0957642011-09-02 14:27:33 -0700388 Thread* self = Thread::Current();
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700389 if ((flags_ & kFlag_Invocation) == 0 || self != NULL) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700390 traceMethod = self->GetCurrentMethod();
Elliott Hughesa2501992011-08-26 19:39:54 -0700391 }
392 }
Elliott Hughesa0957642011-09-02 14:27:33 -0700393
Elliott Hughes485cac42011-12-09 17:49:35 -0800394 if (((flags_ & kFlag_ForceTrace) != 0) || (traceMethod != NULL && ShouldTrace(vm_, traceMethod))) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700395 va_start(ap, fmt0);
396 std::string msg;
397 for (const char* fmt = fmt0; *fmt;) {
398 char ch = *fmt++;
399 if (ch == 'B') { // jbyte
400 jbyte b = va_arg(ap, int);
401 if (b >= 0 && b < 10) {
402 StringAppendF(&msg, "%d", b);
403 } else {
404 StringAppendF(&msg, "%#x (%d)", b, b);
405 }
406 } else if (ch == 'C') { // jchar
407 jchar c = va_arg(ap, int);
408 if (c < 0x7f && c >= ' ') {
409 StringAppendF(&msg, "U+%x ('%c')", c, c);
410 } else {
411 StringAppendF(&msg, "U+%x", c);
412 }
413 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
414 StringAppendF(&msg, "%g", va_arg(ap, double));
415 } else if (ch == 'I' || ch == 'S') { // jint, jshort
416 StringAppendF(&msg, "%d", va_arg(ap, int));
417 } else if (ch == 'J') { // jlong
418 StringAppendF(&msg, "%lld", va_arg(ap, jlong));
419 } else if (ch == 'Z') { // jboolean
420 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
421 } else if (ch == 'V') { // void
422 msg += "void";
423 } else if (ch == 'v') { // JavaVM*
424 JavaVM* vm = va_arg(ap, JavaVM*);
425 StringAppendF(&msg, "(JavaVM*)%p", vm);
426 } else if (ch == 'E') { // JNIEnv*
427 JNIEnv* env = va_arg(ap, JNIEnv*);
428 StringAppendF(&msg, "(JNIEnv*)%p", env);
429 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
430 // For logging purposes, these are identical.
431 jobject o = va_arg(ap, jobject);
432 if (o == NULL) {
433 msg += "NULL";
434 } else {
435 StringAppendF(&msg, "%p", o);
436 }
437 } else if (ch == 'b') { // jboolean (JNI-style)
438 jboolean b = va_arg(ap, int);
439 msg += (b ? "JNI_TRUE" : "JNI_FALSE");
440 } else if (ch == 'c') { // jclass
441 jclass jc = va_arg(ap, jclass);
442 Class* c = reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(jc));
443 if (c == NULL) {
444 msg += "NULL";
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800445 } else if (c == kInvalidIndirectRefObject || !Runtime::Current()->GetHeap()->IsHeapAddress(c)) {
Elliott Hughes485cac42011-12-09 17:49:35 -0800446 StringAppendF(&msg, "INVALID POINTER:%p", jc);
447 } else if (!c->IsClass()) {
448 msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700449 } else {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700450 msg += PrettyClass(c);
Elliott Hughesa2501992011-08-26 19:39:54 -0700451 if (!entry) {
452 StringAppendF(&msg, " (%p)", jc);
453 }
454 }
455 } else if (ch == 'f') { // jfieldID
456 jfieldID fid = va_arg(ap, jfieldID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700457 Field* f = reinterpret_cast<Field*>(fid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700458 msg += PrettyField(f);
459 if (!entry) {
460 StringAppendF(&msg, " (%p)", fid);
461 }
462 } else if (ch == 'z') { // non-negative jsize
463 // You might expect jsize to be size_t, but it's not; it's the same as jint.
464 // We only treat this specially so we can do the non-negative check.
465 // TODO: maybe this wasn't worth it?
466 jint i = va_arg(ap, jint);
467 StringAppendF(&msg, "%d", i);
468 } else if (ch == 'm') { // jmethodID
469 jmethodID mid = va_arg(ap, jmethodID);
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700470 Method* m = reinterpret_cast<Method*>(mid);
Elliott Hughesa2501992011-08-26 19:39:54 -0700471 msg += PrettyMethod(m);
472 if (!entry) {
473 StringAppendF(&msg, " (%p)", mid);
474 }
475 } else if (ch == 'p') { // void* ("pointer")
476 void* p = va_arg(ap, void*);
477 if (p == NULL) {
478 msg += "NULL";
479 } else {
480 StringAppendF(&msg, "(void*) %p", p);
481 }
482 } else if (ch == 'r') { // jint (release mode)
483 jint releaseMode = va_arg(ap, jint);
484 if (releaseMode == 0) {
485 msg += "0";
486 } else if (releaseMode == JNI_ABORT) {
487 msg += "JNI_ABORT";
488 } else if (releaseMode == JNI_COMMIT) {
489 msg += "JNI_COMMIT";
490 } else {
491 StringAppendF(&msg, "invalid release mode %d", releaseMode);
492 }
Elliott Hughes78090d12011-10-07 14:31:47 -0700493 } else if (ch == 'u') { // const char* (Modified UTF-8)
Elliott Hughesa2501992011-08-26 19:39:54 -0700494 const char* utf = va_arg(ap, const char*);
495 if (utf == NULL) {
496 msg += "NULL";
497 } else {
498 StringAppendF(&msg, "\"%s\"", utf);
499 }
500 } else if (ch == '.') {
501 msg += "...";
502 } else {
503 LOG(ERROR) << "unknown trace format specifier: " << ch;
504 JniAbort();
505 return;
506 }
507 if (*fmt) {
508 StringAppendF(&msg, ", ");
509 }
510 }
511 va_end(ap);
512
Elliott Hughes485cac42011-12-09 17:49:35 -0800513 if ((flags_ & kFlag_ForceTrace) != 0) {
514 LOG(INFO) << "JNI: call to " << function_name_ << "(" << msg << ")";
515 } else if (entry) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700516 if (has_method_) {
Elliott Hughesa0957642011-09-02 14:27:33 -0700517 std::string methodName(PrettyMethod(traceMethod, false));
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700518 LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
519 indent_ = methodName.size() + 1;
Elliott Hughesa2501992011-08-26 19:39:54 -0700520 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700521 LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
522 indent_ = 0;
Elliott Hughesa2501992011-08-26 19:39:54 -0700523 }
524 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700525 LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
Elliott Hughesa2501992011-08-26 19:39:54 -0700526 }
527 }
528
529 // We always do the thorough checks on entry, and never on exit...
530 if (entry) {
531 va_start(ap, fmt0);
532 for (const char* fmt = fmt0; *fmt; ++fmt) {
533 char ch = *fmt;
534 if (ch == 'a') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700535 CheckArray(va_arg(ap, jarray));
Elliott Hughesa2501992011-08-26 19:39:54 -0700536 } else if (ch == 'c') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700537 CheckInstance(kClass, va_arg(ap, jclass));
Elliott Hughesa2501992011-08-26 19:39:54 -0700538 } else if (ch == 'L') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700539 CheckObject(va_arg(ap, jobject));
Elliott Hughesa2501992011-08-26 19:39:54 -0700540 } else if (ch == 'r') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700541 CheckReleaseMode(va_arg(ap, jint));
Elliott Hughesa2501992011-08-26 19:39:54 -0700542 } else if (ch == 's') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700543 CheckInstance(kString, va_arg(ap, jstring));
Elliott Hughesa2501992011-08-26 19:39:54 -0700544 } else if (ch == 'u') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700545 if ((flags_ & kFlag_Release) != 0) {
546 CheckNonNull(va_arg(ap, const char*));
Elliott Hughesa2501992011-08-26 19:39:54 -0700547 } else {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700548 bool nullable = ((flags_ & kFlag_NullableUtf) != 0);
549 CheckUtfString(va_arg(ap, const char*), nullable);
Elliott Hughesa2501992011-08-26 19:39:54 -0700550 }
551 } else if (ch == 'z') {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700552 CheckLengthPositive(va_arg(ap, jsize));
Elliott Hughesa2501992011-08-26 19:39:54 -0700553 } else if (strchr("BCISZbfmpEv", ch) != NULL) {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800554 va_arg(ap, uint32_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700555 } else if (ch == 'D' || ch == 'F') {
556 va_arg(ap, double); // Skip this argument.
557 } else if (ch == 'J') {
Elliott Hughesba8eee12012-01-24 20:25:24 -0800558 va_arg(ap, uint64_t); // Skip this argument.
Elliott Hughesa2501992011-08-26 19:39:54 -0700559 } else if (ch == '.') {
560 } else {
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800561 LOG(FATAL) << "Unknown check format specifier: " << ch;
Elliott Hughesa2501992011-08-26 19:39:54 -0700562 }
563 }
564 va_end(ap);
565 }
566 }
567
Elliott Hughesa92853e2012-02-07 16:09:27 -0800568 enum InstanceKind {
569 kClass,
Elliott Hughes0f3c5532012-03-30 14:51:51 -0700570 kDirectByteBuffer,
571 kObject,
572 kString,
573 kThrowable,
Elliott Hughesa92853e2012-02-07 16:09:27 -0800574 };
575
576 /*
577 * Verify that "jobj" is a valid non-NULL object reference, and points to
578 * an instance of expectedClass.
579 *
580 * Because we're looking at an object on the GC heap, we have to switch
581 * to "running" mode before doing the checks.
582 */
583 bool CheckInstance(InstanceKind kind, jobject java_object) {
584 const char* what = NULL;
585 switch (kind) {
586 case kClass:
587 what = "jclass";
588 break;
589 case kDirectByteBuffer:
590 what = "direct ByteBuffer";
591 break;
592 case kObject:
593 what = "jobject";
594 break;
595 case kString:
596 what = "jstring";
597 break;
598 case kThrowable:
599 what = "jthrowable";
600 break;
601 default:
Elliott Hughes7b9d9962012-04-20 18:48:18 -0700602 LOG(FATAL) << "Unknown kind " << static_cast<int>(kind);
Elliott Hughesa92853e2012-02-07 16:09:27 -0800603 }
604
605 if (java_object == NULL) {
606 LOG(ERROR) << "JNI ERROR: " << function_name_ << " received null " << what;
607 JniAbort();
608 return false;
609 }
610
611 ScopedJniThreadState ts(env_);
612 Object* obj = Decode<Object*>(ts, java_object);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800613 if (!Runtime::Current()->GetHeap()->IsHeapAddress(obj)) {
614 LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": "
615 << java_object << " (" << obj << ")";
Elliott Hughesa92853e2012-02-07 16:09:27 -0800616 JniAbort();
617 return false;
618 }
619
620 bool okay = true;
621 switch (kind) {
622 case kClass:
623 okay = obj->IsClass();
624 break;
625 case kDirectByteBuffer:
626 UNIMPLEMENTED(FATAL);
627 break;
628 case kString:
629 okay = obj->GetClass()->IsStringClass();
630 break;
631 case kThrowable:
632 okay = obj->GetClass()->IsThrowableClass();
633 break;
634 case kObject:
635 break;
636 }
637 if (!okay) {
638 LOG(ERROR) << "JNI ERROR: " << what << " has wrong type: " << PrettyTypeOf(obj);
639 JniAbort();
640 return false;
641 }
642
643 return true;
644 }
645
Elliott Hughesba8eee12012-01-24 20:25:24 -0800646 private:
Elliott Hughes81ff3182012-03-23 20:35:56 -0700647 // Set "has_method" to true if we have a valid thread with a method pointer.
648 // We won't have one before attaching a thread, after detaching a thread, or
649 // when shutting down the runtime.
650 void Init(JNIEnv* env, JavaVM* vm, int flags, const char* functionName, bool has_method) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700651 env_ = reinterpret_cast<JNIEnvExt*>(env);
652 vm_ = reinterpret_cast<JavaVMExt*>(vm);
653 flags_ = flags;
654 function_name_ = functionName;
Elliott Hughes81ff3182012-03-23 20:35:56 -0700655 has_method_ = has_method;
Elliott Hughesa2501992011-08-26 19:39:54 -0700656 }
657
658 /*
659 * Verify that "array" is non-NULL and points to an Array object.
660 *
661 * Since we're dealing with objects, switch to "running" mode.
662 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700663 void CheckArray(jarray java_array) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700664 if (java_array == NULL) {
665 LOG(ERROR) << "JNI ERROR: received null array";
666 JniAbort();
667 return;
668 }
669
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700670 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700671 Array* a = Decode<Array*>(ts, java_array);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800672 if (!Runtime::Current()->GetHeap()->IsHeapAddress(a)) {
673 LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array) << " (" << a << ")";
Elliott Hughesa2501992011-08-26 19:39:54 -0700674 JniAbort();
675 } else if (!a->IsArrayInstance()) {
Elliott Hughes54e7df12011-09-16 11:47:04 -0700676 LOG(ERROR) << "JNI ERROR: jarray argument has non-array type: " << PrettyTypeOf(a);
Elliott Hughesa2501992011-08-26 19:39:54 -0700677 JniAbort();
678 }
679 }
680
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700681 void CheckLengthPositive(jsize length) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700682 if (length < 0) {
683 LOG(ERROR) << "JNI ERROR: negative jsize: " << length;
684 JniAbort();
685 }
686 }
687
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700688 Field* CheckFieldID(jfieldID fid) {
689 if (fid == NULL) {
690 LOG(ERROR) << "JNI ERROR: null jfieldID";
691 JniAbort();
692 return NULL;
693 }
694 Field* f = DecodeField(fid);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800695 if (!Runtime::Current()->GetHeap()->IsHeapAddress(f)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700696 LOG(ERROR) << "JNI ERROR: invalid jfieldID: " << fid;
697 JniAbort();
698 return NULL;
699 }
700 return f;
701 }
702
703 Method* CheckMethodID(jmethodID mid) {
704 if (mid == NULL) {
705 LOG(ERROR) << "JNI ERROR: null jmethodID";
706 JniAbort();
707 return NULL;
708 }
709 Method* m = DecodeMethod(mid);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800710 if (!Runtime::Current()->GetHeap()->IsHeapAddress(m)) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700711 LOG(ERROR) << "JNI ERROR: invalid jmethodID: " << mid;
712 JniAbort();
713 return NULL;
714 }
715 return m;
716 }
717
Elliott Hughesa2501992011-08-26 19:39:54 -0700718 /*
719 * Verify that "jobj" is a valid object, and that it's an object that JNI
720 * is allowed to know about. We allow NULL references.
721 *
722 * Switches to "running" mode before performing checks.
723 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700724 void CheckObject(jobject java_object) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700725 if (java_object == NULL) {
726 return;
727 }
728
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700729 ScopedJniThreadState ts(env_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700730
731 Object* o = Decode<Object*>(ts, java_object);
Elliott Hughes88c5c352012-03-15 18:49:48 -0700732 if (!Runtime::Current()->GetHeap()->IsHeapAddress(o)) {
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700733 // TODO: when we remove work_around_app_jni_bugs, this should be impossible.
Elliott Hughesa2501992011-08-26 19:39:54 -0700734 LOG(ERROR) << "JNI ERROR: native code passing in reference to invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
735 JniAbort();
736 }
737 }
738
739 /*
740 * Verify that the "mode" argument passed to a primitive array Release
741 * function is one of the valid values.
742 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700743 void CheckReleaseMode(jint mode) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700744 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
745 LOG(ERROR) << "JNI ERROR: bad value for release mode: " << mode;
746 JniAbort();
747 }
748 }
749
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700750 void CheckThread(int flags) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700751 Thread* self = Thread::Current();
752 if (self == NULL) {
Elliott Hughes81ff3182012-03-23 20:35:56 -0700753 LOG(ERROR) << "JNI ERROR: a thread is making JNI calls without being attached";
Elliott Hughesa2501992011-08-26 19:39:54 -0700754 JniAbort();
755 return;
756 }
757
758 // Get the *correct* JNIEnv by going through our TLS pointer.
759 JNIEnvExt* threadEnv = self->GetJniEnv();
760
761 /*
762 * Verify that the current thread is (a) attached and (b) associated with
763 * this particular instance of JNIEnv.
764 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700765 if (env_ != threadEnv) {
766 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNIEnv* from thread " << *env_->self;
Elliott Hughesa2501992011-08-26 19:39:54 -0700767 // If we're keeping broken code limping along, we need to suppress the abort...
Elliott Hughesc2dc62d2012-01-17 20:06:12 -0800768 if (!vm_->work_around_app_jni_bugs) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700769 JniAbort();
770 return;
771 }
772 }
773
774 /*
775 * Verify that, if this thread previously made a critical "get" call, we
776 * do the corresponding "release" call before we try anything else.
777 */
778 switch (flags & kFlag_CritMask) {
779 case kFlag_CritOkay: // okay to call this method
780 break;
781 case kFlag_CritBad: // not okay to call
782 if (threadEnv->critical) {
783 LOG(ERROR) << "JNI ERROR: thread " << *self << " using JNI after critical get";
784 JniAbort();
785 return;
786 }
787 break;
788 case kFlag_CritGet: // this is a "get" call
789 /* don't check here; we allow nested gets */
790 threadEnv->critical++;
791 break;
792 case kFlag_CritRelease: // this is a "release" call
793 threadEnv->critical--;
794 if (threadEnv->critical < 0) {
795 LOG(ERROR) << "JNI ERROR: thread " << *self << " called too many critical releases";
796 JniAbort();
797 return;
798 }
799 break;
800 default:
Elliott Hughes3d30d9b2011-12-07 17:35:48 -0800801 LOG(FATAL) << "Bad flags (internal error): " << flags;
Elliott Hughesa2501992011-08-26 19:39:54 -0700802 }
803
804 /*
805 * Verify that, if an exception has been raised, the native code doesn't
806 * make any JNI calls other than the Exception* methods.
807 */
808 if ((flags & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
Elliott Hughes30646832011-10-13 16:59:46 -0700809 std::string type(PrettyTypeOf(self->GetException()));
810 LOG(ERROR) << "JNI ERROR: JNI " << function_name_ << " called with " << type << " pending";
811 // TODO: write native code that doesn't require allocation for dumping an exception.
812 if (type != "java.lang.OutOfMemoryError") {
813 LOG(ERROR) << "Pending exception is: ";
814 LOG(ERROR) << jniGetStackTrace(env_);
815 }
Elliott Hughesa2501992011-08-26 19:39:54 -0700816 JniAbort();
817 return;
818 }
819 }
820
821 /*
Elliott Hughes78090d12011-10-07 14:31:47 -0700822 * Verify that "bytes" points to valid Modified UTF-8 data.
Elliott Hughesa2501992011-08-26 19:39:54 -0700823 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700824 void CheckUtfString(const char* bytes, bool nullable) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700825 if (bytes == NULL) {
826 if (!nullable) {
827 LOG(ERROR) << "JNI ERROR: non-nullable const char* was NULL";
828 JniAbort();
829 return;
830 }
831 return;
832 }
833
834 const char* errorKind = NULL;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700835 uint8_t utf8 = CheckUtfBytes(bytes, &errorKind);
Elliott Hughesa2501992011-08-26 19:39:54 -0700836 if (errorKind != NULL) {
Elliott Hughes78090d12011-10-07 14:31:47 -0700837 LOG(ERROR) << "JNI ERROR: input is not valid Modified UTF-8: "
838 << "illegal " << errorKind << " byte " << StringPrintf("%#x", utf8) << "\n"
839 << " string: '" << bytes << "'";
Elliott Hughesa2501992011-08-26 19:39:54 -0700840 JniAbort();
841 return;
842 }
843 }
844
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700845 static uint8_t CheckUtfBytes(const char* bytes, const char** errorKind) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700846 while (*bytes != '\0') {
847 uint8_t utf8 = *(bytes++);
848 // Switch on the high four bits.
849 switch (utf8 >> 4) {
850 case 0x00:
851 case 0x01:
852 case 0x02:
853 case 0x03:
854 case 0x04:
855 case 0x05:
856 case 0x06:
857 case 0x07:
858 // Bit pattern 0xxx. No need for any extra bytes.
859 break;
860 case 0x08:
861 case 0x09:
862 case 0x0a:
863 case 0x0b:
864 case 0x0f:
865 /*
866 * Bit pattern 10xx or 1111, which are illegal start bytes.
867 * Note: 1111 is valid for normal UTF-8, but not the
Elliott Hughes78090d12011-10-07 14:31:47 -0700868 * Modified UTF-8 used here.
Elliott Hughesa2501992011-08-26 19:39:54 -0700869 */
870 *errorKind = "start";
871 return utf8;
872 case 0x0e:
873 // Bit pattern 1110, so there are two additional bytes.
874 utf8 = *(bytes++);
875 if ((utf8 & 0xc0) != 0x80) {
876 *errorKind = "continuation";
877 return utf8;
878 }
879 // Fall through to take care of the final byte.
880 case 0x0c:
881 case 0x0d:
882 // Bit pattern 110x, so there is one additional byte.
883 utf8 = *(bytes++);
884 if ((utf8 & 0xc0) != 0x80) {
885 *errorKind = "continuation";
886 return utf8;
887 }
888 break;
889 }
890 }
891 return 0;
892 }
893
894 void JniAbort() {
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700895 ::art::JniAbort(function_name_);
Elliott Hughesa2501992011-08-26 19:39:54 -0700896 }
897
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700898 JNIEnvExt* env_;
899 JavaVMExt* vm_;
900 const char* function_name_;
901 int flags_;
902 bool has_method_;
Elliott Hughes92cb4982011-12-16 16:57:28 -0800903 int indent_;
Elliott Hughesa2501992011-08-26 19:39:54 -0700904
905 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
906};
907
908#define CHECK_JNI_ENTRY(flags, types, args...) \
909 ScopedCheck sc(env, flags, __FUNCTION__); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700910 sc.Check(true, types, ##args)
Elliott Hughesa2501992011-08-26 19:39:54 -0700911
912#define CHECK_JNI_EXIT(type, exp) ({ \
Elliott Hughes362f9bc2011-10-17 18:56:41 -0700913 typeof(exp) _rc = (exp); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700914 sc.Check(false, type, _rc); \
Elliott Hughesa2501992011-08-26 19:39:54 -0700915 _rc; })
916#define CHECK_JNI_EXIT_VOID() \
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700917 sc.Check(false, "V")
Elliott Hughesa2501992011-08-26 19:39:54 -0700918
919/*
920 * ===========================================================================
921 * Guarded arrays
922 * ===========================================================================
923 */
924
925#define kGuardLen 512 /* must be multiple of 2 */
926#define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */
927#define kGuardMagic 0xffd5aa96
928
929/* this gets tucked in at the start of the buffer; struct size must be even */
930struct GuardedCopy {
931 uint32_t magic;
932 uLong adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700933 size_t original_length;
934 const void* original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700935
936 /* find the GuardedCopy given the pointer into the "live" data */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700937 static inline const GuardedCopy* FromData(const void* dataBuf) {
938 return reinterpret_cast<const GuardedCopy*>(ActualBuffer(dataBuf));
Elliott Hughesa2501992011-08-26 19:39:54 -0700939 }
940
941 /*
942 * Create an over-sized buffer to hold the contents of "buf". Copy it in,
943 * filling in the area around it with guard data.
944 *
945 * We use a 16-bit pattern to make a rogue memset less likely to elude us.
946 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700947 static void* Create(const void* buf, size_t len, bool modOkay) {
948 size_t newLen = ActualLength(len);
949 uint8_t* newBuf = DebugAlloc(newLen);
Elliott Hughesa2501992011-08-26 19:39:54 -0700950
951 /* fill it in with a pattern */
Elliott Hughesba8eee12012-01-24 20:25:24 -0800952 uint16_t* pat = reinterpret_cast<uint16_t*>(newBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -0700953 for (size_t i = 0; i < newLen / 2; i++) {
954 *pat++ = kGuardPattern;
955 }
956
957 /* copy the data in; note "len" could be zero */
958 memcpy(newBuf + kGuardLen / 2, buf, len);
959
960 /* if modification is not expected, grab a checksum */
961 uLong adler = 0;
962 if (!modOkay) {
963 adler = adler32(0L, Z_NULL, 0);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800964 adler = adler32(adler, reinterpret_cast<const Bytef*>(buf), len);
965 *reinterpret_cast<uLong*>(newBuf) = adler;
Elliott Hughesa2501992011-08-26 19:39:54 -0700966 }
967
968 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
969 pExtra->magic = kGuardMagic;
970 pExtra->adler = adler;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700971 pExtra->original_ptr = buf;
972 pExtra->original_length = len;
Elliott Hughesa2501992011-08-26 19:39:54 -0700973
974 return newBuf + kGuardLen / 2;
975 }
976
977 /*
978 * Free up the guard buffer, scrub it, and return the original pointer.
979 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700980 static void* Destroy(void* dataBuf) {
981 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesba8eee12012-01-24 20:25:24 -0800982 void* original_ptr = const_cast<void*>(pExtra->original_ptr);
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700983 size_t len = pExtra->original_length;
984 DebugFree(dataBuf, len);
985 return original_ptr;
Elliott Hughesa2501992011-08-26 19:39:54 -0700986 }
987
988 /*
989 * Verify the guard area and, if "modOkay" is false, that the data itself
990 * has not been altered.
991 *
992 * The caller has already checked that "dataBuf" is non-NULL.
993 */
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700994 static void Check(const char* functionName, const void* dataBuf, bool modOkay) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700995 static const uint32_t kMagicCmp = kGuardMagic;
Elliott Hughes32ae6e32011-09-27 10:46:50 -0700996 const uint8_t* fullBuf = ActualBuffer(dataBuf);
997 const GuardedCopy* pExtra = GuardedCopy::FromData(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -0700998
999 /*
1000 * Before we do anything with "pExtra", check the magic number. We
1001 * do the check with memcmp rather than "==" in case the pointer is
1002 * unaligned. If it points to completely bogus memory we're going
1003 * to crash, but there's no easy way around that.
1004 */
1005 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
1006 uint8_t buf[4];
1007 memcpy(buf, &pExtra->magic, 4);
1008 LOG(ERROR) << StringPrintf("JNI: guard magic does not match "
1009 "(found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
1010 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
1011 JniAbort(functionName);
1012 }
1013
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001014 size_t len = pExtra->original_length;
Elliott Hughesa2501992011-08-26 19:39:54 -07001015
1016 /* check bottom half of guard; skip over optional checksum storage */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001017 const uint16_t* pat = reinterpret_cast<const uint16_t*>(fullBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001018 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
1019 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001020 LOG(ERROR) << "JNI: guard pattern(1) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001021 JniAbort(functionName);
1022 }
1023 }
1024
1025 int offset = kGuardLen / 2 + len;
1026 if (offset & 0x01) {
1027 /* odd byte; expected value depends on endian-ness of host */
1028 const uint16_t patSample = kGuardPattern;
Elliott Hughesba8eee12012-01-24 20:25:24 -08001029 if (fullBuf[offset] != reinterpret_cast<const uint8_t*>(&patSample)[1]) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001030 LOG(ERROR) << "JNI: guard pattern disturbed in odd byte after "
Elliott Hughesba8eee12012-01-24 20:25:24 -08001031 << reinterpret_cast<const void*>(fullBuf) << " (+" << offset << ") "
Elliott Hughesa2501992011-08-26 19:39:54 -07001032 << StringPrintf("0x%02x 0x%02x", fullBuf[offset], ((const uint8_t*) &patSample)[1]);
1033 JniAbort(functionName);
1034 }
1035 offset++;
1036 }
1037
1038 /* check top half of guard */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001039 pat = reinterpret_cast<const uint16_t*>(fullBuf + offset);
Elliott Hughesa2501992011-08-26 19:39:54 -07001040 for (size_t i = 0; i < kGuardLen / 4; i++) {
1041 if (pat[i] != kGuardPattern) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001042 LOG(ERROR) << "JNI: guard pattern(2) disturbed at " << reinterpret_cast<const void*>(fullBuf) << " + " << (offset + i*2);
Elliott Hughesa2501992011-08-26 19:39:54 -07001043 JniAbort(functionName);
1044 }
1045 }
1046
1047 /*
1048 * If modification is not expected, verify checksum. Strictly speaking
1049 * this is wrong: if we told the client that we made a copy, there's no
1050 * reason they can't alter the buffer.
1051 */
1052 if (!modOkay) {
1053 uLong adler = adler32(0L, Z_NULL, 0);
1054 adler = adler32(adler, (const Bytef*)dataBuf, len);
1055 if (pExtra->adler != adler) {
1056 LOG(ERROR) << StringPrintf("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", pExtra->adler, adler, dataBuf);
1057 JniAbort(functionName);
1058 }
1059 }
1060 }
1061
1062 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001063 static uint8_t* DebugAlloc(size_t len) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001064 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1065 if (result == MAP_FAILED) {
1066 PLOG(FATAL) << "GuardedCopy::create mmap(" << len << ") failed";
1067 }
1068 return reinterpret_cast<uint8_t*>(result);
1069 }
1070
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001071 static void DebugFree(void* dataBuf, size_t len) {
1072 uint8_t* fullBuf = ActualBuffer(dataBuf);
1073 size_t totalByteCount = ActualLength(len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001074 // TODO: we could mprotect instead, and keep the allocation around for a while.
1075 // This would be even more expensive, but it might catch more errors.
1076 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
Elliott Hughes7b9d9962012-04-20 18:48:18 -07001077 // PLOG(WARNING) << "mprotect(PROT_NONE) failed";
Elliott Hughesa2501992011-08-26 19:39:54 -07001078 // }
1079 if (munmap(fullBuf, totalByteCount) != 0) {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001080 PLOG(FATAL) << "munmap(" << reinterpret_cast<void*>(fullBuf) << ", " << totalByteCount << ") failed";
Elliott Hughesa2501992011-08-26 19:39:54 -07001081 }
1082 }
1083
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001084 static const uint8_t* ActualBuffer(const void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001085 return reinterpret_cast<const uint8_t*>(dataBuf) - kGuardLen / 2;
1086 }
1087
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001088 static uint8_t* ActualBuffer(void* dataBuf) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001089 return reinterpret_cast<uint8_t*>(dataBuf) - kGuardLen / 2;
1090 }
1091
1092 // Underlying length of a user allocation of 'length' bytes.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001093 static size_t ActualLength(size_t length) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001094 return (length + kGuardLen + 1) & ~0x01;
1095 }
1096};
1097
1098/*
1099 * Create a guarded copy of a primitive array. Modifications to the copied
1100 * data are allowed. Returns a pointer to the copied data.
1101 */
1102void* CreateGuardedPACopy(JNIEnv* env, const jarray java_array, jboolean* isCopy) {
1103 ScopedJniThreadState ts(env);
1104
1105 Array* a = Decode<Array*>(ts, java_array);
Ian Rogersa15e67d2012-02-28 13:51:55 -08001106 size_t component_size = a->GetClass()->GetComponentSize();
1107 size_t byte_count = a->GetLength() * component_size;
1108 void* result = GuardedCopy::Create(a->GetRawData(component_size), byte_count, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001109 if (isCopy != NULL) {
1110 *isCopy = JNI_TRUE;
1111 }
1112 return result;
1113}
1114
1115/*
1116 * Perform the array "release" operation, which may or may not copy data
Elliott Hughes81ff3182012-03-23 20:35:56 -07001117 * back into the managed heap, and may or may not release the underlying storage.
Elliott Hughesa2501992011-08-26 19:39:54 -07001118 */
1119void ReleaseGuardedPACopy(JNIEnv* env, jarray java_array, void* dataBuf, int mode) {
1120 if (reinterpret_cast<uintptr_t>(dataBuf) == kNoCopyMagic) {
1121 return;
1122 }
1123
1124 ScopedJniThreadState ts(env);
1125 Array* a = Decode<Array*>(ts, java_array);
1126
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001127 GuardedCopy::Check(__FUNCTION__, dataBuf, true);
Elliott Hughesa2501992011-08-26 19:39:54 -07001128
1129 if (mode != JNI_ABORT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001130 size_t len = GuardedCopy::FromData(dataBuf)->original_length;
Ian Rogersa15e67d2012-02-28 13:51:55 -08001131 memcpy(a->GetRawData(a->GetClass()->GetComponentSize()), dataBuf, len);
Elliott Hughesa2501992011-08-26 19:39:54 -07001132 }
1133 if (mode != JNI_COMMIT) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001134 GuardedCopy::Destroy(dataBuf);
Elliott Hughesa2501992011-08-26 19:39:54 -07001135 }
1136}
1137
1138/*
1139 * ===========================================================================
1140 * JNI functions
1141 * ===========================================================================
1142 */
1143
1144class CheckJNI {
1145 public:
1146 static jint GetVersion(JNIEnv* env) {
1147 CHECK_JNI_ENTRY(kFlag_Default, "E", env);
1148 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
1149 }
1150
1151 static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf, jsize bufLen) {
1152 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001153 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001154 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
1155 }
1156
1157 static jclass FindClass(JNIEnv* env, const char* name) {
1158 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001159 sc.CheckClassName(name);
Elliott Hughesa2501992011-08-26 19:39:54 -07001160 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
1161 }
1162
Elliott Hughese84278b2012-03-22 10:06:53 -07001163 static jclass GetSuperclass(JNIEnv* env, jclass c) {
1164 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, c);
1165 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, c));
Elliott Hughesa2501992011-08-26 19:39:54 -07001166 }
1167
Elliott Hughese84278b2012-03-22 10:06:53 -07001168 static jboolean IsAssignableFrom(JNIEnv* env, jclass c1, jclass c2) {
1169 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, c1, c2);
1170 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, c1, c2));
Elliott Hughesa2501992011-08-26 19:39:54 -07001171 }
1172
1173 static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
1174 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
1175 // TODO: check that 'field' is a java.lang.reflect.Method.
1176 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
1177 }
1178
1179 static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
1180 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
1181 // TODO: check that 'field' is a java.lang.reflect.Field.
1182 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
1183 }
1184
1185 static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
1186 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, mid, isStatic);
1187 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, mid, isStatic));
1188 }
1189
1190 static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
1191 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fid, isStatic);
1192 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fid, isStatic));
1193 }
1194
1195 static jint Throw(JNIEnv* env, jthrowable obj) {
1196 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1197 // TODO: check that 'obj' is a java.lang.Throwable.
1198 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
1199 }
1200
Elliott Hughese84278b2012-03-22 10:06:53 -07001201 static jint ThrowNew(JNIEnv* env, jclass c, const char* message) {
1202 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, c, message);
1203 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, c, message));
Elliott Hughesa2501992011-08-26 19:39:54 -07001204 }
1205
1206 static jthrowable ExceptionOccurred(JNIEnv* env) {
1207 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1208 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
1209 }
1210
1211 static void ExceptionDescribe(JNIEnv* env) {
1212 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1213 baseEnv(env)->ExceptionDescribe(env);
1214 CHECK_JNI_EXIT_VOID();
1215 }
1216
1217 static void ExceptionClear(JNIEnv* env) {
1218 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1219 baseEnv(env)->ExceptionClear(env);
1220 CHECK_JNI_EXIT_VOID();
1221 }
1222
1223 static void FatalError(JNIEnv* env, const char* msg) {
1224 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
1225 baseEnv(env)->FatalError(env, msg);
1226 CHECK_JNI_EXIT_VOID();
1227 }
1228
1229 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1230 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
1231 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
1232 }
1233
1234 static jobject PopLocalFrame(JNIEnv* env, jobject res) {
1235 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
1236 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
1237 }
1238
1239 static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
1240 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1241 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
1242 }
1243
1244 static jobject NewLocalRef(JNIEnv* env, jobject ref) {
1245 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
1246 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
1247 }
1248
1249 static void DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
1250 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
1251 if (globalRef != NULL && GetIndirectRefKind(globalRef) != kGlobal) {
1252 LOG(ERROR) << "JNI ERROR: DeleteGlobalRef on " << GetIndirectRefKind(globalRef) << ": " << globalRef;
1253 JniAbort(__FUNCTION__);
1254 } else {
1255 baseEnv(env)->DeleteGlobalRef(env, globalRef);
1256 CHECK_JNI_EXIT_VOID();
1257 }
1258 }
1259
1260 static void DeleteWeakGlobalRef(JNIEnv* env, jweak weakGlobalRef) {
1261 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, weakGlobalRef);
1262 if (weakGlobalRef != NULL && GetIndirectRefKind(weakGlobalRef) != kWeakGlobal) {
1263 LOG(ERROR) << "JNI ERROR: DeleteWeakGlobalRef on " << GetIndirectRefKind(weakGlobalRef) << ": " << weakGlobalRef;
1264 JniAbort(__FUNCTION__);
1265 } else {
1266 baseEnv(env)->DeleteWeakGlobalRef(env, weakGlobalRef);
1267 CHECK_JNI_EXIT_VOID();
1268 }
1269 }
1270
1271 static void DeleteLocalRef(JNIEnv* env, jobject localRef) {
1272 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
Ian Rogers959f8ed2012-02-07 16:33:37 -08001273 if (localRef != NULL && GetIndirectRefKind(localRef) != kLocal && !IsSirtLocalRef(env, localRef)) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001274 LOG(ERROR) << "JNI ERROR: DeleteLocalRef on " << GetIndirectRefKind(localRef) << ": " << localRef;
1275 JniAbort(__FUNCTION__);
1276 } else {
1277 baseEnv(env)->DeleteLocalRef(env, localRef);
1278 CHECK_JNI_EXIT_VOID();
1279 }
1280 }
1281
1282 static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
1283 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
1284 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
1285 }
1286
1287 static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
1288 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
1289 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
1290 }
1291
Elliott Hughese84278b2012-03-22 10:06:53 -07001292 static jobject AllocObject(JNIEnv* env, jclass c) {
1293 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, c);
1294 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, c));
Elliott Hughesa2501992011-08-26 19:39:54 -07001295 }
1296
Elliott Hughese84278b2012-03-22 10:06:53 -07001297 static jobject NewObject(JNIEnv* env, jclass c, jmethodID mid, ...) {
1298 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, c, mid);
Elliott Hughesa2501992011-08-26 19:39:54 -07001299 va_list args;
1300 va_start(args, mid);
Elliott Hughese84278b2012-03-22 10:06:53 -07001301 jobject result = baseEnv(env)->NewObjectV(env, c, mid, args);
Elliott Hughesa2501992011-08-26 19:39:54 -07001302 va_end(args);
1303 return CHECK_JNI_EXIT("L", result);
1304 }
1305
Elliott Hughese84278b2012-03-22 10:06:53 -07001306 static jobject NewObjectV(JNIEnv* env, jclass c, jmethodID mid, va_list args) {
1307 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, c, mid);
1308 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, c, mid, args));
Elliott Hughesa2501992011-08-26 19:39:54 -07001309 }
1310
Elliott Hughese84278b2012-03-22 10:06:53 -07001311 static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, jvalue* args) {
1312 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, c, mid);
1313 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, c, mid, args));
Elliott Hughesa2501992011-08-26 19:39:54 -07001314 }
1315
1316 static jclass GetObjectClass(JNIEnv* env, jobject obj) {
1317 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1318 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
1319 }
1320
Elliott Hughese84278b2012-03-22 10:06:53 -07001321 static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass c) {
1322 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, c);
1323 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, c));
Elliott Hughesa2501992011-08-26 19:39:54 -07001324 }
1325
Elliott Hughese84278b2012-03-22 10:06:53 -07001326 static jmethodID GetMethodID(JNIEnv* env, jclass c, const char* name, const char* sig) {
1327 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, c, name, sig);
1328 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, c, name, sig));
Elliott Hughesa2501992011-08-26 19:39:54 -07001329 }
1330
Elliott Hughese84278b2012-03-22 10:06:53 -07001331 static jfieldID GetFieldID(JNIEnv* env, jclass c, const char* name, const char* sig) {
1332 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, c, name, sig);
1333 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, c, name, sig));
Elliott Hughesa2501992011-08-26 19:39:54 -07001334 }
1335
Elliott Hughese84278b2012-03-22 10:06:53 -07001336 static jmethodID GetStaticMethodID(JNIEnv* env, jclass c, const char* name, const char* sig) {
1337 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, c, name, sig);
1338 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, c, name, sig));
Elliott Hughesa2501992011-08-26 19:39:54 -07001339 }
1340
Elliott Hughese84278b2012-03-22 10:06:53 -07001341 static jfieldID GetStaticFieldID(JNIEnv* env, jclass c, const char* name, const char* sig) {
1342 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, c, name, sig);
1343 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, c, name, sig));
Elliott Hughesa2501992011-08-26 19:39:54 -07001344 }
1345
1346#define FIELD_ACCESSORS(_ctype, _jname, _type) \
Elliott Hughese84278b2012-03-22 10:06:53 -07001347 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass c, jfieldID fid) { \
1348 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, c, fid); \
1349 sc.CheckStaticFieldID(c, fid); \
1350 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, c, fid)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001351 } \
1352 static _ctype Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid) { \
1353 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fid); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001354 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001355 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fid)); \
1356 } \
Elliott Hughese84278b2012-03-22 10:06:53 -07001357 static void SetStatic##_jname##Field(JNIEnv* env, jclass c, jfieldID fid, _ctype value) { \
1358 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, c, fid, value); \
1359 sc.CheckStaticFieldID(c, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001360 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001361 sc.CheckFieldType((jobject)(uint32_t)value, fid, _type[0], true); \
Elliott Hughese84278b2012-03-22 10:06:53 -07001362 baseEnv(env)->SetStatic##_jname##Field(env, c, fid, value); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001363 CHECK_JNI_EXIT_VOID(); \
1364 } \
1365 static void Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fid, _ctype value) { \
1366 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fid, value); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001367 sc.CheckInstanceFieldID(obj, fid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001368 /* "value" arg only used when type == ref */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001369 sc.CheckFieldType((jobject)(uint32_t) value, fid, _type[0], false); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001370 baseEnv(env)->Set##_jname##Field(env, obj, fid, value); \
1371 CHECK_JNI_EXIT_VOID(); \
1372 }
1373
1374FIELD_ACCESSORS(jobject, Object, "L");
1375FIELD_ACCESSORS(jboolean, Boolean, "Z");
1376FIELD_ACCESSORS(jbyte, Byte, "B");
1377FIELD_ACCESSORS(jchar, Char, "C");
1378FIELD_ACCESSORS(jshort, Short, "S");
1379FIELD_ACCESSORS(jint, Int, "I");
1380FIELD_ACCESSORS(jlong, Long, "J");
1381FIELD_ACCESSORS(jfloat, Float, "F");
1382FIELD_ACCESSORS(jdouble, Double, "D");
1383
1384#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
1385 /* Virtual... */ \
1386 static _ctype Call##_jname##Method(JNIEnv* env, jobject obj, \
1387 jmethodID mid, ...) \
1388 { \
1389 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001390 sc.CheckSig(mid, _retsig, false); \
1391 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001392 _retdecl; \
1393 va_list args; \
1394 va_start(args, mid); \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001395 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001396 va_end(args); \
1397 _retok; \
1398 } \
1399 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1400 jmethodID mid, va_list args) \
1401 { \
1402 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001403 sc.CheckSig(mid, _retsig, false); \
1404 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001405 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001406 _retasgn(baseEnv(env)->Call##_jname##MethodV(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001407 _retok; \
1408 } \
1409 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1410 jmethodID mid, jvalue* args) \
1411 { \
1412 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001413 sc.CheckSig(mid, _retsig, false); \
1414 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001415 _retdecl; \
Elliott Hughesba8eee12012-01-24 20:25:24 -08001416 _retasgn(baseEnv(env)->Call##_jname##MethodA(env, obj, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001417 _retok; \
1418 } \
1419 /* Non-virtual... */ \
1420 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, \
Elliott Hughese84278b2012-03-22 10:06:53 -07001421 jobject obj, jclass c, jmethodID mid, ...) \
Elliott Hughesa2501992011-08-26 19:39:54 -07001422 { \
Elliott Hughese84278b2012-03-22 10:06:53 -07001423 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, c, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001424 sc.CheckSig(mid, _retsig, false); \
1425 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001426 _retdecl; \
1427 va_list args; \
1428 va_start(args, mid); \
Elliott Hughese84278b2012-03-22 10:06:53 -07001429 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, c, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001430 va_end(args); \
1431 _retok; \
1432 } \
1433 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, \
Elliott Hughese84278b2012-03-22 10:06:53 -07001434 jobject obj, jclass c, jmethodID mid, va_list args) \
Elliott Hughesa2501992011-08-26 19:39:54 -07001435 { \
Elliott Hughese84278b2012-03-22 10:06:53 -07001436 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, c, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001437 sc.CheckSig(mid, _retsig, false); \
1438 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001439 _retdecl; \
Elliott Hughese84278b2012-03-22 10:06:53 -07001440 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, c, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001441 _retok; \
1442 } \
1443 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, \
Elliott Hughese84278b2012-03-22 10:06:53 -07001444 jobject obj, jclass c, jmethodID mid, jvalue* args) \
Elliott Hughesa2501992011-08-26 19:39:54 -07001445 { \
Elliott Hughese84278b2012-03-22 10:06:53 -07001446 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, c, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001447 sc.CheckSig(mid, _retsig, false); \
1448 sc.CheckVirtualMethod(obj, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001449 _retdecl; \
Elliott Hughese84278b2012-03-22 10:06:53 -07001450 _retasgn(baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, c, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001451 _retok; \
1452 } \
1453 /* Static... */ \
Elliott Hughese84278b2012-03-22 10:06:53 -07001454 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass c, jmethodID mid, ...) \
Elliott Hughesa2501992011-08-26 19:39:54 -07001455 { \
Elliott Hughese84278b2012-03-22 10:06:53 -07001456 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, c, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001457 sc.CheckSig(mid, _retsig, true); \
Elliott Hughese84278b2012-03-22 10:06:53 -07001458 sc.CheckStaticMethod(c, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001459 _retdecl; \
1460 va_list args; \
1461 va_start(args, mid); \
Elliott Hughese84278b2012-03-22 10:06:53 -07001462 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, c, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001463 va_end(args); \
1464 _retok; \
1465 } \
Elliott Hughese84278b2012-03-22 10:06:53 -07001466 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass c, jmethodID mid, va_list args) \
Elliott Hughesa2501992011-08-26 19:39:54 -07001467 { \
Elliott Hughese84278b2012-03-22 10:06:53 -07001468 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, c, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001469 sc.CheckSig(mid, _retsig, true); \
Elliott Hughese84278b2012-03-22 10:06:53 -07001470 sc.CheckStaticMethod(c, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001471 _retdecl; \
Elliott Hughese84278b2012-03-22 10:06:53 -07001472 _retasgn(baseEnv(env)->CallStatic##_jname##MethodV(env, c, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001473 _retok; \
1474 } \
Elliott Hughese84278b2012-03-22 10:06:53 -07001475 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass c, jmethodID mid, jvalue* args) \
Elliott Hughesa2501992011-08-26 19:39:54 -07001476 { \
Elliott Hughese84278b2012-03-22 10:06:53 -07001477 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, c, mid); /* TODO: args! */ \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001478 sc.CheckSig(mid, _retsig, true); \
Elliott Hughese84278b2012-03-22 10:06:53 -07001479 sc.CheckStaticMethod(c, mid); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001480 _retdecl; \
Elliott Hughese84278b2012-03-22 10:06:53 -07001481 _retasgn(baseEnv(env)->CallStatic##_jname##MethodA(env, c, mid, args)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001482 _retok; \
1483 }
1484
1485#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
1486#define VOID_RETURN CHECK_JNI_EXIT_VOID()
1487
Elliott Hughesba8eee12012-01-24 20:25:24 -08001488CALL(jobject, Object, Object* result, result = reinterpret_cast<Object*>, NON_VOID_RETURN("L", jobject), "L");
1489CALL(jboolean, Boolean, jboolean result, result =, NON_VOID_RETURN("Z", jboolean), "Z");
1490CALL(jbyte, Byte, jbyte result, result =, NON_VOID_RETURN("B", jbyte), "B");
1491CALL(jchar, Char, jchar result, result =, NON_VOID_RETURN("C", jchar), "C");
1492CALL(jshort, Short, jshort result, result =, NON_VOID_RETURN("S", jshort), "S");
1493CALL(jint, Int, jint result, result =, NON_VOID_RETURN("I", jint), "I");
1494CALL(jlong, Long, jlong result, result =, NON_VOID_RETURN("J", jlong), "J");
1495CALL(jfloat, Float, jfloat result, result =, NON_VOID_RETURN("F", jfloat), "F");
1496CALL(jdouble, Double, jdouble result, result =, NON_VOID_RETURN("D", jdouble), "D");
Elliott Hughesa2501992011-08-26 19:39:54 -07001497CALL(void, Void, , , VOID_RETURN, "V");
1498
1499 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
1500 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
1501 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
1502 }
1503
1504 static jsize GetStringLength(JNIEnv* env, jstring string) {
1505 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1506 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
1507 }
1508
1509 static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1510 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, java_string, isCopy);
1511 const jchar* result = baseEnv(env)->GetStringChars(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001512 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001513 ScopedJniThreadState ts(env);
1514 String* s = Decode<String*>(ts, java_string);
1515 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001516 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001517 if (isCopy != NULL) {
1518 *isCopy = JNI_TRUE;
1519 }
1520 }
1521 return CHECK_JNI_EXIT("p", result);
1522 }
1523
1524 static void ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
1525 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001526 sc.CheckNonNull(chars);
1527 if (sc.ForceCopy()) {
1528 GuardedCopy::Check(__FUNCTION__, chars, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001529 chars = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(chars)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001530 }
1531 baseEnv(env)->ReleaseStringChars(env, string, chars);
1532 CHECK_JNI_EXIT_VOID();
1533 }
1534
1535 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
1536 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
1537 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
1538 }
1539
1540 static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
1541 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1542 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
1543 }
1544
1545 static const char* GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1546 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1547 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001548 if (sc.ForceCopy() && result != NULL) {
1549 result = (const char*) GuardedCopy::Create(result, strlen(result) + 1, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001550 if (isCopy != NULL) {
1551 *isCopy = JNI_TRUE;
1552 }
1553 }
1554 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
1555 }
1556
1557 static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
1558 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001559 if (sc.ForceCopy()) {
1560 GuardedCopy::Check(__FUNCTION__, utf, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001561 utf = reinterpret_cast<const char*>(GuardedCopy::Destroy(const_cast<char*>(utf)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001562 }
1563 baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
1564 CHECK_JNI_EXIT_VOID();
1565 }
1566
1567 static jsize GetArrayLength(JNIEnv* env, jarray array) {
1568 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
1569 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
1570 }
1571
1572 static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass elementClass, jobject initialElement) {
1573 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
1574 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
1575 }
1576
1577 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
1578 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
1579 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
1580 }
1581
1582 static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
1583 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
1584 baseEnv(env)->SetObjectArrayElement(env, array, index, value);
1585 CHECK_JNI_EXIT_VOID();
1586 }
1587
1588#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
1589 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
1590 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
1591 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
1592 }
1593NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
1594NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
1595NEW_PRIMITIVE_ARRAY(jcharArray, Char);
1596NEW_PRIMITIVE_ARRAY(jshortArray, Short);
1597NEW_PRIMITIVE_ARRAY(jintArray, Int);
1598NEW_PRIMITIVE_ARRAY(jlongArray, Long);
1599NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
1600NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
1601
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001602struct ForceCopyGetChecker {
Elliott Hughesba8eee12012-01-24 20:25:24 -08001603 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07001604 ForceCopyGetChecker(ScopedCheck& sc, jboolean* isCopy) {
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001605 force_copy = sc.ForceCopy();
1606 no_copy = 0;
1607 if (force_copy && isCopy != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001608 /* capture this before the base call tramples on it */
Elliott Hughesba8eee12012-01-24 20:25:24 -08001609 no_copy = *reinterpret_cast<uint32_t*>(isCopy);
Elliott Hughesa2501992011-08-26 19:39:54 -07001610 }
1611 }
1612
1613 template<typename ResultT>
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001614 ResultT Check(JNIEnv* env, jarray array, jboolean* isCopy, ResultT result) {
1615 if (force_copy && result != NULL) {
1616 if (no_copy != kNoCopyMagic) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001617 result = reinterpret_cast<ResultT>(CreateGuardedPACopy(env, array, isCopy));
1618 }
1619 }
1620 return result;
1621 }
1622
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001623 uint32_t no_copy;
1624 bool force_copy;
Elliott Hughesa2501992011-08-26 19:39:54 -07001625};
1626
1627#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1628 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, jboolean* isCopy) { \
1629 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001630 _ctype* result = ForceCopyGetChecker(sc, isCopy).Check(env, array, isCopy, baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy)); \
Elliott Hughesa2501992011-08-26 19:39:54 -07001631 return CHECK_JNI_EXIT("p", result); \
1632 }
1633
1634#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1635 static void Release##_jname##ArrayElements(JNIEnv* env, _ctype##Array array, _ctype* elems, jint mode) { \
1636 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001637 sc.CheckNonNull(elems); \
1638 if (sc.ForceCopy()) { \
Elliott Hughesa2501992011-08-26 19:39:54 -07001639 ReleaseGuardedPACopy(env, array, elems, mode); \
1640 } \
1641 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
1642 CHECK_JNI_EXIT_VOID(); \
1643 }
1644
1645#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1646 static void Get##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
1647 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1648 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
1649 CHECK_JNI_EXIT_VOID(); \
1650 }
1651
1652#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1653 static void Set##_jname##ArrayRegion(JNIEnv* env, _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
1654 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1655 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
1656 CHECK_JNI_EXIT_VOID(); \
1657 }
1658
1659#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
1660 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1661 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1662 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
1663 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
1664
1665/* TODO: verify primitive array type matches call type */
1666PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
1667PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
1668PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
1669PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
1670PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
1671PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
1672PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
1673PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
1674
Elliott Hughese84278b2012-03-22 10:06:53 -07001675 static jint RegisterNatives(JNIEnv* env, jclass c, const JNINativeMethod* methods, jint nMethods) {
1676 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, c, methods, nMethods);
1677 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, c, methods, nMethods));
Elliott Hughesa2501992011-08-26 19:39:54 -07001678 }
1679
Elliott Hughese84278b2012-03-22 10:06:53 -07001680 static jint UnregisterNatives(JNIEnv* env, jclass c) {
1681 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, c);
1682 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, c));
Elliott Hughesa2501992011-08-26 19:39:54 -07001683 }
1684
1685 static jint MonitorEnter(JNIEnv* env, jobject obj) {
1686 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
Elliott Hughesa92853e2012-02-07 16:09:27 -08001687 if (!sc.CheckInstance(ScopedCheck::kObject, obj)) {
1688 return JNI_ERR; // Only for jni_internal_test. Real code will have aborted already.
1689 }
Elliott Hughesa2501992011-08-26 19:39:54 -07001690 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
1691 }
1692
1693 static jint MonitorExit(JNIEnv* env, jobject obj) {
1694 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
Elliott Hughesa92853e2012-02-07 16:09:27 -08001695 if (!sc.CheckInstance(ScopedCheck::kObject, obj)) {
1696 return JNI_ERR; // Only for jni_internal_test. Real code will have aborted already.
1697 }
Elliott Hughesa2501992011-08-26 19:39:54 -07001698 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
1699 }
1700
1701 static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
1702 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
1703 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
1704 }
1705
1706 static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
1707 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1708 baseEnv(env)->GetStringRegion(env, str, start, len, buf);
1709 CHECK_JNI_EXIT_VOID();
1710 }
1711
1712 static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
1713 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1714 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
1715 CHECK_JNI_EXIT_VOID();
1716 }
1717
1718 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
1719 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
1720 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001721 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001722 result = CreateGuardedPACopy(env, array, isCopy);
1723 }
1724 return CHECK_JNI_EXIT("p", result);
1725 }
1726
1727 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
1728 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001729 sc.CheckNonNull(carray);
1730 if (sc.ForceCopy()) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001731 ReleaseGuardedPACopy(env, array, carray, mode);
1732 }
1733 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
1734 CHECK_JNI_EXIT_VOID();
1735 }
1736
1737 static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* isCopy) {
1738 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, java_string, isCopy);
1739 const jchar* result = baseEnv(env)->GetStringCritical(env, java_string, isCopy);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001740 if (sc.ForceCopy() && result != NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -07001741 ScopedJniThreadState ts(env);
1742 String* s = Decode<String*>(ts, java_string);
1743 int byteCount = s->GetLength() * 2;
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001744 result = (const jchar*) GuardedCopy::Create(result, byteCount, false);
Elliott Hughesa2501992011-08-26 19:39:54 -07001745 if (isCopy != NULL) {
1746 *isCopy = JNI_TRUE;
1747 }
1748 }
1749 return CHECK_JNI_EXIT("p", result);
1750 }
1751
1752 static void ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
1753 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07001754 sc.CheckNonNull(carray);
1755 if (sc.ForceCopy()) {
1756 GuardedCopy::Check(__FUNCTION__, carray, false);
Elliott Hughesba8eee12012-01-24 20:25:24 -08001757 carray = reinterpret_cast<const jchar*>(GuardedCopy::Destroy(const_cast<jchar*>(carray)));
Elliott Hughesa2501992011-08-26 19:39:54 -07001758 }
1759 baseEnv(env)->ReleaseStringCritical(env, string, carray);
1760 CHECK_JNI_EXIT_VOID();
1761 }
1762
1763 static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
1764 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1765 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
1766 }
1767
1768 static jboolean ExceptionCheck(JNIEnv* env) {
1769 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
1770 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
1771 }
1772
1773 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
1774 // Note: we use "Ep" rather than "EL" because this is the one JNI function
1775 // that it's okay to pass an invalid reference to.
1776 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, obj);
1777 // TODO: proper decoding of jobjectRefType!
1778 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
1779 }
1780
1781 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
1782 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
1783 if (address == NULL) {
1784 LOG(ERROR) << "JNI ERROR: non-nullable address is NULL";
1785 JniAbort(__FUNCTION__);
1786 }
1787 if (capacity <= 0) {
1788 LOG(ERROR) << "JNI ERROR: capacity must be greater than 0: " << capacity;
1789 JniAbort(__FUNCTION__);
1790 }
1791 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
1792 }
1793
1794 static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
1795 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1796 // TODO: check that 'buf' is a java.nio.Buffer.
1797 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
1798 }
1799
1800 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
1801 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1802 // TODO: check that 'buf' is a java.nio.Buffer.
1803 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
1804 }
1805
1806 private:
1807 static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
1808 return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions;
1809 }
1810};
1811
1812const JNINativeInterface gCheckNativeInterface = {
1813 NULL, // reserved0.
1814 NULL, // reserved1.
1815 NULL, // reserved2.
1816 NULL, // reserved3.
1817 CheckJNI::GetVersion,
1818 CheckJNI::DefineClass,
1819 CheckJNI::FindClass,
1820 CheckJNI::FromReflectedMethod,
1821 CheckJNI::FromReflectedField,
1822 CheckJNI::ToReflectedMethod,
1823 CheckJNI::GetSuperclass,
1824 CheckJNI::IsAssignableFrom,
1825 CheckJNI::ToReflectedField,
1826 CheckJNI::Throw,
1827 CheckJNI::ThrowNew,
1828 CheckJNI::ExceptionOccurred,
1829 CheckJNI::ExceptionDescribe,
1830 CheckJNI::ExceptionClear,
1831 CheckJNI::FatalError,
1832 CheckJNI::PushLocalFrame,
1833 CheckJNI::PopLocalFrame,
1834 CheckJNI::NewGlobalRef,
1835 CheckJNI::DeleteGlobalRef,
1836 CheckJNI::DeleteLocalRef,
1837 CheckJNI::IsSameObject,
1838 CheckJNI::NewLocalRef,
1839 CheckJNI::EnsureLocalCapacity,
1840 CheckJNI::AllocObject,
1841 CheckJNI::NewObject,
1842 CheckJNI::NewObjectV,
1843 CheckJNI::NewObjectA,
1844 CheckJNI::GetObjectClass,
1845 CheckJNI::IsInstanceOf,
1846 CheckJNI::GetMethodID,
1847 CheckJNI::CallObjectMethod,
1848 CheckJNI::CallObjectMethodV,
1849 CheckJNI::CallObjectMethodA,
1850 CheckJNI::CallBooleanMethod,
1851 CheckJNI::CallBooleanMethodV,
1852 CheckJNI::CallBooleanMethodA,
1853 CheckJNI::CallByteMethod,
1854 CheckJNI::CallByteMethodV,
1855 CheckJNI::CallByteMethodA,
1856 CheckJNI::CallCharMethod,
1857 CheckJNI::CallCharMethodV,
1858 CheckJNI::CallCharMethodA,
1859 CheckJNI::CallShortMethod,
1860 CheckJNI::CallShortMethodV,
1861 CheckJNI::CallShortMethodA,
1862 CheckJNI::CallIntMethod,
1863 CheckJNI::CallIntMethodV,
1864 CheckJNI::CallIntMethodA,
1865 CheckJNI::CallLongMethod,
1866 CheckJNI::CallLongMethodV,
1867 CheckJNI::CallLongMethodA,
1868 CheckJNI::CallFloatMethod,
1869 CheckJNI::CallFloatMethodV,
1870 CheckJNI::CallFloatMethodA,
1871 CheckJNI::CallDoubleMethod,
1872 CheckJNI::CallDoubleMethodV,
1873 CheckJNI::CallDoubleMethodA,
1874 CheckJNI::CallVoidMethod,
1875 CheckJNI::CallVoidMethodV,
1876 CheckJNI::CallVoidMethodA,
1877 CheckJNI::CallNonvirtualObjectMethod,
1878 CheckJNI::CallNonvirtualObjectMethodV,
1879 CheckJNI::CallNonvirtualObjectMethodA,
1880 CheckJNI::CallNonvirtualBooleanMethod,
1881 CheckJNI::CallNonvirtualBooleanMethodV,
1882 CheckJNI::CallNonvirtualBooleanMethodA,
1883 CheckJNI::CallNonvirtualByteMethod,
1884 CheckJNI::CallNonvirtualByteMethodV,
1885 CheckJNI::CallNonvirtualByteMethodA,
1886 CheckJNI::CallNonvirtualCharMethod,
1887 CheckJNI::CallNonvirtualCharMethodV,
1888 CheckJNI::CallNonvirtualCharMethodA,
1889 CheckJNI::CallNonvirtualShortMethod,
1890 CheckJNI::CallNonvirtualShortMethodV,
1891 CheckJNI::CallNonvirtualShortMethodA,
1892 CheckJNI::CallNonvirtualIntMethod,
1893 CheckJNI::CallNonvirtualIntMethodV,
1894 CheckJNI::CallNonvirtualIntMethodA,
1895 CheckJNI::CallNonvirtualLongMethod,
1896 CheckJNI::CallNonvirtualLongMethodV,
1897 CheckJNI::CallNonvirtualLongMethodA,
1898 CheckJNI::CallNonvirtualFloatMethod,
1899 CheckJNI::CallNonvirtualFloatMethodV,
1900 CheckJNI::CallNonvirtualFloatMethodA,
1901 CheckJNI::CallNonvirtualDoubleMethod,
1902 CheckJNI::CallNonvirtualDoubleMethodV,
1903 CheckJNI::CallNonvirtualDoubleMethodA,
1904 CheckJNI::CallNonvirtualVoidMethod,
1905 CheckJNI::CallNonvirtualVoidMethodV,
1906 CheckJNI::CallNonvirtualVoidMethodA,
1907 CheckJNI::GetFieldID,
1908 CheckJNI::GetObjectField,
1909 CheckJNI::GetBooleanField,
1910 CheckJNI::GetByteField,
1911 CheckJNI::GetCharField,
1912 CheckJNI::GetShortField,
1913 CheckJNI::GetIntField,
1914 CheckJNI::GetLongField,
1915 CheckJNI::GetFloatField,
1916 CheckJNI::GetDoubleField,
1917 CheckJNI::SetObjectField,
1918 CheckJNI::SetBooleanField,
1919 CheckJNI::SetByteField,
1920 CheckJNI::SetCharField,
1921 CheckJNI::SetShortField,
1922 CheckJNI::SetIntField,
1923 CheckJNI::SetLongField,
1924 CheckJNI::SetFloatField,
1925 CheckJNI::SetDoubleField,
1926 CheckJNI::GetStaticMethodID,
1927 CheckJNI::CallStaticObjectMethod,
1928 CheckJNI::CallStaticObjectMethodV,
1929 CheckJNI::CallStaticObjectMethodA,
1930 CheckJNI::CallStaticBooleanMethod,
1931 CheckJNI::CallStaticBooleanMethodV,
1932 CheckJNI::CallStaticBooleanMethodA,
1933 CheckJNI::CallStaticByteMethod,
1934 CheckJNI::CallStaticByteMethodV,
1935 CheckJNI::CallStaticByteMethodA,
1936 CheckJNI::CallStaticCharMethod,
1937 CheckJNI::CallStaticCharMethodV,
1938 CheckJNI::CallStaticCharMethodA,
1939 CheckJNI::CallStaticShortMethod,
1940 CheckJNI::CallStaticShortMethodV,
1941 CheckJNI::CallStaticShortMethodA,
1942 CheckJNI::CallStaticIntMethod,
1943 CheckJNI::CallStaticIntMethodV,
1944 CheckJNI::CallStaticIntMethodA,
1945 CheckJNI::CallStaticLongMethod,
1946 CheckJNI::CallStaticLongMethodV,
1947 CheckJNI::CallStaticLongMethodA,
1948 CheckJNI::CallStaticFloatMethod,
1949 CheckJNI::CallStaticFloatMethodV,
1950 CheckJNI::CallStaticFloatMethodA,
1951 CheckJNI::CallStaticDoubleMethod,
1952 CheckJNI::CallStaticDoubleMethodV,
1953 CheckJNI::CallStaticDoubleMethodA,
1954 CheckJNI::CallStaticVoidMethod,
1955 CheckJNI::CallStaticVoidMethodV,
1956 CheckJNI::CallStaticVoidMethodA,
1957 CheckJNI::GetStaticFieldID,
1958 CheckJNI::GetStaticObjectField,
1959 CheckJNI::GetStaticBooleanField,
1960 CheckJNI::GetStaticByteField,
1961 CheckJNI::GetStaticCharField,
1962 CheckJNI::GetStaticShortField,
1963 CheckJNI::GetStaticIntField,
1964 CheckJNI::GetStaticLongField,
1965 CheckJNI::GetStaticFloatField,
1966 CheckJNI::GetStaticDoubleField,
1967 CheckJNI::SetStaticObjectField,
1968 CheckJNI::SetStaticBooleanField,
1969 CheckJNI::SetStaticByteField,
1970 CheckJNI::SetStaticCharField,
1971 CheckJNI::SetStaticShortField,
1972 CheckJNI::SetStaticIntField,
1973 CheckJNI::SetStaticLongField,
1974 CheckJNI::SetStaticFloatField,
1975 CheckJNI::SetStaticDoubleField,
1976 CheckJNI::NewString,
1977 CheckJNI::GetStringLength,
1978 CheckJNI::GetStringChars,
1979 CheckJNI::ReleaseStringChars,
1980 CheckJNI::NewStringUTF,
1981 CheckJNI::GetStringUTFLength,
1982 CheckJNI::GetStringUTFChars,
1983 CheckJNI::ReleaseStringUTFChars,
1984 CheckJNI::GetArrayLength,
1985 CheckJNI::NewObjectArray,
1986 CheckJNI::GetObjectArrayElement,
1987 CheckJNI::SetObjectArrayElement,
1988 CheckJNI::NewBooleanArray,
1989 CheckJNI::NewByteArray,
1990 CheckJNI::NewCharArray,
1991 CheckJNI::NewShortArray,
1992 CheckJNI::NewIntArray,
1993 CheckJNI::NewLongArray,
1994 CheckJNI::NewFloatArray,
1995 CheckJNI::NewDoubleArray,
1996 CheckJNI::GetBooleanArrayElements,
1997 CheckJNI::GetByteArrayElements,
1998 CheckJNI::GetCharArrayElements,
1999 CheckJNI::GetShortArrayElements,
2000 CheckJNI::GetIntArrayElements,
2001 CheckJNI::GetLongArrayElements,
2002 CheckJNI::GetFloatArrayElements,
2003 CheckJNI::GetDoubleArrayElements,
2004 CheckJNI::ReleaseBooleanArrayElements,
2005 CheckJNI::ReleaseByteArrayElements,
2006 CheckJNI::ReleaseCharArrayElements,
2007 CheckJNI::ReleaseShortArrayElements,
2008 CheckJNI::ReleaseIntArrayElements,
2009 CheckJNI::ReleaseLongArrayElements,
2010 CheckJNI::ReleaseFloatArrayElements,
2011 CheckJNI::ReleaseDoubleArrayElements,
2012 CheckJNI::GetBooleanArrayRegion,
2013 CheckJNI::GetByteArrayRegion,
2014 CheckJNI::GetCharArrayRegion,
2015 CheckJNI::GetShortArrayRegion,
2016 CheckJNI::GetIntArrayRegion,
2017 CheckJNI::GetLongArrayRegion,
2018 CheckJNI::GetFloatArrayRegion,
2019 CheckJNI::GetDoubleArrayRegion,
2020 CheckJNI::SetBooleanArrayRegion,
2021 CheckJNI::SetByteArrayRegion,
2022 CheckJNI::SetCharArrayRegion,
2023 CheckJNI::SetShortArrayRegion,
2024 CheckJNI::SetIntArrayRegion,
2025 CheckJNI::SetLongArrayRegion,
2026 CheckJNI::SetFloatArrayRegion,
2027 CheckJNI::SetDoubleArrayRegion,
2028 CheckJNI::RegisterNatives,
2029 CheckJNI::UnregisterNatives,
2030 CheckJNI::MonitorEnter,
2031 CheckJNI::MonitorExit,
2032 CheckJNI::GetJavaVM,
2033 CheckJNI::GetStringRegion,
2034 CheckJNI::GetStringUTFRegion,
2035 CheckJNI::GetPrimitiveArrayCritical,
2036 CheckJNI::ReleasePrimitiveArrayCritical,
2037 CheckJNI::GetStringCritical,
2038 CheckJNI::ReleaseStringCritical,
2039 CheckJNI::NewWeakGlobalRef,
2040 CheckJNI::DeleteWeakGlobalRef,
2041 CheckJNI::ExceptionCheck,
2042 CheckJNI::NewDirectByteBuffer,
2043 CheckJNI::GetDirectBufferAddress,
2044 CheckJNI::GetDirectBufferCapacity,
2045 CheckJNI::GetObjectRefType,
2046};
2047
2048const JNINativeInterface* GetCheckJniNativeInterface() {
2049 return &gCheckNativeInterface;
2050}
2051
2052class CheckJII {
Elliott Hughesba8eee12012-01-24 20:25:24 -08002053 public:
Elliott Hughesa2501992011-08-26 19:39:54 -07002054 static jint DestroyJavaVM(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002055 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002056 sc.Check(true, "v", vm);
2057 return CHECK_JNI_EXIT("I", BaseVm(vm)->DestroyJavaVM(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002058 }
2059
2060 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002061 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002062 sc.Check(true, "vpp", vm, p_env, thr_args);
2063 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002064 }
2065
2066 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002067 ScopedCheck sc(vm, false, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002068 sc.Check(true, "vpp", vm, p_env, thr_args);
2069 return CHECK_JNI_EXIT("I", BaseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
Elliott Hughesa2501992011-08-26 19:39:54 -07002070 }
2071
2072 static jint DetachCurrentThread(JavaVM* vm) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002073 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002074 sc.Check(true, "v", vm);
2075 return CHECK_JNI_EXIT("I", BaseVm(vm)->DetachCurrentThread(vm));
Elliott Hughesa2501992011-08-26 19:39:54 -07002076 }
2077
2078 static jint GetEnv(JavaVM* vm, void** env, jint version) {
Elliott Hughesa0957642011-09-02 14:27:33 -07002079 ScopedCheck sc(vm, true, __FUNCTION__);
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002080 sc.Check(true, "v", vm);
2081 return CHECK_JNI_EXIT("I", BaseVm(vm)->GetEnv(vm, env, version));
Elliott Hughesa2501992011-08-26 19:39:54 -07002082 }
2083
2084 private:
Elliott Hughes32ae6e32011-09-27 10:46:50 -07002085 static inline const JNIInvokeInterface* BaseVm(JavaVM* vm) {
Elliott Hughesa2501992011-08-26 19:39:54 -07002086 return reinterpret_cast<JavaVMExt*>(vm)->unchecked_functions;
2087 }
2088};
2089
2090const JNIInvokeInterface gCheckInvokeInterface = {
2091 NULL, // reserved0
2092 NULL, // reserved1
2093 NULL, // reserved2
2094 CheckJII::DestroyJavaVM,
2095 CheckJII::AttachCurrentThread,
2096 CheckJII::DetachCurrentThread,
2097 CheckJII::GetEnv,
2098 CheckJII::AttachCurrentThreadAsDaemon
2099};
2100
2101const JNIInvokeInterface* GetCheckJniInvokeInterface() {
2102 return &gCheckInvokeInterface;
2103}
2104
2105} // namespace art