summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ian Rogers <irogers@google.com> 2014-03-13 23:45:53 -0700
committer Ian Rogers <irogers@google.com> 2014-03-14 11:28:10 -0700
commit53b8b09fc80329539585dcf43657bc5f4ecefdff (patch)
treecac0f82fbb89bd907104e3fed6c36203e11a3de0
parent0dea9872082bc3e576ed6cefed86b0d6c0c45ffd (diff)
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 954ca996f3..99285cca73 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 df5afa223a..31acb69e31 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 852cef4662..9808869de9 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 2067a455af..a0ba6b9846 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 36dc1cb06c..184e5e9879 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 4a75152670..9c76a1480f 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 76b94fdca0..45904ffca0 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 589e0b042a..21eeafa9d9 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 6ecce4072c..0000000000
--- 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 6efff1a740..43db7eccb0 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 7b49d33625..42796dbe79 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 28408d25cf..7b29a9cd43 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 64829178dc..0b58af4c7c 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 0e2d921b7b..5c5eaa1ad4 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 7e02e29d3f..9975bf7c7d 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 8bf36e7e37..6daf9a951a 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 f6149fff44..636be5d2ab 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 2665a08ab0..de1b593c01 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 332a1305e0..d1a1105d0d 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 314cdb1a7e..cb8e6237ad 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 c06bf4c9b7..a22d7caa06 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 694f5e42ca..7e21d6c985 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 d29de3debe..0b8bb7bbe5 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 1266c41417..07d670d51a 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 4f81a0b95a..1b9ebe42a3 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 645d78cce8..744ac05dc6 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 96ad55fc0a..63801d3a3f 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 0bfa70f279..43105571c9 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 13c90af895..d2f9f25e55 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 0000000000..c14da5dc00
--- /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 1555bf2617..51edc85b10 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 d9e7986efe..ebc545250a 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 f4b9d9a7c4..f5ed08247f 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 264a927157..fdf976d2bd 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 2e6ce4fe71..76b6f270d9 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"