Implement the direct ByteBuffer JNI functions, GetObjectRefType, and the string region functions.
Also run tests in a consistent (alphabetical) order.
Change-Id: I1bb4f3389e749ec031254d23da349be0397c260d
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 0845c0f..d11f2a7 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -503,6 +503,10 @@
"%s offset=%d length=%d %s.length=%d",
type.c_str(), start, length, identifier, array->GetLength());
}
+void ThrowSIOOBE(ScopedJniThreadState& ts, jsize start, jsize length, jsize array_length) {
+ ts.Self()->ThrowNewException("Ljava/lang/StringIndexOutOfBoundsException;",
+ "offset=%d length=%d string.length()=%d", start, length, array_length);
+}
template <typename JavaArrayT, typename JavaT, typename ArrayT>
static void GetPrimitiveArrayRegion(ScopedJniThreadState& ts, JavaArrayT java_array, jsize start, jsize length, JavaT* buf) {
@@ -526,6 +530,17 @@
}
}
+static jclass InitDirectByteBufferClass(JNIEnv* env) {
+ ScopedLocalRef<jclass> buffer_class(env, env->FindClass("java/nio/ReadWriteDirectByteBuffer"));
+ CHECK(buffer_class.get() != NULL);
+ return reinterpret_cast<jclass>(env->NewGlobalRef(buffer_class.get()));
+}
+
+static jclass GetDirectByteBufferClass(JNIEnv* env) {
+ static jclass buffer_class = InitDirectByteBufferClass(env);
+ return buffer_class;
+}
+
} // namespace
class JNI {
@@ -1700,14 +1715,26 @@
return Decode<String*>(ts, java_string)->GetUtfLength();
}
- static void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
+ static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length, jchar* buf) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
+ String* s = Decode<String*>(ts, java_string);
+ if (start < 0 || length < 0 || start + length > s->GetLength()) {
+ ThrowSIOOBE(ts, start, length, s->GetLength());
+ } else {
+ const jchar* chars = s->GetCharArray()->GetData() + s->GetOffset();
+ memcpy(buf, chars + start, length * sizeof(jchar));
+ }
}
- static void GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
+ static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length, char* buf) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
+ String* s = Decode<String*>(ts, java_string);
+ if (start < 0 || length < 0 || start + length > s->GetLength()) {
+ ThrowSIOOBE(ts, start, length, s->GetLength());
+ } else {
+ const jchar* chars = s->GetCharArray()->GetData() + s->GetOffset();
+ ConvertUtf16ToModifiedUtf8(buf, chars + start, length);
+ }
}
static const jchar* GetStringChars(JNIEnv* env, jstring str, jboolean* isCopy) {
@@ -1732,6 +1759,17 @@
UNIMPLEMENTED(FATAL);
}
+ static const jchar* GetStringCritical(JNIEnv* env, jstring s, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void ReleaseStringCritical(JNIEnv* env, jstring s, const jchar* cstr) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
ScopedJniThreadState ts(env);
Object* obj = Decode<Object*>(ts, java_array);
@@ -1817,6 +1855,17 @@
return NewPrimitiveArray<jshortArray, ShortArray>(ts, length);
}
+ static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
static jboolean* GetBooleanArrayElements(JNIEnv* env,
jbooleanArray array, jboolean* isCopy) {
ScopedJniThreadState ts(env);
@@ -2091,52 +2140,73 @@
return (*vm != NULL) ? JNI_OK : JNI_ERR;
}
- static void* GetPrimitiveArrayCritical(JNIEnv* env,
- jarray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
- }
-
- static void ReleasePrimitiveArrayCritical(JNIEnv* env,
- jarray array, void* carray, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- }
-
- static const jchar* GetStringCritical(JNIEnv* env, jstring s, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
- }
-
- static void ReleaseStringCritical(JNIEnv* env, jstring s, const jchar* cstr) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- }
-
static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+
+ // The address may not be NULL, and the capacity must be > 0.
+ CHECK(address != NULL);
+ CHECK_GT(capacity, 0);
+
+ jclass buffer_class = GetDirectByteBufferClass(env);
+ jmethodID mid = env->GetMethodID(buffer_class, "<init>", "(II)V");
+ if (mid == NULL) {
+ return NULL;
+ }
+
+ // At the moment, the Java side is limited to 32 bits.
+ CHECK_LE(reinterpret_cast<uintptr_t>(address), 0xffffffff);
+ CHECK_LE(capacity, 0xffffffff);
+ jint address_arg = reinterpret_cast<jint>(address);
+ jint capacity_arg = static_cast<jint>(capacity);
+
+ jobject result = env->NewObject(buffer_class, mid, address_arg, capacity_arg);
+ return ts.Self()->IsExceptionPending() ? NULL : result;
}
- static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
+ static void* GetDirectBufferAddress(JNIEnv* env, jobject java_buffer) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ static jfieldID fid = env->GetFieldID(GetDirectByteBufferClass(env), "effectiveDirectAddress", "I");
+ return reinterpret_cast<void*>(env->GetIntField(java_buffer, fid));
}
- static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
+ static jlong GetDirectBufferCapacity(JNIEnv* env, jobject java_buffer) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ static jfieldID fid = env->GetFieldID(GetDirectByteBufferClass(env), "capacity", "I");
+ return static_cast<jlong>(env->GetIntField(java_buffer, fid));
}
- static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
+ static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNIInvalidRefType;
+
+ CHECK(java_object != NULL);
+
+ // Do we definitely know what kind of reference this is?
+ IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
+ IndirectRefKind kind = GetIndirectRefKind(ref);
+ switch (kind) {
+ case kLocal:
+ return JNILocalRefType;
+ case kGlobal:
+ return JNIGlobalRefType;
+ case kWeakGlobal:
+ return JNIWeakGlobalRefType;
+ case kSirtOrInvalid:
+ // Is it in a stack IRT?
+ if (ts.Self()->SirtContains(java_object)) {
+ return JNILocalRefType;
+ }
+
+ // If we're handing out direct pointers, check whether it's a direct pointer
+ // to a local reference.
+ // TODO: replace 'false' with the replacement for gDvmJni.workAroundAppJniBugs
+ if (false && Decode<Object*>(ts, java_object) == reinterpret_cast<Object*>(java_object)) {
+ if (ts.Env()->locals.Contains(java_object)) {
+ return JNILocalRefType;
+ }
+ }
+
+ return JNIInvalidRefType;
+ }
}
};
@@ -2699,3 +2769,20 @@
}
} // namespace art
+
+std::ostream& operator<<(std::ostream& os, const jobjectRefType& rhs) {
+ switch (rhs) {
+ case JNIInvalidRefType:
+ os << "JNIInvalidRefType";
+ return os;
+ case JNILocalRefType:
+ os << "JNILocalRefType";
+ return os;
+ case JNIGlobalRefType:
+ os << "JNIGlobalRefType";
+ return os;
+ case JNIWeakGlobalRefType:
+ os << "JNIWeakGlobalRefType";
+ return os;
+ }
+}