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