summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2014-03-13 23:45:53 -0700
committerIan Rogers <irogers@google.com>2014-03-14 11:28:10 -0700
commit53b8b09fc80329539585dcf43657bc5f4ecefdff (patch)
treecac0f82fbb89bd907104e3fed6c36203e11a3de0
parent0dea9872082bc3e576ed6cefed86b0d6c0c45ffd (diff)
downloadart-53b8b09fc80329539585dcf43657bc5f4ecefdff.zip
art-53b8b09fc80329539585dcf43657bc5f4ecefdff.tar.gz
art-53b8b09fc80329539585dcf43657bc5f4ecefdff.tar.bz2
Refactor reflective method invocation.
Move invocation code out of JNI internal into reflection, including ArgArray code. Make reflective invocation use the ArgArray to build arguments rather than allocating a jvalue[] and unboxing arguments into that. Move reflection part of jni_internal_test into reflection_test. Make greater use of fast JNI. Change-Id: Ib381372df5f9a83679e30e7275de24fa0e6b1057
-rw-r--r--build/Android.gtest.mk1
-rw-r--r--compiler/jni/jni_compiler_test.cc2
-rw-r--r--runtime/debugger.cc8
-rw-r--r--runtime/entrypoints/interpreter/interpreter_entrypoints.cc6
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc2
-rw-r--r--runtime/exception_test.cc2
-rw-r--r--runtime/gc/heap.cc21
-rw-r--r--runtime/interpreter/interpreter_common.h1
-rw-r--r--runtime/invoke_arg_array_builder.h213
-rw-r--r--runtime/jni_internal.cc161
-rw-r--r--runtime/jni_internal.h34
-rw-r--r--runtime/jni_internal_test.cc843
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc18
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc2
-rw-r--r--runtime/native/dalvik_system_VMStack.cc66
-rw-r--r--runtime/native/java_lang_Class.cc4
-rw-r--r--runtime/native/java_lang_Runtime.cc6
-rw-r--r--runtime/native/java_lang_Thread.cc6
-rw-r--r--runtime/native/java_lang_Throwable.cc15
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc8
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc5
-rw-r--r--runtime/native/java_lang_reflect_Field.cc2
-rw-r--r--runtime/native/java_lang_reflect_Method.cc10
-rw-r--r--runtime/native/java_lang_reflect_Proxy.cc6
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc20
-rw-r--r--runtime/native/scoped_fast_native_object_access.h60
-rw-r--r--runtime/object_utils.h2
-rw-r--r--runtime/reflection.cc481
-rw-r--r--runtime/reflection.h27
-rw-r--r--runtime/reflection_test.cc627
-rw-r--r--runtime/runtime.cc6
-rw-r--r--runtime/scoped_thread_state_change.h23
-rw-r--r--runtime/thread.cc40
-rw-r--r--runtime/thread.h5
-rw-r--r--runtime/transaction_test.cc1
35 files changed, 1292 insertions, 1442 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 954ca99..99285cc 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -63,6 +63,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \
COMPILER_GTEST_COMMON_SRC_FILES := \
runtime/jni_internal_test.cc \
runtime/proxy_test.cc \
+ runtime/reflection_test.cc \
compiler/dex/local_value_numbering_test.cc \
compiler/driver/compiler_driver_test.cc \
compiler/elf_writer_test.cc \
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index df5afa2..31acb69 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -591,7 +591,7 @@ jint Java_MyClassNatives_nativeUpCall(JNIEnv* env, jobject thisObj, jint i) {
// Build stack trace
jobject internal = Thread::Current()->CreateInternalStackTrace(soa);
- jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(env, internal);
+ jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
mirror::ObjectArray<mirror::StackTraceElement>* trace_array =
soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
EXPECT_TRUE(trace_array != NULL);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 852cef4..9808869 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -28,7 +28,6 @@
#include "gc/accounting/card_table-inl.h"
#include "gc/space/large_object_space.h"
#include "gc/space/space-inl.h"
-#include "invoke_arg_array_builder.h"
#include "jdwp/object_registry.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
@@ -39,6 +38,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/throwable.h"
#include "object_utils.h"
+#include "reflection.h"
#include "safe_map.h"
#include "scoped_thread_state_change.h"
#include "ScopedLocalRef.h"
@@ -3052,10 +3052,8 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) {
CHECK_EQ(sizeof(jvalue), sizeof(uint64_t));
- MethodHelper mh(m.get());
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, pReq->receiver, reinterpret_cast<jvalue*>(pReq->arg_values));
- InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty());
+ pReq->result_value = InvokeWithJValues(soa, pReq->receiver, soa.EncodeMethod(pReq->method),
+ reinterpret_cast<jvalue*>(pReq->arg_values));
mirror::Throwable* exception = soa.Self()->GetException(NULL);
soa.Self()->ClearException();
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index 2067a45..a0ba6b9 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -16,10 +16,10 @@
#include "class_linker.h"
#include "interpreter/interpreter.h"
-#include "invoke_arg_array_builder.h"
#include "mirror/art_method-inl.h"
#include "mirror/object-inl.h"
#include "object_utils.h"
+#include "reflection.h"
#include "runtime.h"
#include "stack.h"
@@ -46,9 +46,7 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m
}
uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
if (kUsePortableCompiler) {
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
- method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty());
+ InvokeWithShadowFrame(self, shadow_frame, arg_offset, mh, result);
} else {
method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
(shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 36dc1cb..184e5e9 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -21,13 +21,13 @@
#include "entrypoints/entrypoint_utils.h"
#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
-#include "invoke_arg_array_builder.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "runtime.h"
+#include "scoped_thread_state_change.h"
namespace art {
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 4a75152..9c76a14 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -201,7 +201,7 @@ TEST_F(ExceptionTest, StackTraceElement) {
jobject internal = thread->CreateInternalStackTrace(soa);
ASSERT_TRUE(internal != NULL);
- jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(env, internal);
+ jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
ASSERT_TRUE(ste_array != NULL);
mirror::ObjectArray<mirror::StackTraceElement>* trace_array =
soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 76b94fd..45904ff 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -48,7 +48,6 @@
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "heap-inl.h"
#include "image.h"
-#include "invoke_arg_array_builder.h"
#include "mirror/art_field-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
@@ -57,6 +56,7 @@
#include "mirror/reference-inl.h"
#include "object_utils.h"
#include "os.h"
+#include "reflection.h"
#include "runtime.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change.h"
@@ -2453,11 +2453,10 @@ void Heap::ClearGrowthLimit() {
void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
ScopedObjectAccess soa(self);
- JValue result;
- ArgArray arg_array("VL", 2);
- arg_array.Append(object);
- soa.DecodeMethod(WellKnownClasses::java_lang_ref_FinalizerReference_add)->Invoke(self,
- arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
+ ScopedLocalRef<jobject> arg(self->GetJniEnv(), soa.AddLocalReference<jobject>(object));
+ jvalue args[1];
+ args[0].l = arg.get();
+ InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
}
void Heap::EnqueueClearedReferences() {
@@ -2467,11 +2466,11 @@ void Heap::EnqueueClearedReferences() {
// When a runtime isn't started there are no reference queues to care about so ignore.
if (LIKELY(Runtime::Current()->IsStarted())) {
ScopedObjectAccess soa(self);
- JValue result;
- ArgArray arg_array("VL", 2);
- arg_array.Append(cleared_references_.GetList());
- soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(),
- arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
+ ScopedLocalRef<jobject> arg(self->GetJniEnv(),
+ soa.AddLocalReference<jobject>(cleared_references_.GetList()));
+ jvalue args[1];
+ args[0].l = arg.get();
+ InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_ReferenceQueue_add, args);
}
cleared_references_.Clear();
}
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 589e0b0..21eeafa 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -29,7 +29,6 @@
#include "dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
#include "gc/accounting/card_table-inl.h"
-#include "invoke_arg_array_builder.h"
#include "nth_caller_visitor.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method.h"
diff --git a/runtime/invoke_arg_array_builder.h b/runtime/invoke_arg_array_builder.h
deleted file mode 100644
index 6ecce40..0000000
--- a/runtime/invoke_arg_array_builder.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_
-#define ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_
-
-#include "mirror/art_method.h"
-#include "mirror/object.h"
-#include "scoped_thread_state_change.h"
-
-namespace art {
-
-static inline size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len) {
- size_t num_bytes = 0;
- for (size_t i = 1; i < shorty_len; ++i) {
- char ch = shorty[i];
- if (ch == 'D' || ch == 'J') {
- num_bytes += 8;
- } else if (ch == 'L') {
- // Argument is a reference or an array. The shorty descriptor
- // does not distinguish between these types.
- num_bytes += sizeof(mirror::Object*);
- } else {
- num_bytes += 4;
- }
- }
- return num_bytes;
-}
-
-class ArgArray {
- public:
- explicit ArgArray(const char* shorty, uint32_t shorty_len)
- : shorty_(shorty), shorty_len_(shorty_len), num_bytes_(0) {
- size_t num_slots = shorty_len + 1; // +1 in case of receiver.
- if (LIKELY((num_slots * 2) < kSmallArgArraySize)) {
- // We can trivially use the small arg array.
- arg_array_ = small_arg_array_;
- } else {
- // Analyze shorty to see if we need the large arg array.
- for (size_t i = 1; i < shorty_len; ++i) {
- char c = shorty[i];
- if (c == 'J' || c == 'D') {
- num_slots++;
- }
- }
- if (num_slots <= kSmallArgArraySize) {
- arg_array_ = small_arg_array_;
- } else {
- large_arg_array_.reset(new uint32_t[num_slots]);
- arg_array_ = large_arg_array_.get();
- }
- }
- }
-
- uint32_t* GetArray() {
- return arg_array_;
- }
-
- uint32_t GetNumBytes() {
- return num_bytes_;
- }
-
- void Append(uint32_t value) {
- arg_array_[num_bytes_ / 4] = value;
- num_bytes_ += 4;
- }
-
- void Append(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Append(StackReference<mirror::Object>::FromMirrorPtr(obj).AsVRegValue());
- }
-
- void AppendWide(uint64_t value) {
- // For ARM and MIPS portable, align wide values to 8 bytes (ArgArray starts at offset of 4).
-#if defined(ART_USE_PORTABLE_COMPILER) && (defined(__arm__) || defined(__mips__))
- if (num_bytes_ % 8 == 0) {
- num_bytes_ += 4;
- }
-#endif
- arg_array_[num_bytes_ / 4] = value;
- arg_array_[(num_bytes_ / 4) + 1] = value >> 32;
- num_bytes_ += 8;
- }
-
- void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, va_list ap)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // Set receiver if non-null (method is not static)
- if (receiver != nullptr) {
- Append(receiver);
- }
- for (size_t i = 1; i < shorty_len_; ++i) {
- switch (shorty_[i]) {
- case 'Z':
- case 'B':
- case 'C':
- case 'S':
- case 'I':
- Append(va_arg(ap, jint));
- break;
- case 'F': {
- JValue value;
- value.SetF(va_arg(ap, jdouble));
- Append(value.GetI());
- break;
- }
- case 'L':
- Append(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
- break;
- case 'D': {
- JValue value;
- value.SetD(va_arg(ap, jdouble));
- AppendWide(value.GetJ());
- break;
- }
- case 'J': {
- AppendWide(va_arg(ap, jlong));
- break;
- }
- }
- }
- }
-
- void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, jvalue* args)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // Set receiver if non-null (method is not static)
- if (receiver != nullptr) {
- Append(receiver);
- }
- for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
- switch (shorty_[i]) {
- case 'Z':
- Append(args[args_offset].z);
- break;
- case 'B':
- Append(args[args_offset].b);
- break;
- case 'C':
- Append(args[args_offset].c);
- break;
- case 'S':
- Append(args[args_offset].s);
- break;
- case 'I':
- case 'F':
- Append(args[args_offset].i);
- break;
- case 'L':
- Append(soa.Decode<mirror::Object*>(args[args_offset].l));
- break;
- case 'D':
- case 'J':
- AppendWide(args[args_offset].j);
- break;
- }
- }
- }
-
-
- void BuildArgArrayFromFrame(ShadowFrame* shadow_frame, uint32_t arg_offset)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // Set receiver if non-null (method is not static)
- size_t cur_arg = arg_offset;
- if (!shadow_frame->GetMethod()->IsStatic()) {
- Append(shadow_frame->GetVReg(cur_arg));
- cur_arg++;
- }
- for (size_t i = 1; i < shorty_len_; ++i) {
- switch (shorty_[i]) {
- case 'Z':
- case 'B':
- case 'C':
- case 'S':
- case 'I':
- case 'F':
- case 'L':
- Append(shadow_frame->GetVReg(cur_arg));
- cur_arg++;
- break;
- case 'D':
- case 'J':
- AppendWide(shadow_frame->GetVRegLong(cur_arg));
- cur_arg++;
- cur_arg++;
- break;
- }
- }
- }
-
- private:
- enum { kSmallArgArraySize = 16 };
- const char* const shorty_;
- const uint32_t shorty_len_;
- uint32_t num_bytes_;
- uint32_t* arg_array_;
- uint32_t small_arg_array_[kSmallArgArraySize];
- UniquePtr<uint32_t[]> large_arg_array_;
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 6efff1a..43db7ec 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -30,7 +30,6 @@
#include "dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
-#include "invoke_arg_array_builder.h"
#include "jni.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
@@ -41,6 +40,7 @@
#include "mirror/throwable.h"
#include "object_utils.h"
#include "parsed_options.h"
+#include "reflection.h"
#include "runtime.h"
#include "safe_map.h"
#include "scoped_thread_state_change.h"
@@ -77,104 +77,6 @@ static bool IsBadJniVersion(int version) {
return version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && version != JNI_VERSION_1_6;
}
-static void CheckMethodArguments(mirror::ArtMethod* m, uint32_t* args)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const DexFile::TypeList* params = MethodHelper(m).GetParameterTypeList();
- if (params == nullptr) {
- return; // No arguments so nothing to check.
- }
- uint32_t offset = 0;
- uint32_t num_params = params->Size();
- size_t error_count = 0;
- if (!m->IsStatic()) {
- offset = 1;
- }
- for (uint32_t i = 0; i < num_params; i++) {
- uint16_t type_idx = params->GetTypeItem(i).type_idx_;
- mirror::Class* param_type = MethodHelper(m).GetClassFromTypeIdx(type_idx);
- if (param_type == nullptr) {
- Thread* self = Thread::Current();
- CHECK(self->IsExceptionPending());
- LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
- << MethodHelper(m).GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
- << self->GetException(nullptr)->Dump();
- self->ClearException();
- ++error_count;
- } else if (!param_type->IsPrimitive()) {
- // TODO: check primitives are in range.
- mirror::Object* argument = reinterpret_cast<mirror::Object*>(args[i + offset]);
- if (argument != nullptr && !argument->InstanceOf(param_type)) {
- LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
- << PrettyTypeOf(argument) << " as argument " << (i + 1)
- << " to " << PrettyMethod(m);
- ++error_count;
- }
- } else if (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble()) {
- offset++;
- }
- }
- if (error_count > 0) {
- // TODO: pass the JNI function name (such as "CallVoidMethodV") through so we can call JniAbort
- // with an argument.
- JniAbortF(nullptr, "bad arguments passed to %s (see above for details)",
- PrettyMethod(m).c_str());
- }
-}
-
-void InvokeWithArgArray(const ScopedObjectAccess& soa, mirror::ArtMethod* method,
- ArgArray* arg_array, JValue* result, const char* shorty)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- uint32_t* args = arg_array->GetArray();
- if (UNLIKELY(soa.Env()->check_jni)) {
- CheckMethodArguments(method, args);
- }
- method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
-}
-
-static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj,
- jmethodID mid, va_list args)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method = soa.DecodeMethod(mid);
- mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
- MethodHelper mh(method);
- JValue result;
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, receiver, args);
- InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
- return result;
-}
-
-static mirror::ArtMethod* FindVirtualMethod(mirror::Object* receiver, mirror::ArtMethod* method)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method);
-}
-
-static JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa,
- jobject obj, jmethodID mid, jvalue* args)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
- mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
- MethodHelper mh(method);
- JValue result;
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, receiver, args);
- InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
- return result;
-}
-
-static JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa,
- jobject obj, jmethodID mid, va_list args)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
- mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
- MethodHelper mh(method);
- JValue result;
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, receiver, args);
- InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
- return result;
-}
-
// Section 12.3.2 of the JNI spec describes JNI class descriptors. They're
// separated with slashes but aren't wrapped with "L;" like regular descriptors
// (i.e. "a/b/C" rather than "La/b/C;"). Arrays of reference types are an
@@ -611,18 +513,6 @@ class Libraries {
SafeMap<std::string, SharedLibrary*> libraries_;
};
-JValue InvokeWithJValues(const ScopedObjectAccess& soa, jobject obj, jmethodID mid,
- jvalue* args) {
- mirror::ArtMethod* method = soa.DecodeMethod(mid);
- mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
- MethodHelper mh(method);
- JValue result;
- ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, receiver, args);
- InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
- return result;
-}
-
#define CHECK_NON_NULL_ARGUMENT(fn, value) \
if (UNLIKELY(value == nullptr)) { \
JniAbortF(#fn, #value " == null"); \
@@ -1014,7 +904,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallObjectMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallObjectMethodA, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args));
+ JValue result(InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args));
return soa.AddLocalReference<jobject>(result.GetL());
}
@@ -1040,7 +931,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallBooleanMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallBooleanMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetZ();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetZ();
}
static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1065,7 +957,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallByteMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallByteMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetB();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetB();
}
static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1090,7 +983,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallCharMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallCharMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetC();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetC();
}
static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1115,7 +1009,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallDoubleMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallDoubleMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetD();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetD();
}
static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1140,7 +1035,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallFloatMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallFloatMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetF();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetF();
}
static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1165,7 +1061,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallIntMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallIntMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetI();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetI();
}
static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1190,7 +1087,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallLongMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallLongMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetJ();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetJ();
}
static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1215,7 +1113,8 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallShortMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallShortMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args).GetS();
+ return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
+ args).GetS();
}
static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1239,7 +1138,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallVoidMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallVoidMethodA, mid);
ScopedObjectAccess soa(env);
- InvokeVirtualOrInterfaceWithJValues(soa, obj, mid, args);
+ InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
}
static jobject CallNonvirtualObjectMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1268,7 +1167,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethodA, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithJValues(soa, obj, mid, args));
+ JValue result(InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args));
return soa.AddLocalReference<jobject>(result.GetL());
}
@@ -1297,7 +1196,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetZ();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetZ();
}
static jbyte CallNonvirtualByteMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1324,7 +1223,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetB();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetB();
}
static jchar CallNonvirtualCharMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1351,7 +1250,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetC();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetC();
}
static jshort CallNonvirtualShortMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1378,7 +1277,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetS();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetS();
}
static jint CallNonvirtualIntMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1405,7 +1304,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetI();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetI();
}
static jlong CallNonvirtualLongMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1432,7 +1331,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetJ();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetJ();
}
static jfloat CallNonvirtualFloatMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1459,7 +1358,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetF();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetF();
}
static jdouble CallNonvirtualDoubleMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1486,7 +1385,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, obj, mid, args).GetD();
+ return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetD();
}
static void CallNonvirtualVoidMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
@@ -1512,7 +1411,7 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethodA, obj);
CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethodA, mid);
ScopedObjectAccess soa(env);
- InvokeWithJValues(soa, obj, mid, args);
+ InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
}
static jfieldID GetFieldID(JNIEnv* env, jclass java_class, const char* name, const char* sig) {
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index 7b49d33..42796db 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -42,7 +42,6 @@ namespace mirror {
class ArtMethod;
class ClassLoader;
} // namespace mirror
-class ArgArray;
union JValue;
class Libraries;
class ParsedOptions;
@@ -55,12 +54,6 @@ void JniAbortF(const char* jni_function_name, const char* fmt, ...)
void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
jint method_count);
-JValue InvokeWithJValues(const ScopedObjectAccess&, jobject obj, jmethodID mid, jvalue* args)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-void InvokeWithArgArray(const ScopedObjectAccess& soa, mirror::ArtMethod* method,
- ArgArray *arg_array, JValue* result, const char* shorty)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause);
class JavaVMExt : public JavaVM {
@@ -155,6 +148,10 @@ struct JNIEnvExt : public JNIEnv {
void PushFrame(int capacity);
void PopFrame();
+ template<typename T>
+ T AddLocalReference(mirror::Object* obj, bool jni_work_arounds)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static Offset SegmentStateOffset();
static Offset LocalRefCookieOffset() {
@@ -218,8 +215,29 @@ class ScopedJniEnvLocalRefState {
DISALLOW_COPY_AND_ASSIGN(ScopedJniEnvLocalRefState);
};
+template<typename T>
+inline T JNIEnvExt::AddLocalReference(mirror::Object* obj, bool jni_work_arounds) {
+ IndirectRef ref = locals.Add(local_ref_cookie, obj);
+
+ // TODO: fix this to understand PushLocalFrame, so we can turn it on.
+ if (false) {
+ if (check_jni) {
+ size_t entry_count = locals.Capacity();
+ if (entry_count > 16) {
+ locals.Dump(LOG(WARNING) << "Warning: more than 16 JNI local references: "
+ << entry_count << " (most recent was a " << PrettyTypeOf(obj) << ")\n");
+ // TODO: LOG(FATAL) in a later release?
+ }
+ }
+ }
+
+ if (jni_work_arounds) {
+ return reinterpret_cast<T>(obj);
+ }
+ return reinterpret_cast<T>(ref);
+}
+
} // namespace art
std::ostream& operator<<(std::ostream& os, const jobjectRefType& rhs);
-
#endif // ART_RUNTIME_JNI_INTERNAL_H_
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 28408d2..7b29a9c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -21,7 +21,6 @@
#include <cmath>
#include "common_compiler_test.h"
-#include "invoke_arg_array_builder.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
@@ -74,7 +73,7 @@ class JniInternalTest : public CommonCompilerTest {
}
}
- virtual void TearDown() {
+ virtual void TearDown() OVERRIDE {
CleanUpJniEnv();
CommonCompilerTest::TearDown();
}
@@ -86,676 +85,6 @@ class JniInternalTest : public CommonCompilerTest {
return soa.AddLocalReference<jclass>(c);
}
- void JniInternalTestMakeExecutable(mirror::ArtMethod** method,
- mirror::Object** receiver,
- bool is_static, const char* method_name,
- const char* method_signature)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const char* class_name = is_static ? "StaticLeafMethods" : "NonStaticLeafMethods";
- jobject jclass_loader(LoadDex(class_name));
- Thread* self = Thread::Current();
- SirtRef<mirror::ClassLoader> null_class_loader(self, nullptr);
- SirtRef<mirror::ClassLoader>
- class_loader(self,
- ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader));
- if (is_static) {
- MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
- class_name);
- } else {
- MakeExecutable(nullptr, "java.lang.Class");
- MakeExecutable(nullptr, "java.lang.Object");
- MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
- class_name);
- }
-
- mirror::Class* c = class_linker_->FindClass(self, DotToDescriptor(class_name).c_str(),
- class_loader);
- CHECK(c != NULL);
-
- *method = is_static ? c->FindDirectMethod(method_name, method_signature)
- : c->FindVirtualMethod(method_name, method_signature);
- CHECK(method != nullptr);
-
- *receiver = (is_static ? nullptr : c->AllocObject(self));
-
- // Start runtime.
- bool started = runtime_->Start();
- CHECK(started);
- self->TransitionFromSuspendedToRunnable();
- }
-
- void InvokeNopMethod(bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "nop", "()V");
-
- ArgArray arg_array("V", 1);
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- }
-
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "V");
- }
-
- void InvokeIdentityByteMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "identity", "(B)B");
-
- ArgArray arg_array("BB", 2);
- uint32_t* args = arg_array.GetArray();
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- arg_array.Append(0U);
- result.SetB(-1);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
- EXPECT_EQ(0, result.GetB());
-
- args[0] = -1;
- result.SetB(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
- EXPECT_EQ(-1, result.GetB());
-
- args[0] = SCHAR_MAX;
- result.SetB(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
- EXPECT_EQ(SCHAR_MAX, result.GetB());
-
- args[0] = (SCHAR_MIN << 24) >> 24;
- result.SetB(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
- EXPECT_EQ(SCHAR_MIN, result.GetB());
- }
-
- void InvokeIdentityIntMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "identity", "(I)I");
-
- ArgArray arg_array("II", 2);
- uint32_t* args = arg_array.GetArray();
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- arg_array.Append(0U);
- result.SetI(-1);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
- EXPECT_EQ(0, result.GetI());
-
- args[0] = -1;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
- EXPECT_EQ(-1, result.GetI());
-
- args[0] = INT_MAX;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
- EXPECT_EQ(INT_MAX, result.GetI());
-
- args[0] = INT_MIN;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
- EXPECT_EQ(INT_MIN, result.GetI());
- }
-
- void InvokeIdentityDoubleMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "identity", "(D)D");
-
- ArgArray arg_array("DD", 2);
- uint32_t* args = arg_array.GetArray();
- JValue value;
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- value.SetD(0.0);
- arg_array.AppendWide(value.GetJ());
- result.SetD(-1.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
- EXPECT_EQ(0.0, result.GetD());
-
- value.SetD(-1.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
- EXPECT_EQ(-1.0, result.GetD());
-
- value.SetD(DBL_MAX);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
- EXPECT_EQ(DBL_MAX, result.GetD());
-
- value.SetD(DBL_MIN);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
- EXPECT_EQ(DBL_MIN, result.GetD());
- }
-
- void InvokeSumIntIntMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(II)I");
-
- ArgArray arg_array("III", 3);
- uint32_t* args = arg_array.GetArray();
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- arg_array.Append(0U);
- arg_array.Append(0U);
- result.SetI(-1);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
- EXPECT_EQ(0, result.GetI());
-
- args[0] = 1;
- args[1] = 2;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
- EXPECT_EQ(3, result.GetI());
-
- args[0] = -2;
- args[1] = 5;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
- EXPECT_EQ(3, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MIN;
- result.SetI(1234);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
- EXPECT_EQ(-1, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MAX;
- result.SetI(INT_MIN);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
- EXPECT_EQ(-2, result.GetI());
- }
-
- void InvokeSumIntIntIntMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(III)I");
-
- ArgArray arg_array("IIII", 4);
- uint32_t* args = arg_array.GetArray();
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- arg_array.Append(0U);
- arg_array.Append(0U);
- arg_array.Append(0U);
- result.SetI(-1);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIII");
- EXPECT_EQ(0, result.GetI());
-
- args[0] = 1;
- args[1] = 2;
- args[2] = 3;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIII");
- EXPECT_EQ(6, result.GetI());
-
- args[0] = -1;
- args[1] = 2;
- args[2] = -3;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIII");
- EXPECT_EQ(-2, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MIN;
- args[2] = INT_MAX;
- result.SetI(1234);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIII");
- EXPECT_EQ(2147483646, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MAX;
- args[2] = INT_MAX;
- result.SetI(INT_MIN);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIII");
- EXPECT_EQ(2147483645, result.GetI());
- }
-
- void InvokeSumIntIntIntIntMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(IIII)I");
-
- ArgArray arg_array("IIIII", 5);
- uint32_t* args = arg_array.GetArray();
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- arg_array.Append(0U);
- arg_array.Append(0U);
- arg_array.Append(0U);
- arg_array.Append(0U);
- result.SetI(-1);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIII");
- EXPECT_EQ(0, result.GetI());
-
- args[0] = 1;
- args[1] = 2;
- args[2] = 3;
- args[3] = 4;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIII");
- EXPECT_EQ(10, result.GetI());
-
- args[0] = -1;
- args[1] = 2;
- args[2] = -3;
- args[3] = 4;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIII");
- EXPECT_EQ(2, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MIN;
- args[2] = INT_MAX;
- args[3] = INT_MIN;
- result.SetI(1234);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIII");
- EXPECT_EQ(-2, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MAX;
- args[2] = INT_MAX;
- args[3] = INT_MAX;
- result.SetI(INT_MIN);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIII");
- EXPECT_EQ(-4, result.GetI());
- }
-
- void InvokeSumIntIntIntIntIntMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(IIIII)I");
-
- ArgArray arg_array("IIIIII", 6);
- uint32_t* args = arg_array.GetArray();
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- arg_array.Append(0U);
- arg_array.Append(0U);
- arg_array.Append(0U);
- arg_array.Append(0U);
- arg_array.Append(0U);
- result.SetI(-1.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIIII");
- EXPECT_EQ(0, result.GetI());
-
- args[0] = 1;
- args[1] = 2;
- args[2] = 3;
- args[3] = 4;
- args[4] = 5;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIIII");
- EXPECT_EQ(15, result.GetI());
-
- args[0] = -1;
- args[1] = 2;
- args[2] = -3;
- args[3] = 4;
- args[4] = -5;
- result.SetI(0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIIII");
- EXPECT_EQ(-3, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MIN;
- args[2] = INT_MAX;
- args[3] = INT_MIN;
- args[4] = INT_MAX;
- result.SetI(1234);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIIII");
- EXPECT_EQ(2147483645, result.GetI());
-
- args[0] = INT_MAX;
- args[1] = INT_MAX;
- args[2] = INT_MAX;
- args[3] = INT_MAX;
- args[4] = INT_MAX;
- result.SetI(INT_MIN);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "IIIIII");
- EXPECT_EQ(2147483643, result.GetI());
- }
-
- void InvokeSumDoubleDoubleMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(DD)D");
-
- ArgArray arg_array("DDD", 3);
- uint32_t* args = arg_array.GetArray();
- JValue value;
- JValue value2;
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- value.SetD(0.0);
- value2.SetD(0.0);
- arg_array.AppendWide(value.GetJ());
- arg_array.AppendWide(value2.GetJ());
- result.SetD(-1.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDD");
- EXPECT_EQ(0.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(2.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDD");
- EXPECT_EQ(3.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(-2.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDD");
- EXPECT_EQ(-1.0, result.GetD());
-
- value.SetD(DBL_MAX);
- value2.SetD(DBL_MIN);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDD");
- EXPECT_EQ(1.7976931348623157e308, result.GetD());
-
- value.SetD(DBL_MAX);
- value2.SetD(DBL_MAX);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDD");
- EXPECT_EQ(INFINITY, result.GetD());
- }
-
- void InvokeSumDoubleDoubleDoubleMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDD)D");
-
- ArgArray arg_array("DDDD", 4);
- uint32_t* args = arg_array.GetArray();
- JValue value;
- JValue value2;
- JValue value3;
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- value.SetD(0.0);
- value2.SetD(0.0);
- value3.SetD(0.0);
- arg_array.AppendWide(value.GetJ());
- arg_array.AppendWide(value2.GetJ());
- arg_array.AppendWide(value3.GetJ());
- result.SetD(-1.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDD");
- EXPECT_EQ(0.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(2.0);
- value3.SetD(3.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- args[4] = value3.GetJ();
- args[5] = value3.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDD");
- EXPECT_EQ(6.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(-2.0);
- value3.SetD(3.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- args[4] = value3.GetJ();
- args[5] = value3.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDD");
- EXPECT_EQ(2.0, result.GetD());
- }
-
- void InvokeSumDoubleDoubleDoubleDoubleMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDDD)D");
-
- ArgArray arg_array("DDDDD", 5);
- uint32_t* args = arg_array.GetArray();
- JValue value;
- JValue value2;
- JValue value3;
- JValue value4;
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- value.SetD(0.0);
- value2.SetD(0.0);
- value3.SetD(0.0);
- value4.SetD(0.0);
- arg_array.AppendWide(value.GetJ());
- arg_array.AppendWide(value2.GetJ());
- arg_array.AppendWide(value3.GetJ());
- arg_array.AppendWide(value4.GetJ());
- result.SetD(-1.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDDD");
- EXPECT_EQ(0.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(2.0);
- value3.SetD(3.0);
- value4.SetD(4.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- args[4] = value3.GetJ();
- args[5] = value3.GetJ() >> 32;
- args[6] = value4.GetJ();
- args[7] = value4.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDDD");
- EXPECT_EQ(10.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(-2.0);
- value3.SetD(3.0);
- value4.SetD(-4.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- args[4] = value3.GetJ();
- args[5] = value3.GetJ() >> 32;
- args[6] = value4.GetJ();
- args[7] = value4.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDDD");
- EXPECT_EQ(-2.0, result.GetD());
- }
-
- void InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method;
- mirror::Object* receiver;
- JniInternalTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDDDD)D");
-
- ArgArray arg_array("DDDDDD", 6);
- uint32_t* args = arg_array.GetArray();
- JValue value;
- JValue value2;
- JValue value3;
- JValue value4;
- JValue value5;
- JValue result;
-
- if (!is_static) {
- arg_array.Append(receiver);
- args++;
- }
-
- value.SetD(0.0);
- value2.SetD(0.0);
- value3.SetD(0.0);
- value4.SetD(0.0);
- value5.SetD(0.0);
- arg_array.AppendWide(value.GetJ());
- arg_array.AppendWide(value2.GetJ());
- arg_array.AppendWide(value3.GetJ());
- arg_array.AppendWide(value4.GetJ());
- arg_array.AppendWide(value5.GetJ());
- result.SetD(-1.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDDDD");
- EXPECT_EQ(0.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(2.0);
- value3.SetD(3.0);
- value4.SetD(4.0);
- value5.SetD(5.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- args[4] = value3.GetJ();
- args[5] = value3.GetJ() >> 32;
- args[6] = value4.GetJ();
- args[7] = value4.GetJ() >> 32;
- args[8] = value5.GetJ();
- args[9] = value5.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDDDD");
- EXPECT_EQ(15.0, result.GetD());
-
- value.SetD(1.0);
- value2.SetD(-2.0);
- value3.SetD(3.0);
- value4.SetD(-4.0);
- value5.SetD(5.0);
- args[0] = value.GetJ();
- args[1] = value.GetJ() >> 32;
- args[2] = value2.GetJ();
- args[3] = value2.GetJ() >> 32;
- args[4] = value3.GetJ();
- args[5] = value3.GetJ() >> 32;
- args[6] = value4.GetJ();
- args[7] = value4.GetJ() >> 32;
- args[8] = value5.GetJ();
- args[9] = value5.GetJ() >> 32;
- result.SetD(0.0);
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
- "DDDDDD");
- EXPECT_EQ(3.0, result.GetD());
- }
-
JavaVMExt* vm_;
JNIEnv* env_;
jclass aioobe_;
@@ -1772,176 +1101,6 @@ TEST_F(JniInternalTest, DeleteWeakGlobalRef) {
env_->DeleteWeakGlobalRef(o2);
}
-TEST_F(JniInternalTest, StaticMainMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- jobject jclass_loader = LoadDex("Main");
- SirtRef<mirror::ClassLoader>
- class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
- CompileDirectMethod(class_loader, "Main", "main", "([Ljava/lang/String;)V");
-
- mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- mirror::ArtMethod* method = klass->FindDirectMethod("main", "([Ljava/lang/String;)V");
- ASSERT_TRUE(method != NULL);
-
- ArgArray arg_array("VL", 2);
- arg_array.Append(0U);
- JValue result;
-
- // Start runtime.
- bool started = runtime_->Start();
- CHECK(started);
- Thread::Current()->TransitionFromSuspendedToRunnable();
-
- method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
-}
-
-TEST_F(JniInternalTest, StaticNopMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeNopMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticNopMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeNopMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticIdentityByteMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeIdentityByteMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticIdentityByteMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeIdentityByteMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticIdentityIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeIdentityIntMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticIdentityIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeIdentityIntMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticIdentityDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeIdentityDoubleMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticIdentityDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeIdentityDoubleMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumIntIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntIntMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumIntIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntIntMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumIntIntIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntIntIntMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumIntIntIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntIntIntMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumIntIntIntIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntIntIntIntMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumIntIntIntIntIntMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumIntIntIntIntIntMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleDoubleMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleDoubleMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleDoubleDoubleMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleDoubleDoubleMethod(false);
-}
-
-TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(true);
-}
-
-TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
- TEST_DISABLED_FOR_PORTABLE();
- ScopedObjectAccess soa(Thread::Current());
- InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(false);
-}
-
TEST_F(JniInternalTest, Throw) {
EXPECT_EQ(JNI_ERR, env_->Throw(NULL));
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 6482917..0b58af4 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -29,7 +29,7 @@
#include "jni_internal.h"
#include "mirror/class.h"
#include "ScopedUtfChars.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
#include "toStringArray.h"
#include "trace.h"
@@ -153,12 +153,12 @@ static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) {
}
static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags);
}
static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
}
@@ -318,14 +318,14 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"),
NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
- NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
+ NATIVE_METHOD(VMDebug, getLoadedClassCount, "!()I"),
NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
NATIVE_METHOD(VMDebug, infopoint, "(I)V"),
- NATIVE_METHOD(VMDebug, isDebuggerConnected, "()Z"),
- NATIVE_METHOD(VMDebug, isDebuggingEnabled, "()Z"),
+ NATIVE_METHOD(VMDebug, isDebuggerConnected, "!()Z"),
+ NATIVE_METHOD(VMDebug, isDebuggingEnabled, "!()Z"),
NATIVE_METHOD(VMDebug, getMethodTracingMode, "()I"),
- NATIVE_METHOD(VMDebug, lastDebuggerActivity, "()J"),
- NATIVE_METHOD(VMDebug, printLoadedClasses, "(I)V"),
+ NATIVE_METHOD(VMDebug, lastDebuggerActivity, "!()J"),
+ NATIVE_METHOD(VMDebug, printLoadedClasses, "!(I)V"),
NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
NATIVE_METHOD(VMDebug, resetInstructionCount, "()V"),
NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
@@ -338,7 +338,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMDebug, stopEmulatorTracing, "()V"),
NATIVE_METHOD(VMDebug, stopInstructionCounting, "()V"),
NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
- NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
+ NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "!()J"),
};
void register_dalvik_system_VMDebug(JNIEnv* env) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 0e2d921..5c5eaa1 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -532,7 +532,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),
NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"),
NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"),
- NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"),
+ NATIVE_METHOD(VMRuntime, isDebuggerActive, "!()Z"),
NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"),
NATIVE_METHOD(VMRuntime, newNonMovableArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
NATIVE_METHOD(VMRuntime, newUnpaddedArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 7e02e29..9975bf7 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -26,42 +26,43 @@
namespace art {
-static jobject GetThreadStack(JNIEnv* env, jobject peer) {
- {
- ScopedObjectAccess soa(env);
- if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
- return soa.Self()->CreateInternalStackTrace(soa);
- }
- }
- // Suspend thread to build stack trace.
- bool timed_out;
- Thread* thread = ThreadList::SuspendThreadByPeer(peer, true, false, &timed_out);
- if (thread != NULL) {
- jobject trace;
- {
- ScopedObjectAccess soa(env);
- trace = thread->CreateInternalStackTrace(soa);
- }
- // Restart suspended thread.
- Runtime::Current()->GetThreadList()->Resume(thread, false);
- return trace;
+static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject peer)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ jobject trace = nullptr;
+ if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+ trace = soa.Self()->CreateInternalStackTrace(soa);
} else {
- if (timed_out) {
- LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
- "generous timeout.";
+ // Suspend thread to build stack trace.
+ soa.Self()->TransitionFromRunnableToSuspended(kNative);
+ bool timed_out;
+ Thread* thread = ThreadList::SuspendThreadByPeer(peer, true, false, &timed_out);
+ if (thread != nullptr) {
+ // Must be runnable to create returned array.
+ CHECK_EQ(soa.Self()->TransitionFromSuspendedToRunnable(), kNative);
+ trace = thread->CreateInternalStackTrace(soa);
+ soa.Self()->TransitionFromRunnableToSuspended(kNative);
+ // Restart suspended thread.
+ Runtime::Current()->GetThreadList()->Resume(thread, false);
+ } else {
+ if (timed_out) {
+ LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
+ "generous timeout.";
+ }
}
- return NULL;
+ CHECK_EQ(soa.Self()->TransitionFromSuspendedToRunnable(), kNative);
}
+ return trace;
}
static jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject javaThread,
jobjectArray javaSteArray) {
- jobject trace = GetThreadStack(env, javaThread);
- if (trace == NULL) {
+ ScopedFastNativeObjectAccess soa(env);
+ jobject trace = GetThreadStack(soa, javaThread);
+ if (trace == nullptr) {
return 0;
}
int32_t depth;
- Thread::InternalStackTraceToStackTraceElementArray(env, trace, javaSteArray, &depth);
+ Thread::InternalStackTraceToStackTraceElementArray(soa, trace, javaSteArray, &depth);
return depth;
}
@@ -111,19 +112,20 @@ static jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
}
static jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject javaThread) {
- jobject trace = GetThreadStack(env, javaThread);
- if (trace == NULL) {
- return NULL;
+ ScopedFastNativeObjectAccess soa(env);
+ jobject trace = GetThreadStack(soa, javaThread);
+ if (trace == nullptr) {
+ return nullptr;
}
- return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
+ return Thread::InternalStackTraceToStackTraceElementArray(soa, trace);
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(VMStack, fillStackTraceElements, "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
+ NATIVE_METHOD(VMStack, fillStackTraceElements, "!(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
NATIVE_METHOD(VMStack, getCallingClassLoader, "!()Ljava/lang/ClassLoader;"),
NATIVE_METHOD(VMStack, getClosestUserClassLoader, "!(Ljava/lang/ClassLoader;Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;"),
NATIVE_METHOD(VMStack, getStackClass2, "!()Ljava/lang/Class;"),
- NATIVE_METHOD(VMStack, getThreadStackTrace, "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
+ NATIVE_METHOD(VMStack, getThreadStackTrace, "!(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
};
void register_dalvik_system_VMStack(JNIEnv* env) {
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 8bf36e7..6daf9a9 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -45,7 +45,7 @@ static mirror::Class* DecodeClass(const ScopedFastNativeObjectAccess& soa, jobje
// "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize,
jobject javaLoader) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
ScopedUtfChars name(env, javaName);
if (name.c_str() == nullptr) {
return nullptr;
@@ -96,7 +96,7 @@ static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
+ NATIVE_METHOD(Class, classForName, "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
NATIVE_METHOD(Class, getNameNative, "!()Ljava/lang/String;"),
NATIVE_METHOD(Class, getProxyInterfaces, "!()[Ljava/lang/Class;"),
};
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index f6149ff..636be5d 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -92,12 +92,12 @@ static jlong Runtime_freeMemory(JNIEnv*, jclass) {
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Runtime, freeMemory, "()J"),
+ NATIVE_METHOD(Runtime, freeMemory, "!()J"),
NATIVE_METHOD(Runtime, gc, "()V"),
- NATIVE_METHOD(Runtime, maxMemory, "()J"),
+ NATIVE_METHOD(Runtime, maxMemory, "!()J"),
NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;"),
- NATIVE_METHOD(Runtime, totalMemory, "()J"),
+ NATIVE_METHOD(Runtime, totalMemory, "!()J"),
};
void register_java_lang_Runtime(JNIEnv* env) {
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index 2665a08..de1b593 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -38,7 +38,7 @@ static jboolean Thread_interrupted(JNIEnv* env, jclass) {
}
static jboolean Thread_isInterrupted(JNIEnv* env, jobject java_thread) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
Thread* thread = Thread::FromManagedThread(soa, java_thread);
return (thread != NULL) ? thread->IsInterrupted() : JNI_FALSE;
@@ -170,8 +170,8 @@ static void Thread_yield(JNIEnv*, jobject) {
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Thread, currentThread, "!()Ljava/lang/Thread;"),
- NATIVE_METHOD(Thread, interrupted, "()Z"),
- NATIVE_METHOD(Thread, isInterrupted, "()Z"),
+ NATIVE_METHOD(Thread, interrupted, "!()Z"),
+ NATIVE_METHOD(Thread, isInterrupted, "!()Z"),
NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;JZ)V"),
NATIVE_METHOD(Thread, nativeGetStatus, "(Z)I"),
NATIVE_METHOD(Thread, nativeHoldsLock, "(Ljava/lang/Object;)Z"),
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index 332a130..d1a1105 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -15,26 +15,27 @@
*/
#include "jni_internal.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
#include "thread.h"
namespace art {
static jobject Throwable_nativeFillInStackTrace(JNIEnv* env, jclass) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
return soa.Self()->CreateInternalStackTrace(soa);
}
static jobjectArray Throwable_nativeGetStackTrace(JNIEnv* env, jclass, jobject javaStackState) {
- if (javaStackState == NULL) {
- return NULL;
+ if (javaStackState == nullptr) {
+ return nullptr;
}
- return Thread::InternalStackTraceToStackTraceElementArray(env, javaStackState);
+ ScopedFastNativeObjectAccess soa(env);
+ return Thread::InternalStackTraceToStackTraceElementArray(soa, javaStackState);
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Throwable, nativeFillInStackTrace, "()Ljava/lang/Object;"),
- NATIVE_METHOD(Throwable, nativeGetStackTrace, "(Ljava/lang/Object;)[Ljava/lang/StackTraceElement;"),
+ NATIVE_METHOD(Throwable, nativeFillInStackTrace, "!()Ljava/lang/Object;"),
+ NATIVE_METHOD(Throwable, nativeGetStackTrace, "!(Ljava/lang/Object;)[Ljava/lang/StackTraceElement;"),
};
void register_java_lang_Throwable(JNIEnv* env) {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 314cdb1..cb8e623 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -18,14 +18,14 @@
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
#include "ScopedUtfChars.h"
#include "zip_archive.h"
namespace art {
static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader, jstring javaName) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
ScopedUtfChars name(env, javaName);
if (name.c_str() == NULL) {
@@ -89,9 +89,9 @@ static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstri
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(VMClassLoader, findLoadedClass, "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;"),
+ NATIVE_METHOD(VMClassLoader, findLoadedClass, "!(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;"),
NATIVE_METHOD(VMClassLoader, getBootClassPathResource, "(Ljava/lang/String;I)Ljava/lang/String;"),
- NATIVE_METHOD(VMClassLoader, getBootClassPathSize, "()I"),
+ NATIVE_METHOD(VMClassLoader, getBootClassPathSize, "!()I"),
};
void register_java_lang_VMClassLoader(JNIEnv* env) {
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index c06bf4c..a22d7ca 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -22,7 +22,7 @@
#include "mirror/object-inl.h"
#include "object_utils.h"
#include "reflection.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
#include "well_known_classes.h"
namespace art {
@@ -35,8 +35,7 @@ namespace art {
* with an interface, array, or primitive class.
*/
static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
- // TODO: ScopedFastNativeObjectAccess
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
jobject art_method = soa.Env()->GetObjectField(
javaMethod, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 694f5e4..7e21d6c 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -90,7 +90,7 @@ static bool CheckReceiver(const ScopedFastNativeObjectAccess& soa, jobject j_rcv
class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
mirror::Class* declaringClass = f->GetDeclaringClass();
- if (!VerifyObjectInClass(class_or_rcvr, declaringClass)) {
+ if (!VerifyObjectIsClass(class_or_rcvr, declaringClass)) {
return false;
}
return true;
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index d29de3d..0b8bb7b 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -24,19 +24,19 @@
#include "mirror/proxy.h"
#include "object_utils.h"
#include "reflection.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
#include "well_known_classes.h"
namespace art {
static jobject Method_invoke(JNIEnv* env,
jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
}
static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
jobject art_method = soa.Env()->GetObjectField(
javaMethod, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
@@ -59,8 +59,8 @@ static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
- NATIVE_METHOD(Method, getExceptionTypesNative, "()[Ljava/lang/Class;"),
+ NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
+ NATIVE_METHOD(Method, getExceptionTypesNative, "!()[Ljava/lang/Class;"),
};
void register_java_lang_reflect_Method(JNIEnv* env) {
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 1266c41..07d670d 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -19,14 +19,14 @@
#include "mirror/class_loader.h"
#include "mirror/object_array.h"
#include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
#include "verify_object-inl.h"
namespace art {
static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
jobject loader, jobjectArray methods, jobjectArray throws) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::Class* result = class_linker->CreateProxyClass(soa, name, interfaces, loader, methods,
throws);
@@ -34,7 +34,7 @@ static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArra
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/ArtMethod;[[Ljava/lang/Class;)Ljava/lang/Class;"),
+ NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/ArtMethod;[[Ljava/lang/Class;)Ljava/lang/Class;"),
};
void register_java_lang_reflect_Proxy(JNIEnv* env) {
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 4f81a0b..1b9ebe4 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -18,7 +18,7 @@
#include "base/mutex.h"
#include "debugger.h"
#include "jni_internal.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "stack.h"
@@ -31,7 +31,7 @@ static void DdmVmInternal_enableRecentAllocations(JNIEnv*, jclass, jboolean enab
}
static jbyteArray DdmVmInternal_getRecentAllocations(JNIEnv* env, jclass) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
return Dbg::GetRecentAllocations();
}
@@ -46,24 +46,24 @@ static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) {
static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
// Suspend thread to build stack trace.
ThreadList* thread_list = Runtime::Current()->GetThreadList();
+ jobjectArray trace = nullptr;
bool timed_out;
Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id, false, &timed_out);
if (thread != NULL) {
- jobject trace;
{
ScopedObjectAccess soa(env);
- trace = thread->CreateInternalStackTrace(soa);
+ jobject internal_trace = thread->CreateInternalStackTrace(soa);
+ trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace);
}
// Restart suspended thread.
thread_list->Resume(thread, false);
- return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
} else {
if (timed_out) {
LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
"within a generous timeout.";
}
- return NULL;
}
+ return trace;
}
static void ThreadCountCallback(Thread*, void* context) {
@@ -136,7 +136,7 @@ static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) {
}
static jint DdmVmInternal_heapInfoNotify(JNIEnv* env, jclass, jint when) {
- ScopedObjectAccess soa(env);
+ ScopedFastNativeObjectAccess soa(env);
return Dbg::DdmHandleHpifChunk(static_cast<Dbg::HpifWhen>(when));
}
@@ -150,11 +150,11 @@ static void DdmVmInternal_threadNotify(JNIEnv*, jclass, jboolean enable) {
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(DdmVmInternal, enableRecentAllocations, "(Z)V"),
- NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "()[B"),
- NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "()Z"),
+ NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "!()[B"),
+ NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "!()Z"),
NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"),
NATIVE_METHOD(DdmVmInternal, getThreadStats, "()[B"),
- NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "(I)Z"),
+ NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "!(I)Z"),
NATIVE_METHOD(DdmVmInternal, heapSegmentNotify, "(IIZ)Z"),
NATIVE_METHOD(DdmVmInternal, threadNotify, "(Z)V"),
};
diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h
index 645d78c..744ac05 100644
--- a/runtime/native/scoped_fast_native_object_access.h
+++ b/runtime/native/scoped_fast_native_object_access.h
@@ -17,22 +17,19 @@
#ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
#define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
-#include "base/casts.h"
-#include "jni_internal.h"
-#include "thread-inl.h"
#include "mirror/art_method.h"
-#include "verify_object.h"
+#include "scoped_thread_state_change.h"
namespace art {
// Variant of ScopedObjectAccess that does no runnable transitions. Should only be used by "fast"
// JNI methods.
-class ScopedFastNativeObjectAccess {
+class ScopedFastNativeObjectAccess : public ScopedObjectAccess {
public:
explicit ScopedFastNativeObjectAccess(JNIEnv* env)
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
- : env_(down_cast<JNIEnvExt*>(env)), self_(ThreadForEnv(env)) {
+ : ScopedObjectAccess(env) {
Locks::mutator_lock_->AssertSharedHeld(Self());
DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
// Don't work with raw objects in non-runnable states.
@@ -42,57 +39,8 @@ class ScopedFastNativeObjectAccess {
~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
}
- Thread* Self() const {
- return self_;
- }
-
- JNIEnvExt* Env() const {
- return env_;
- }
-
- template<typename T>
- T Decode(jobject obj) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- // Don't work with raw objects in non-runnable states.
- DCHECK_EQ(Self()->GetState(), kRunnable);
- return down_cast<T>(Self()->DecodeJObject(obj));
- }
-
- mirror::ArtField* DecodeField(jfieldID fid) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- // Don't work with raw objects in non-runnable states.
- DCHECK_EQ(Self()->GetState(), kRunnable);
- return reinterpret_cast<mirror::ArtField*>(fid);
- }
-
- /*
- * Variant of ScopedObjectAccessUnched::AddLocalReference that without JNI work arounds
- * or check JNI that should be being used by fast native methods.
- */
- template<typename T>
- T AddLocalReference(mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- // Don't work with raw objects in non-runnable states.
- DCHECK_EQ(Self()->GetState(), kRunnable);
- if (obj == NULL) {
- return NULL;
- }
-
- DCHECK_NE((reinterpret_cast<uintptr_t>(obj) & 0xffff0000), 0xebad0000);
-
- IndirectReferenceTable& locals = Env()->locals;
-
- uint32_t cookie = Env()->local_ref_cookie;
- IndirectRef ref = locals.Add(cookie, obj);
-
- return reinterpret_cast<T>(ref);
- }
-
private:
- JNIEnvExt* const env_;
- Thread* const self_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedFastNativeObjectAccess);
};
} // namespace art
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 96ad55f..63801d3 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -341,7 +341,7 @@ class MethodHelper {
shorty_ = nullptr;
}
- const mirror::ArtMethod* GetMethod() const {
+ mirror::ArtMethod* GetMethod() const {
return method_;
}
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 0bfa70f..4310557 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -19,7 +19,6 @@
#include "class_linker.h"
#include "common_throws.h"
#include "dex_file-inl.h"
-#include "invoke_arg_array_builder.h"
#include "jni_internal.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
@@ -29,12 +28,440 @@
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "scoped_thread_state_change.h"
+#include "stack.h"
#include "well_known_classes.h"
namespace art {
-jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, jobject javaReceiver,
- jobject javaArgs) {
+class ArgArray {
+ public:
+ explicit ArgArray(const char* shorty, uint32_t shorty_len)
+ : shorty_(shorty), shorty_len_(shorty_len), num_bytes_(0) {
+ size_t num_slots = shorty_len + 1; // +1 in case of receiver.
+ if (LIKELY((num_slots * 2) < kSmallArgArraySize)) {
+ // We can trivially use the small arg array.
+ arg_array_ = small_arg_array_;
+ } else {
+ // Analyze shorty to see if we need the large arg array.
+ for (size_t i = 1; i < shorty_len; ++i) {
+ char c = shorty[i];
+ if (c == 'J' || c == 'D') {
+ num_slots++;
+ }
+ }
+ if (num_slots <= kSmallArgArraySize) {
+ arg_array_ = small_arg_array_;
+ } else {
+ large_arg_array_.reset(new uint32_t[num_slots]);
+ arg_array_ = large_arg_array_.get();
+ }
+ }
+ }
+
+ uint32_t* GetArray() {
+ return arg_array_;
+ }
+
+ uint32_t GetNumBytes() {
+ return num_bytes_;
+ }
+
+ void Append(uint32_t value) {
+ arg_array_[num_bytes_ / 4] = value;
+ num_bytes_ += 4;
+ }
+
+ void Append(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Append(StackReference<mirror::Object>::FromMirrorPtr(obj).AsVRegValue());
+ }
+
+ void AppendWide(uint64_t value) {
+ // For ARM and MIPS portable, align wide values to 8 bytes (ArgArray starts at offset of 4).
+#if defined(ART_USE_PORTABLE_COMPILER) && (defined(__arm__) || defined(__mips__))
+ if (num_bytes_ % 8 == 0) {
+ num_bytes_ += 4;
+ }
+#endif
+ arg_array_[num_bytes_ / 4] = value;
+ arg_array_[(num_bytes_ / 4) + 1] = value >> 32;
+ num_bytes_ += 8;
+ }
+
+ void AppendFloat(float value) {
+ jvalue jv;
+ jv.f = value;
+ Append(jv.i);
+ }
+
+ void AppendDouble(double value) {
+ jvalue jv;
+ jv.d = value;
+ AppendWide(jv.j);
+ }
+
+ void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, va_list ap)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Set receiver if non-null (method is not static)
+ if (receiver != nullptr) {
+ Append(receiver);
+ }
+ for (size_t i = 1; i < shorty_len_; ++i) {
+ switch (shorty_[i]) {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ case 'I':
+ Append(va_arg(ap, jint));
+ break;
+ case 'F':
+ AppendFloat(va_arg(ap, jdouble));
+ break;
+ case 'L':
+ Append(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
+ break;
+ case 'D':
+ AppendDouble(va_arg(ap, jdouble));
+ break;
+ case 'J':
+ AppendWide(va_arg(ap, jlong));
+ break;
+#ifndef NDEBUG
+ default:
+ LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
+#endif
+ }
+ }
+ }
+
+ void BuildArgArray(const ScopedObjectAccessUnchecked& soa, mirror::Object* receiver,
+ jvalue* args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Set receiver if non-null (method is not static)
+ if (receiver != nullptr) {
+ Append(receiver);
+ }
+ for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
+ switch (shorty_[i]) {
+ case 'Z':
+ Append(args[args_offset].z);
+ break;
+ case 'B':
+ Append(args[args_offset].b);
+ break;
+ case 'C':
+ Append(args[args_offset].c);
+ break;
+ case 'S':
+ Append(args[args_offset].s);
+ break;
+ case 'I':
+ case 'F':
+ Append(args[args_offset].i);
+ break;
+ case 'L':
+ Append(soa.Decode<mirror::Object*>(args[args_offset].l));
+ break;
+ case 'D':
+ case 'J':
+ AppendWide(args[args_offset].j);
+ break;
+#ifndef NDEBUG
+ default:
+ LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
+#endif
+ }
+ }
+ }
+
+ void BuildArgArrayFromFrame(ShadowFrame* shadow_frame, uint32_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Set receiver if non-null (method is not static)
+ size_t cur_arg = arg_offset;
+ if (!shadow_frame->GetMethod()->IsStatic()) {
+ Append(shadow_frame->GetVReg(cur_arg));
+ cur_arg++;
+ }
+ for (size_t i = 1; i < shorty_len_; ++i) {
+ switch (shorty_[i]) {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ case 'I':
+ case 'F':
+ case 'L':
+ Append(shadow_frame->GetVReg(cur_arg));
+ cur_arg++;
+ break;
+ case 'D':
+ case 'J':
+ AppendWide(shadow_frame->GetVRegLong(cur_arg));
+ cur_arg++;
+ cur_arg++;
+ break;
+#ifndef NDEBUG
+ default:
+ LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
+#endif
+ }
+ }
+ }
+
+ static void ThrowIllegalPrimitiveArgumentException(const char* expected,
+ const StringPiece& found_descriptor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ThrowIllegalArgumentException(nullptr,
+ StringPrintf("Invalid primitive conversion from %s to %s", expected,
+ PrettyDescriptor(found_descriptor.as_string()).c_str()).c_str());
+ }
+
+ bool BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver,
+ mirror::ObjectArray<mirror::Object>* args, MethodHelper& mh)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const DexFile::TypeList* classes = mh.GetParameterTypeList();
+ // Set receiver if non-null (method is not static)
+ if (receiver != nullptr) {
+ Append(receiver);
+ }
+ for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
+ mirror::Object* arg = args->Get(args_offset);
+ if (((shorty_[i] == 'L') && (arg != nullptr)) || ((arg == nullptr && shorty_[i] != 'L'))) {
+ mirror::Class* dst_class =
+ mh.GetClassFromTypeIdx(classes->GetTypeItem(args_offset).type_idx_);
+ if (UNLIKELY(arg == nullptr || !arg->InstanceOf(dst_class))) {
+ ThrowIllegalArgumentException(nullptr,
+ StringPrintf("method %s argument %d has type %s, got %s",
+ PrettyMethod(mh.GetMethod(), false).c_str(),
+ args_offset + 1, // Humans don't count from 0.
+ PrettyDescriptor(dst_class).c_str(),
+ PrettyTypeOf(arg).c_str()).c_str());
+ return false;
+ }
+ }
+
+#define DO_FIRST_ARG(match_descriptor, get_fn, append) { \
+ const StringPiece src_descriptor(arg != nullptr \
+ ? ClassHelper(arg->GetClass<>()).GetDescriptor() \
+ : "null"); \
+ if (LIKELY(src_descriptor == match_descriptor)) { \
+ mirror::ArtField* primitive_field = arg->GetClass()->GetIFields()->Get(0); \
+ append(primitive_field-> get_fn(arg));
+
+#define DO_ARG(match_descriptor, get_fn, append) \
+ } else if (LIKELY(src_descriptor == match_descriptor)) { \
+ mirror::ArtField* primitive_field = arg->GetClass()->GetIFields()->Get(0); \
+ append(primitive_field-> get_fn(arg));
+
+#define DO_FAIL(expected) \
+ } else { \
+ if (arg->GetClass<>()->IsPrimitive()) { \
+ ThrowIllegalPrimitiveArgumentException(expected, src_descriptor); \
+ } else { \
+ ThrowIllegalArgumentException(nullptr, \
+ StringPrintf("method %s argument %d has type %s, got %s", \
+ PrettyMethod(mh.GetMethod(), false).c_str(), \
+ args_offset + 1, \
+ expected, \
+ PrettyTypeOf(arg).c_str()).c_str()); \
+ } \
+ return false; \
+ } }
+
+ switch (shorty_[i]) {
+ case 'L':
+ Append(arg);
+ break;
+ case 'Z':
+ DO_FIRST_ARG("Ljava/lang/Boolean;", GetBoolean, Append)
+ DO_FAIL("boolean")
+ break;
+ case 'B':
+ DO_FIRST_ARG("Ljava/lang/Byte;", GetByte, Append)
+ DO_FAIL("byte")
+ break;
+ case 'C':
+ DO_FIRST_ARG("Ljava/lang/Character;", GetChar, Append)
+ DO_FAIL("char")
+ break;
+ case 'S':
+ DO_FIRST_ARG("Ljava/lang/Short;", GetShort, Append)
+ DO_ARG("Ljava/lang/Byte;", GetByte, Append)
+ DO_FAIL("short")
+ break;
+ case 'I':
+ DO_FIRST_ARG("Ljava/lang/Integer;", GetInt, Append)
+ DO_ARG("Ljava/lang/Character;", GetChar, Append)
+ DO_ARG("Ljava/lang/Short;", GetShort, Append)
+ DO_ARG("Ljava/lang/Byte;", GetByte, Append)
+ DO_FAIL("int")
+ break;
+ case 'J':
+ DO_FIRST_ARG("Ljava/lang/Long;", GetLong, AppendWide)
+ DO_ARG("Ljava/lang/Integer;", GetInt, AppendWide)
+ DO_ARG("Ljava/lang/Character;", GetChar, AppendWide)
+ DO_ARG("Ljava/lang/Short;", GetShort, AppendWide)
+ DO_ARG("Ljava/lang/Byte;", GetByte, AppendWide)
+ DO_FAIL("long")
+ break;
+ case 'F':
+ DO_FIRST_ARG("Ljava/lang/Float;", GetFloat, AppendFloat)
+ DO_ARG("Ljava/lang/Long;", GetLong, AppendFloat)
+ DO_ARG("Ljava/lang/Integer;", GetInt, AppendFloat)
+ DO_ARG("Ljava/lang/Character;", GetChar, AppendFloat)
+ DO_ARG("Ljava/lang/Short;", GetShort, AppendFloat)
+ DO_ARG("Ljava/lang/Byte;", GetByte, AppendFloat)
+ DO_FAIL("float")
+ break;
+ case 'D':
+ DO_FIRST_ARG("Ljava/lang/Double;", GetDouble, AppendDouble)
+ DO_ARG("Ljava/lang/Float;", GetFloat, AppendDouble)
+ DO_ARG("Ljava/lang/Long;", GetLong, AppendDouble)
+ DO_ARG("Ljava/lang/Integer;", GetInt, AppendDouble)
+ DO_ARG("Ljava/lang/Character;", GetChar, AppendDouble)
+ DO_ARG("Ljava/lang/Short;", GetShort, AppendDouble)
+ DO_ARG("Ljava/lang/Byte;", GetByte, AppendDouble)
+ DO_FAIL("double")
+ break;
+#ifndef NDEBUG
+ default:
+ LOG(FATAL) << "Unexpected shorty character: " << shorty_[i];
+#endif
+ }
+#undef DO_FIRST_ARG
+#undef DO_ARG
+#undef DO_FAIL
+ }
+ return true;
+ }
+
+ private:
+ enum { kSmallArgArraySize = 16 };
+ const char* const shorty_;
+ const uint32_t shorty_len_;
+ uint32_t num_bytes_;
+ uint32_t* arg_array_;
+ uint32_t small_arg_array_[kSmallArgArraySize];
+ UniquePtr<uint32_t[]> large_arg_array_;
+};
+
+static void CheckMethodArguments(mirror::ArtMethod* m, uint32_t* args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const DexFile::TypeList* params = MethodHelper(m).GetParameterTypeList();
+ if (params == nullptr) {
+ return; // No arguments so nothing to check.
+ }
+ uint32_t offset = 0;
+ uint32_t num_params = params->Size();
+ size_t error_count = 0;
+ if (!m->IsStatic()) {
+ offset = 1;
+ }
+ for (uint32_t i = 0; i < num_params; i++) {
+ uint16_t type_idx = params->GetTypeItem(i).type_idx_;
+ mirror::Class* param_type = MethodHelper(m).GetClassFromTypeIdx(type_idx);
+ if (param_type == nullptr) {
+ Thread* self = Thread::Current();
+ CHECK(self->IsExceptionPending());
+ LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
+ << MethodHelper(m).GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
+ << self->GetException(nullptr)->Dump();
+ self->ClearException();
+ ++error_count;
+ } else if (!param_type->IsPrimitive()) {
+ // TODO: check primitives are in range.
+ mirror::Object* argument = reinterpret_cast<mirror::Object*>(args[i + offset]);
+ if (argument != nullptr && !argument->InstanceOf(param_type)) {
+ LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
+ << PrettyTypeOf(argument) << " as argument " << (i + 1)
+ << " to " << PrettyMethod(m);
+ ++error_count;
+ }
+ } else if (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble()) {
+ offset++;
+ }
+ }
+ if (error_count > 0) {
+ // TODO: pass the JNI function name (such as "CallVoidMethodV") through so we can call JniAbort
+ // with an argument.
+ JniAbortF(nullptr, "bad arguments passed to %s (see above for details)",
+ PrettyMethod(m).c_str());
+ }
+}
+
+static mirror::ArtMethod* FindVirtualMethod(mirror::Object* receiver,
+ mirror::ArtMethod* method)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method);
+}
+
+
+static void InvokeWithArgArray(const ScopedObjectAccessUnchecked& soa, mirror::ArtMethod* method,
+ ArgArray* arg_array, JValue* result, const char* shorty)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ uint32_t* args = arg_array->GetArray();
+ if (UNLIKELY(soa.Env()->check_jni)) {
+ CheckMethodArguments(method, args);
+ }
+ method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
+}
+
+JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj, jmethodID mid, va_list args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::ArtMethod* method = soa.DecodeMethod(mid);
+ mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+ MethodHelper mh(method);
+ JValue result;
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+ return result;
+}
+
+JValue InvokeWithJValues(const ScopedObjectAccessUnchecked& soa, mirror::Object* receiver,
+ jmethodID mid, jvalue* args) {
+ mirror::ArtMethod* method = soa.DecodeMethod(mid);
+ MethodHelper mh(method);
+ JValue result;
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+ return result;
+}
+
+JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa,
+ mirror::Object* receiver, jmethodID mid, jvalue* args) {
+ mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+ MethodHelper mh(method);
+ JValue result;
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+ return result;
+}
+
+JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa,
+ jobject obj, jmethodID mid, va_list args) {
+ mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+ mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+ MethodHelper mh(method);
+ JValue result;
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+ return result;
+}
+
+void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
+ MethodHelper& mh, JValue* result) {
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
+ shadow_frame->GetMethod()->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result,
+ mh.GetShorty());
+}
+
+jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod,
+ jobject javaReceiver, jobject javaArgs) {
jmethodID mid = soa.Env()->FromReflectedMethod(javaMethod);
mirror::ArtMethod* m = soa.DecodeMethod(mid);
@@ -47,17 +474,16 @@ jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, jobject
declaring_class = sirt_c.get();
}
- mirror::Object* receiver = NULL;
+ mirror::Object* receiver = nullptr;
if (!m->IsStatic()) {
// Check that the receiver is non-null and an instance of the field's declaring class.
receiver = soa.Decode<mirror::Object*>(javaReceiver);
- if (!VerifyObjectInClass(receiver, declaring_class)) {
+ if (!VerifyObjectIsClass(receiver, declaring_class)) {
return NULL;
}
// Find the actual implementation of the virtual method.
m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
- mid = soa.EncodeMethod(m);
}
// Get our arrays of arguments and their types, and check they're the same size.
@@ -65,8 +491,8 @@ jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, jobject
soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs);
MethodHelper mh(m);
const DexFile::TypeList* classes = mh.GetParameterTypeList();
- uint32_t classes_size = classes == NULL ? 0 : classes->Size();
- uint32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
+ uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
+ uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0;
if (arg_count != classes_size) {
ThrowIllegalArgumentException(NULL,
StringPrintf("Wrong number of arguments; expected %d, got %d",
@@ -74,22 +500,15 @@ jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, jobject
return NULL;
}
- // Translate javaArgs to a jvalue[].
- UniquePtr<jvalue[]> args(new jvalue[arg_count]);
- JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
- for (uint32_t i = 0; i < arg_count; ++i) {
- mirror::Object* arg = objects->Get(i);
- mirror::Class* dst_class = mh.GetClassFromTypeIdx(classes->GetTypeItem(i).type_idx_);
- if (!UnboxPrimitiveForArgument(arg, dst_class, decoded_args[i], m, i)) {
- return NULL;
- }
- if (!dst_class->IsPrimitive()) {
- args[i].l = soa.AddLocalReference<jobject>(arg);
- }
+ // Invoke the method.
+ JValue result;
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ if (!arg_array.BuildArgArray(soa, receiver, objects, mh)) {
+ CHECK(soa.Self()->IsExceptionPending());
+ return nullptr;
}
- // Invoke the method.
- JValue value(InvokeWithJValues(soa, javaReceiver, mid, args.get()));
+ InvokeWithArgArray(soa, m, &arg_array, &result, mh.GetShorty());
// Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
if (soa.Self()->IsExceptionPending()) {
@@ -103,10 +522,11 @@ jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, jobject
}
// Box if necessary and return.
- return soa.AddLocalReference<jobject>(BoxPrimitive(mh.GetReturnType()->GetPrimitiveType(), value));
+ return soa.AddLocalReference<jobject>(BoxPrimitive(mh.GetReturnType()->GetPrimitiveType(),
+ result));
}
-bool VerifyObjectInClass(mirror::Object* o, mirror::Class* c) {
+bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) {
if (o == NULL) {
ThrowNullPointerException(NULL, "null receiver");
return false;
@@ -218,6 +638,10 @@ mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
if (src_class == Primitive::kPrimNot) {
return value.GetL();
}
+ if (src_class == Primitive::kPrimVoid) {
+ // There's no such thing as a void field, and void methods invoked via reflection return null.
+ return nullptr;
+ }
jmethodID m = NULL;
const char* shorty;
@@ -254,20 +678,15 @@ mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
m = WellKnownClasses::java_lang_Short_valueOf;
shorty = "LS";
break;
- case Primitive::kPrimVoid:
- // There's no such thing as a void field, and void methods invoked via reflection return null.
- return nullptr;
default:
LOG(FATAL) << static_cast<int>(src_class);
shorty = nullptr;
}
ScopedObjectAccessUnchecked soa(Thread::Current());
- if (kIsDebugBuild) {
- CHECK_EQ(soa.Self()->GetState(), kRunnable);
- }
+ DCHECK_EQ(soa.Self()->GetState(), kRunnable);
- ArgArray arg_array(nullptr, 0);
+ ArgArray arg_array(shorty, 2);
JValue result;
if (src_class == Primitive::kPrimDouble || src_class == Primitive::kPrimLong) {
arg_array.AppendWide(value.GetJ());
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 13c90af..d2f9f25 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -28,7 +28,10 @@ namespace mirror {
class Object;
} // namespace mirror
union JValue;
+class MethodHelper;
class ScopedObjectAccess;
+class ScopedObjectAccessUnchecked;
+class ShadowFrame;
class ThrowLocation;
mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value)
@@ -48,10 +51,30 @@ bool ConvertPrimitiveValue(const ThrowLocation* throw_location, bool unbox_for_r
const JValue& src, JValue& dst)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-jobject InvokeMethod(const ScopedObjectAccess& soa, jobject method, jobject receiver, jobject args)
+JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj, jmethodID mid, va_list args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-bool VerifyObjectInClass(mirror::Object* o, mirror::Class* c)
+JValue InvokeWithJValues(const ScopedObjectAccessUnchecked& soa, mirror::Object* receiver,
+ jmethodID mid, jvalue* args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa,
+ mirror::Object* receiver, jmethodID mid, jvalue* args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa,
+ jobject obj, jmethodID mid, va_list args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
+ MethodHelper& mh, JValue* result)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+jobject InvokeMethod(const ScopedObjectAccess& soa, jobject method, jobject receiver,
+ jobject args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
} // namespace art
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
new file mode 100644
index 0000000..c14da5d
--- /dev/null
+++ b/runtime/reflection_test.cc
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "reflection.h"
+
+#include <cmath>
+
+#include "common_compiler_test.h"
+#include "mirror/art_method-inl.h"
+
+namespace art {
+
+// TODO: Convert to CommonRuntimeTest. Currently MakeExecutable is used.
+class ReflectionTest : public CommonCompilerTest {
+ protected:
+ virtual void SetUp() {
+ CommonCompilerTest::SetUp();
+
+ vm_ = Runtime::Current()->GetJavaVM();
+
+ // Turn on -verbose:jni for the JNI tests.
+ // gLogVerbosity.jni = true;
+
+ vm_->AttachCurrentThread(&env_, NULL);
+
+ ScopedLocalRef<jclass> aioobe(env_,
+ env_->FindClass("java/lang/ArrayIndexOutOfBoundsException"));
+ CHECK(aioobe.get() != NULL);
+ aioobe_ = reinterpret_cast<jclass>(env_->NewGlobalRef(aioobe.get()));
+
+ ScopedLocalRef<jclass> ase(env_, env_->FindClass("java/lang/ArrayStoreException"));
+ CHECK(ase.get() != NULL);
+ ase_ = reinterpret_cast<jclass>(env_->NewGlobalRef(ase.get()));
+
+ ScopedLocalRef<jclass> sioobe(env_,
+ env_->FindClass("java/lang/StringIndexOutOfBoundsException"));
+ CHECK(sioobe.get() != NULL);
+ sioobe_ = reinterpret_cast<jclass>(env_->NewGlobalRef(sioobe.get()));
+ }
+
+ void CleanUpJniEnv() {
+ if (aioobe_ != NULL) {
+ env_->DeleteGlobalRef(aioobe_);
+ aioobe_ = NULL;
+ }
+ if (ase_ != NULL) {
+ env_->DeleteGlobalRef(ase_);
+ ase_ = NULL;
+ }
+ if (sioobe_ != NULL) {
+ env_->DeleteGlobalRef(sioobe_);
+ sioobe_ = NULL;
+ }
+ }
+
+ virtual void TearDown() {
+ CleanUpJniEnv();
+ CommonCompilerTest::TearDown();
+ }
+
+ jclass GetPrimitiveClass(char descriptor) {
+ ScopedObjectAccess soa(env_);
+ mirror::Class* c = class_linker_->FindPrimitiveClass(descriptor);
+ CHECK(c != nullptr);
+ return soa.AddLocalReference<jclass>(c);
+ }
+
+ void ReflectionTestMakeExecutable(mirror::ArtMethod** method,
+ mirror::Object** receiver,
+ bool is_static, const char* method_name,
+ const char* method_signature)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const char* class_name = is_static ? "StaticLeafMethods" : "NonStaticLeafMethods";
+ jobject jclass_loader(LoadDex(class_name));
+ Thread* self = Thread::Current();
+ SirtRef<mirror::ClassLoader> null_class_loader(self, nullptr);
+ SirtRef<mirror::ClassLoader>
+ class_loader(self,
+ ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader));
+ if (is_static) {
+ MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
+ class_name);
+ } else {
+ MakeExecutable(nullptr, "java.lang.Class");
+ MakeExecutable(nullptr, "java.lang.Object");
+ MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
+ class_name);
+ }
+
+ mirror::Class* c = class_linker_->FindClass(self, DotToDescriptor(class_name).c_str(),
+ class_loader);
+ CHECK(c != NULL);
+
+ *method = is_static ? c->FindDirectMethod(method_name, method_signature)
+ : c->FindVirtualMethod(method_name, method_signature);
+ CHECK(method != nullptr);
+
+ *receiver = (is_static ? nullptr : c->AllocObject(self));
+
+ // Start runtime.
+ bool started = runtime_->Start();
+ CHECK(started);
+ self->TransitionFromSuspendedToRunnable();
+ }
+
+ void InvokeNopMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "nop", "()V");
+ InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), nullptr);
+ }
+
+ void InvokeIdentityByteMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "identity", "(B)B");
+ jvalue args[1];
+
+ args[0].b = 0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0, result.GetB());
+
+ args[0].b = -1;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-1, result.GetB());
+
+ args[0].b = SCHAR_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(SCHAR_MAX, result.GetB());
+
+ args[0].b = (SCHAR_MIN << 24) >> 24;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(SCHAR_MIN, result.GetB());
+ }
+
+ void InvokeIdentityIntMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "identity", "(I)I");
+ jvalue args[1];
+
+ args[0].i = 0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0, result.GetI());
+
+ args[0].i = -1;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-1, result.GetI());
+
+ args[0].i = INT_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(INT_MAX, result.GetI());
+
+ args[0].i = INT_MIN;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(INT_MIN, result.GetI());
+ }
+
+ void InvokeIdentityDoubleMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "identity", "(D)D");
+ jvalue args[1];
+
+ args[0].d = 0.0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0.0, result.GetD());
+
+ args[0].d = -1.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-1.0, result.GetD());
+
+ args[0].d = DBL_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(DBL_MAX, result.GetD());
+
+ args[0].d = DBL_MIN;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(DBL_MIN, result.GetD());
+ }
+
+ void InvokeSumIntIntMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(II)I");
+ jvalue args[2];
+
+ args[0].i = 1;
+ args[1].i = 2;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(3, result.GetI());
+
+ args[0].i = -2;
+ args[1].i = 5;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(3, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MIN;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-1, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-2, result.GetI());
+ }
+
+ void InvokeSumIntIntIntMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(III)I");
+ jvalue args[3];
+
+ args[0].i = 0;
+ args[1].i = 0;
+ args[2].i = 0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0, result.GetI());
+
+ args[0].i = 1;
+ args[1].i = 2;
+ args[2].i = 3;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(6, result.GetI());
+
+ args[0].i = -1;
+ args[1].i = 2;
+ args[2].i = -3;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-2, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MIN;
+ args[2].i = INT_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(2147483646, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MAX;
+ args[2].i = INT_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(2147483645, result.GetI());
+ }
+
+ void InvokeSumIntIntIntIntMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(IIII)I");
+ jvalue args[4];
+
+ args[0].i = 0;
+ args[1].i = 0;
+ args[2].i = 0;
+ args[3].i = 0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0, result.GetI());
+
+ args[0].i = 1;
+ args[1].i = 2;
+ args[2].i = 3;
+ args[3].i = 4;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(10, result.GetI());
+
+ args[0].i = -1;
+ args[1].i = 2;
+ args[2].i = -3;
+ args[3].i = 4;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(2, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MIN;
+ args[2].i = INT_MAX;
+ args[3].i = INT_MIN;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-2, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MAX;
+ args[2].i = INT_MAX;
+ args[3].i = INT_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-4, result.GetI());
+ }
+
+ void InvokeSumIntIntIntIntIntMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(IIIII)I");
+ jvalue args[5];
+
+ args[0].i = 0;
+ args[1].i = 0;
+ args[2].i = 0;
+ args[3].i = 0;
+ args[4].i = 0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0, result.GetI());
+
+ args[0].i = 1;
+ args[1].i = 2;
+ args[2].i = 3;
+ args[3].i = 4;
+ args[4].i = 5;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(15, result.GetI());
+
+ args[0].i = -1;
+ args[1].i = 2;
+ args[2].i = -3;
+ args[3].i = 4;
+ args[4].i = -5;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-3, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MIN;
+ args[2].i = INT_MAX;
+ args[3].i = INT_MIN;
+ args[4].i = INT_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(2147483645, result.GetI());
+
+ args[0].i = INT_MAX;
+ args[1].i = INT_MAX;
+ args[2].i = INT_MAX;
+ args[3].i = INT_MAX;
+ args[4].i = INT_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(2147483643, result.GetI());
+ }
+
+ void InvokeSumDoubleDoubleMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DD)D");
+ jvalue args[2];
+
+ args[0].d = 0.0;
+ args[1].d = 0.0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = 2.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(3.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = -2.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-1.0, result.GetD());
+
+ args[0].d = DBL_MAX;
+ args[1].d = DBL_MIN;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(1.7976931348623157e308, result.GetD());
+
+ args[0].d = DBL_MAX;
+ args[1].d = DBL_MAX;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(INFINITY, result.GetD());
+ }
+
+ void InvokeSumDoubleDoubleDoubleMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDD)D");
+ jvalue args[3];
+
+ args[0].d = 0.0;
+ args[1].d = 0.0;
+ args[2].d = 0.0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = 2.0;
+ args[2].d = 3.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(6.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = -2.0;
+ args[2].d = 3.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(2.0, result.GetD());
+ }
+
+ void InvokeSumDoubleDoubleDoubleDoubleMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDDD)D");
+ jvalue args[4];
+
+ args[0].d = 0.0;
+ args[1].d = 0.0;
+ args[2].d = 0.0;
+ args[3].d = 0.0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = 2.0;
+ args[2].d = 3.0;
+ args[3].d = 4.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(10.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = -2.0;
+ args[2].d = 3.0;
+ args[3].d = -4.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(-2.0, result.GetD());
+ }
+
+ void InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(bool is_static) {
+ ScopedObjectAccess soa(env_);
+ mirror::ArtMethod* method;
+ mirror::Object* receiver;
+ ReflectionTestMakeExecutable(&method, &receiver, is_static, "sum", "(DDDDD)D");
+ jvalue args[5];
+
+ args[0].d = 0.0;
+ args[1].d = 0.0;
+ args[2].d = 0.0;
+ args[3].d = 0.0;
+ args[4].d = 0.0;
+ JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(0.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = 2.0;
+ args[2].d = 3.0;
+ args[3].d = 4.0;
+ args[4].d = 5.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(15.0, result.GetD());
+
+ args[0].d = 1.0;
+ args[1].d = -2.0;
+ args[2].d = 3.0;
+ args[3].d = -4.0;
+ args[4].d = 5.0;
+ result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
+ EXPECT_EQ(3.0, result.GetD());
+ }
+
+ JavaVMExt* vm_;
+ JNIEnv* env_;
+ jclass aioobe_;
+ jclass ase_;
+ jclass sioobe_;
+};
+
+TEST_F(ReflectionTest, StaticMainMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ ScopedObjectAccess soa(Thread::Current());
+ jobject jclass_loader = LoadDex("Main");
+ SirtRef<mirror::ClassLoader>
+ class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
+ CompileDirectMethod(class_loader, "Main", "main", "([Ljava/lang/String;)V");
+
+ mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader);
+ ASSERT_TRUE(klass != NULL);
+
+ mirror::ArtMethod* method = klass->FindDirectMethod("main", "([Ljava/lang/String;)V");
+ ASSERT_TRUE(method != NULL);
+
+ // Start runtime.
+ bool started = runtime_->Start();
+ CHECK(started);
+ soa.Self()->TransitionFromSuspendedToRunnable();
+
+ jvalue args[1];
+ args[0].l = nullptr;
+ InvokeWithJValues(soa, nullptr, soa.EncodeMethod(method), args);
+}
+
+TEST_F(ReflectionTest, StaticNopMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeNopMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticNopMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeNopMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticIdentityByteMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeIdentityByteMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticIdentityByteMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeIdentityByteMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticIdentityIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeIdentityIntMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticIdentityIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeIdentityIntMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticIdentityDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeIdentityDoubleMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticIdentityDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeIdentityDoubleMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumIntIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntIntMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumIntIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntIntMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumIntIntIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntIntIntMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumIntIntIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntIntIntMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumIntIntIntIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntIntIntIntMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumIntIntIntIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumIntIntIntIntIntMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumDoubleDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleDoubleMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumDoubleDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleDoubleMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleDoubleDoubleMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumDoubleDoubleDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleDoubleDoubleMethod(false);
+}
+
+TEST_F(ReflectionTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(true);
+}
+
+TEST_F(ReflectionTest, NonStaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
+ InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(false);
+}
+
+} // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1555bf2..51edc85 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -42,7 +42,6 @@
#include "image.h"
#include "instrumentation.h"
#include "intern_table.h"
-#include "invoke_arg_array_builder.h"
#include "jni_internal.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
@@ -54,6 +53,7 @@
#include "monitor.h"
#include "parsed_options.h"
#include "oat_file.h"
+#include "reflection.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change.h"
#include "signal_catcher.h"
@@ -316,9 +316,7 @@ jobject CreateSystemClassLoader() {
class_loader_class->FindDirectMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;");
CHECK(getSystemClassLoader != NULL);
- JValue result;
- ArgArray arg_array(nullptr, 0);
- InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, "L");
+ JValue result = InvokeWithJValues(soa, nullptr, soa.EncodeMethod(getSystemClassLoader), nullptr);
SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
down_cast<mirror::ClassLoader*>(result.GetL()));
CHECK(class_loader.get() != nullptr);
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index d9e7986..ebc5452 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -171,28 +171,7 @@ class ScopedObjectAccessUnchecked : public ScopedThreadStateChange {
DCHECK_NE((reinterpret_cast<uintptr_t>(obj) & 0xffff0000), 0xebad0000);
- IndirectReferenceTable& locals = Env()->locals;
-
- uint32_t cookie = Env()->local_ref_cookie;
- IndirectRef ref = locals.Add(cookie, obj);
-
-#if 0 // TODO: fix this to understand PushLocalFrame, so we can turn it on.
- if (Env()->check_jni) {
- size_t entry_count = locals.Capacity();
- if (entry_count > 16) {
- LOG(WARNING) << "Warning: more than 16 JNI local references: "
- << entry_count << " (most recent was a " << PrettyTypeOf(obj) << ")\n"
- << Dumpable<IndirectReferenceTable>(locals);
- // TODO: LOG(FATAL) in a later release?
- }
- }
-#endif
- if (Vm()->work_around_app_jni_bugs) {
- // Hand out direct pointers to support broken old apps.
- return reinterpret_cast<T>(obj);
- }
-
- return reinterpret_cast<T>(ref);
+ return Env()->AddLocalReference<T>(obj, Vm()->work_around_app_jni_bugs);
}
template<typename T>
diff --git a/runtime/thread.cc b/runtime/thread.cc
index f4b9d9a..f5ed082 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -45,7 +45,6 @@
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
#include "gc/space/space.h"
-#include "invoke_arg_array_builder.h"
#include "jni_internal.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
@@ -174,12 +173,7 @@ void* Thread::CreateCallback(void* arg) {
// Invoke the 'run' method of our java.lang.Thread.
mirror::Object* receiver = self->opeer_;
jmethodID mid = WellKnownClasses::java_lang_Thread_run;
- mirror::ArtMethod* m =
- receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(soa.DecodeMethod(mid));
- JValue result;
- ArgArray arg_array(nullptr, 0);
- arg_array.Append(receiver);
- m->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, "V");
+ InvokeVirtualOrInterfaceWithJValues(soa, receiver, mid, nullptr);
}
// Detach and delete self.
Runtime::Current()->GetThreadList()->Unregister(self);
@@ -1413,10 +1407,8 @@ jobject Thread::CreateInternalStackTrace(const ScopedObjectAccessUnchecked& soa)
return soa.AddLocalReference<jobjectArray>(trace);
}
-jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, jobject internal,
- jobjectArray output_array, int* stack_depth) {
- // Transition into runnable state to work on Object*/Array*
- ScopedObjectAccess soa(env);
+jobjectArray Thread::InternalStackTraceToStackTraceElementArray(const ScopedObjectAccess& soa,
+ jobject internal, jobjectArray output_array, int* stack_depth) {
// Decode the internal stack trace into the depth, method trace and PC trace
int32_t depth = soa.Decode<mirror::ObjectArray<mirror::Object>*>(internal)->GetLength() - 1;
@@ -1526,11 +1518,12 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
const char* exception_class_descriptor,
const char* msg) {
DCHECK_EQ(this, Thread::Current());
+ ScopedObjectAccessUnchecked soa(this);
// Ensure we don't forget arguments over object allocation.
SirtRef<mirror::Object> saved_throw_this(this, throw_location.GetThis());
SirtRef<mirror::ArtMethod> saved_throw_method(this, throw_location.GetMethod());
// Ignore the cause throw location. TODO: should we report this as a re-throw?
- SirtRef<mirror::Throwable> cause(this, GetException(nullptr));
+ ScopedLocalRef<jobject> cause(GetJniEnv(), soa.AddLocalReference<jobject>(GetException(nullptr)));
ClearException();
Runtime* runtime = Runtime::Current();
@@ -1567,10 +1560,11 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
// Choose an appropriate constructor and set up the arguments.
const char* signature;
const char* shorty;
- SirtRef<mirror::String> msg_string(this, nullptr);
+ ScopedLocalRef<jstring> msg_string(GetJniEnv(), nullptr);
if (msg != nullptr) {
// Ensure we remember this and the method over the String allocation.
- msg_string.reset(mirror::String::AllocFromModifiedUtf8(this, msg));
+ msg_string.reset(
+ soa.AddLocalReference<jstring>(mirror::String::AllocFromModifiedUtf8(this, msg)));
if (UNLIKELY(msg_string.get() == nullptr)) {
CHECK(IsExceptionPending()); // OOME.
return;
@@ -1602,25 +1596,27 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
// case in the compiler. We won't be able to invoke the constructor of the exception, so set
// the exception fields directly.
if (msg != nullptr) {
- exception->SetDetailMessage(msg_string.get());
+ exception->SetDetailMessage(down_cast<mirror::String*>(DecodeJObject(msg_string.get())));
}
if (cause.get() != nullptr) {
- exception->SetCause(cause.get());
+ exception->SetCause(down_cast<mirror::Throwable*>(DecodeJObject(cause.get())));
}
ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
throw_location.GetDexPc());
SetException(gc_safe_throw_location, exception.get());
} else {
- ArgArray args(shorty, strlen(shorty));
- args.Append(exception.get());
+ jvalue jv_args[2];
+ size_t i = 0;
+
if (msg != nullptr) {
- args.Append(msg_string.get());
+ jv_args[i].l = msg_string.get();
+ ++i;
}
if (cause.get() != nullptr) {
- args.Append(cause.get());
+ jv_args[i].l = cause.get();
+ ++i;
}
- JValue result;
- exception_init_method->Invoke(this, args.GetArray(), args.GetNumBytes(), &result, shorty);
+ InvokeWithJValues(soa, exception.get(), soa.EncodeMethod(exception_init_method), jv_args);
if (LIKELY(!IsExceptionPending())) {
ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
throw_location.GetDexPc());
diff --git a/runtime/thread.h b/runtime/thread.h
index 264a927..fdf976d 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -398,8 +398,9 @@ class PACKED(4) Thread {
// StackTraceElement[]. If output_array is NULL, a new array is created, otherwise as many
// frames as will fit are written into the given array. If stack_depth is non-NULL, it's updated
// with the number of valid frames in the returned array.
- static jobjectArray InternalStackTraceToStackTraceElementArray(JNIEnv* env, jobject internal,
- jobjectArray output_array = NULL, int* stack_depth = NULL);
+ static jobjectArray InternalStackTraceToStackTraceElementArray(const ScopedObjectAccess& soa,
+ jobject internal, jobjectArray output_array = nullptr, int* stack_depth = nullptr)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void VisitRoots(RootCallback* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 2e6ce4f..76b6f27 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -17,7 +17,6 @@
#include "transaction.h"
#include "common_runtime_test.h"
-#include "invoke_arg_array_builder.h"
#include "mirror/array-inl.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"