summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2023-11-09 18:07:24 +0100
committer VladimĂ­r Marko <vmarko@google.com> 2023-11-20 10:38:07 +0000
commit4f2fcccce50f229cb2b00cc07c040473a59c120b (patch)
tree2f5a6d61b796b95ea63e60bea47cbf6d9be2c482
parent58310a99bcda9a45bc1e07f8d36f4c847f345457 (diff)
Do not create `MethodType` during early init...
... when interpreting `VarHandle` invoke-polymorphic. Use `VariableSizedHandleScope` as a raw method type that can be converted to the managed `MethodType` when desires but can also be used directly without the conversion. Add helper templates that facilitate using either the raw method type or the managed `MethodType` easily by templated code. Change `VarHandleInvokeAccessorWithConversions()` to avoid allocating the `MethodType` (avoid unnecessary work). Change `VarHandle` invokes in the interpreter to avoid allocating the `MethodType` when the `ThreadLocalRandom` is not initialized. This can avoid circular initialization when we reland https://android-review.googlesource.com/2769639 . Test: m test-art-host-gtest Test: testrunner.py --host --optimizing Bug: 297147201 Change-Id: I6a9372543a547366b28e5bf49d15d6140a75f770
-rw-r--r--runtime/class_linker.cc75
-rw-r--r--runtime/class_linker.h9
-rw-r--r--runtime/handle_scope-inl.h37
-rw-r--r--runtime/handle_scope.h5
-rw-r--r--runtime/handle_scope_test.cc10
-rw-r--r--runtime/interpreter/interpreter_common.cc87
-rw-r--r--runtime/method_handles-inl.h100
-rw-r--r--runtime/method_handles.cc17
-rw-r--r--runtime/method_handles.h73
-rw-r--r--runtime/method_handles_test.cc69
-rw-r--r--runtime/mirror/method_type-inl.h110
-rw-r--r--runtime/mirror/method_type.cc86
-rw-r--r--runtime/mirror/method_type.h97
-rw-r--r--runtime/mirror/var_handle.cc89
-rw-r--r--runtime/mirror/var_handle.h19
-rw-r--r--runtime/var_handles.cc102
-rw-r--r--runtime/var_handles.h13
-rw-r--r--runtime/well_known_classes.cc9
-rw-r--r--runtime/well_known_classes.h1
19 files changed, 700 insertions, 308 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3b0dda299e..42027cc223 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -118,7 +118,7 @@
#include "mirror/method.h"
#include "mirror/method_handle_impl.h"
#include "mirror/method_handles_lookup.h"
-#include "mirror/method_type.h"
+#include "mirror/method_type-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
#include "mirror/object.h"
@@ -10112,58 +10112,59 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(
return resolved;
}
- StackHandleScope<4> hs(self);
+ VariableSizedHandleScope raw_method_type_hs(self);
+ mirror::RawMethodType raw_method_type(&raw_method_type_hs);
+ if (!ResolveMethodType(self, proto_idx, dex_cache, class_loader, raw_method_type)) {
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
+
+ // The handle scope was filled with return type and paratemer types.
+ DCHECK_EQ(raw_method_type_hs.Size(),
+ dex_cache->GetDexFile()->GetShortyView(proto_idx).length());
+ ObjPtr<mirror::MethodType> method_type = mirror::MethodType::Create(self, raw_method_type);
+ if (method_type != nullptr) {
+ // Ensure all stores for the newly created MethodType are visible, before we attempt to place
+ // it in the DexCache (b/224733324).
+ std::atomic_thread_fence(std::memory_order_release);
+ dex_cache->SetResolvedMethodType(proto_idx, method_type.Ptr());
+ }
+ return method_type;
+}
+
+bool ClassLinker::ResolveMethodType(Thread* self,
+ dex::ProtoIndex proto_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ /*out*/ mirror::RawMethodType method_type) {
+ DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+ DCHECK(dex_cache != nullptr);
+ DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
// First resolve the return type.
const DexFile& dex_file = *dex_cache->GetDexFile();
const dex::ProtoId& proto_id = dex_file.GetProtoId(proto_idx);
- Handle<mirror::Class> return_type(hs.NewHandle(
- ResolveType(proto_id.return_type_idx_, dex_cache, class_loader)));
+ ObjPtr<mirror::Class> return_type =
+ ResolveType(proto_id.return_type_idx_, dex_cache, class_loader);
if (return_type == nullptr) {
DCHECK(self->IsExceptionPending());
- return nullptr;
+ return false;
}
+ method_type.SetRType(return_type);
// Then resolve the argument types.
- //
- // TODO: Is there a better way to figure out the number of method arguments
- // other than by looking at the shorty ?
- const size_t num_method_args = strlen(dex_file.StringDataByIdx(proto_id.shorty_idx_)) - 1;
-
- ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(this);
- Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle(
- mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_method_args)));
- if (method_params == nullptr) {
- DCHECK(self->IsExceptionPending());
- return nullptr;
- }
-
DexFileParameterIterator it(dex_file, proto_id);
- int32_t i = 0;
- MutableHandle<mirror::Class> param_class = hs.NewHandle<mirror::Class>(nullptr);
for (; it.HasNext(); it.Next()) {
const dex::TypeIndex type_idx = it.GetTypeIdx();
- param_class.Assign(ResolveType(type_idx, dex_cache, class_loader));
- if (param_class == nullptr) {
+ ObjPtr<mirror::Class> param_type = ResolveType(type_idx, dex_cache, class_loader);
+ if (param_type == nullptr) {
DCHECK(self->IsExceptionPending());
- return nullptr;
+ return false;
}
-
- method_params->Set(i++, param_class.Get());
+ method_type.AddPType(param_type);
}
- DCHECK(!it.HasNext());
-
- Handle<mirror::MethodType> type = hs.NewHandle(
- mirror::MethodType::Create(self, return_type, method_params));
- if (type != nullptr) {
- // Ensure all stores for the newly created MethodType are visible, before we attempt to place
- // it in the DexCache (b/224733324).
- std::atomic_thread_fence(std::memory_order_release);
- dex_cache->SetResolvedMethodType(proto_idx, type.Get());
- }
-
- return type.Get();
+ return true;
}
ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(Thread* self,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index e2ac03a58d..f1cede1756 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -97,6 +97,7 @@ class MethodHandle;
class MethodHandlesLookup;
class MethodType;
template<class T> class ObjectArray;
+class RawMethodType;
class StackTraceElement;
} // namespace mirror
@@ -448,6 +449,14 @@ class ClassLinker {
ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
+ bool ResolveMethodType(Thread* self,
+ dex::ProtoIndex proto_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ /*out*/ mirror::RawMethodType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+
// Resolve a method handle with a given ID from the DexFile. The
// result is not cached in the DexCache as the instance will only be
// used once in most circumstances.
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index 1874237174..e620e92e1f 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -19,6 +19,7 @@
#include "handle_scope.h"
+#include "base/casts.h"
#include "base/mutex.h"
#include "handle.h"
#include "handle_wrapper.h"
@@ -246,12 +247,12 @@ inline uint32_t VariableSizedHandleScope::Size() const {
DCHECK(cur != nullptr);
// The linked list of local scopes starts from the latest which may not be fully filled.
uint32_t sum = cur->Size();
- cur = reinterpret_cast<const LocalScopeType*>(cur->GetLink());
+ cur = down_cast<const LocalScopeType*>(cur->GetLink());
while (cur != nullptr) {
// All other local scopes are fully filled.
DCHECK_EQ(cur->Size(), kNumReferencesPerScope);
sum += kNumReferencesPerScope;
- cur = reinterpret_cast<const LocalScopeType*>(cur->GetLink());
+ cur = down_cast<const LocalScopeType*>(cur->GetLink());
}
return sum;
}
@@ -262,7 +263,7 @@ inline uint32_t VariableSizedHandleScope::Capacity() const {
while (cur != nullptr) {
DCHECK_EQ(cur->Capacity(), kNumReferencesPerScope);
sum += kNumReferencesPerScope;
- cur = reinterpret_cast<const LocalScopeType*>(cur->GetLink());
+ cur = down_cast<const LocalScopeType*>(cur->GetLink());
}
return sum;
}
@@ -274,17 +275,41 @@ inline bool VariableSizedHandleScope::Contains(StackReference<mirror::Object>* h
if (cur->Contains(handle_scope_entry)) {
return true;
}
- cur = reinterpret_cast<const LocalScopeType*>(cur->GetLink());
+ cur = down_cast<const LocalScopeType*>(cur->GetLink());
}
return false;
}
+template<class T>
+Handle<T> VariableSizedHandleScope::GetHandle(size_t i) {
+ // Handle the most common path efficiently.
+ if (i < kNumReferencesPerScope) {
+ return first_scope_.GetHandle<T>(i);
+ }
+
+ uint32_t size = Size();
+ DCHECK_GT(size, kNumReferencesPerScope);
+ DCHECK_LT(i, size);
+ LocalScopeType* cur = current_scope_;
+ DCHECK(cur != &first_scope_);
+ // The linked list of local scopes starts from the latest which may not be fully filled.
+ uint32_t cur_start = size - cur->Size();
+ DCHECK_EQ(cur_start % kNumReferencesPerScope, 0u); // All other local scopes are fully filled.
+ while (i < cur_start) {
+ cur = down_cast<LocalScopeType*>(cur->GetLink());
+ DCHECK(cur != nullptr);
+ DCHECK_EQ(cur->Size(), kNumReferencesPerScope);
+ cur_start -= kNumReferencesPerScope;
+ }
+ return cur->GetHandle<T>(i - cur_start);
+}
+
template <typename Visitor>
inline void VariableSizedHandleScope::VisitRoots(Visitor& visitor) {
LocalScopeType* cur = current_scope_;
while (cur != nullptr) {
cur->VisitRoots(visitor);
- cur = reinterpret_cast<LocalScopeType*>(cur->GetLink());
+ cur = down_cast<LocalScopeType*>(cur->GetLink());
}
}
@@ -293,7 +318,7 @@ inline void VariableSizedHandleScope::VisitHandles(Visitor& visitor) {
LocalScopeType* cur = current_scope_;
while (cur != nullptr) {
cur->VisitHandles(visitor);
- cur = reinterpret_cast<LocalScopeType*>(cur->GetLink());
+ cur = down_cast<LocalScopeType*>(cur->GetLink());
}
}
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 4cf6e5e6fe..791023085a 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -244,6 +244,11 @@ class VariableSizedHandleScope : public BaseHandleScope {
// The current capacity of this handle scope.
ALWAYS_INLINE uint32_t Capacity() const;
+ // Retrieve a `Handle<>` based on the slot index (in handle creation order).
+ // Note: This is linear in the size of the scope, so it should be used carefully.
+ template<class T>
+ ALWAYS_INLINE Handle<T> GetHandle(size_t i) REQUIRES_SHARED(Locks::mutator_lock_);
+
ALWAYS_INLINE bool Contains(StackReference<mirror::Object>* handle_scope_entry) const;
template <typename Visitor>
diff --git a/runtime/handle_scope_test.cc b/runtime/handle_scope_test.cc
index fe85f25d96..2e45bdae4a 100644
--- a/runtime/handle_scope_test.cc
+++ b/runtime/handle_scope_test.cc
@@ -97,15 +97,16 @@ class CollectVisitor {
TEST_F(HandleScopeTest, VariableSized) {
ScopedObjectAccess soa(Thread::Current());
VariableSizedHandleScope hs(soa.Self());
+ std::vector<Handle<mirror::Object>> handles;
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> c =
hs.NewHandle(class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;"));
+ handles.push_back(c);
// Test nested scopes.
StackHandleScope<1> inner(soa.Self());
inner.NewHandle(c->AllocObject(soa.Self()));
// Add a bunch of handles and make sure callbacks work.
static const size_t kNumHandles = 100;
- std::vector<Handle<mirror::Object>> handles;
for (size_t i = 0; i < kNumHandles; ++i) {
BaseHandleScope* base = &hs;
ObjPtr<mirror::Object> o = c->AllocObject(soa.Self());
@@ -116,7 +117,8 @@ TEST_F(HandleScopeTest, VariableSized) {
EXPECT_EQ(hs.Capacity(), base->Capacity());
}
// Add one null handle.
- hs.NewHandle<mirror::Object>(nullptr);
+ Handle<mirror::Object> null_handle = hs.NewHandle<mirror::Object>(nullptr);
+ handles.push_back(null_handle);
CollectVisitor visitor;
BaseHandleScope* base = &hs;
base->VisitRoots(visitor);
@@ -125,6 +127,10 @@ TEST_F(HandleScopeTest, VariableSized) {
for (StackReference<mirror::Object>* ref : visitor.visited) {
EXPECT_TRUE(base->Contains(ref));
}
+ // Test `VariableSizedHandleScope::GetHandle<.>()`.
+ for (size_t i = 0, size = handles.size(); i != size; ++i) {
+ EXPECT_EQ(handles[i].GetReference(), hs.GetHandle<mirror::Object>(i).GetReference());
+ }
}
} // namespace art
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 28da3da3f7..cafe3c4418 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -452,36 +452,55 @@ static bool DoVarHandleInvokeCommon(Thread* self,
return false;
}
- StackHandleScope<2> hs(self);
bool is_var_args = inst->HasVarArgs();
- const uint16_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc();
- ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
- Handle<mirror::MethodType> callsite_type(hs.NewHandle(
- class_linker->ResolveMethodType(self, dex::ProtoIndex(vRegH), shadow_frame.GetMethod())));
- // This implies we couldn't resolve one or more types in this VarHandle.
- if (UNLIKELY(callsite_type == nullptr)) {
- CHECK(self->IsExceptionPending());
- return false;
- }
-
const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc();
- ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC));
- Handle<mirror::VarHandle> var_handle(hs.NewHandle(ObjPtr<mirror::VarHandle>::DownCast(receiver)));
+ const uint16_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc();
+ StackHandleScope<4> hs(self);
+ Handle<mirror::VarHandle> var_handle = hs.NewHandle(
+ ObjPtr<mirror::VarHandle>::DownCast(shadow_frame.GetVRegReference(vRegC)));
+ ArtMethod* method = shadow_frame.GetMethod();
+ Handle<mirror::DexCache> dex_cache = hs.NewHandle(method->GetDexCache());
+ Handle<mirror::ClassLoader> class_loader = hs.NewHandle(method->GetClassLoader());
+ uint32_t var_args[Instruction::kMaxVarArgRegs];
+ std::optional<VarArgsInstructionOperands> var_args_operands(std::nullopt);
+ std::optional<RangeInstructionOperands> range_operands(std::nullopt);
+ InstructionOperands* all_operands;
if (is_var_args) {
- uint32_t args[Instruction::kMaxVarArgRegs];
- inst->GetVarArgs(args, inst_data);
- VarArgsInstructionOperands all_operands(args, inst->VRegA_45cc());
- NoReceiverInstructionOperands operands(&all_operands);
- return VarHandleInvokeAccessor(self,
- shadow_frame,
- var_handle,
- callsite_type,
- access_mode,
- &operands,
- result);
+ inst->GetVarArgs(var_args, inst_data);
+ var_args_operands.emplace(var_args, inst->VRegA_45cc());
+ all_operands = &var_args_operands.value();
} else {
- RangeInstructionOperands all_operands(inst->VRegC_4rcc(), inst->VRegA_4rcc());
- NoReceiverInstructionOperands operands(&all_operands);
+ range_operands.emplace(inst->VRegC_4rcc(), inst->VRegA_4rcc());
+ all_operands = &range_operands.value();
+ }
+ NoReceiverInstructionOperands operands(all_operands);
+ ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+
+ // TODO: The "`MethodType` caching" comment below refers to code implemented by
+ // https://android-review.googlesource.com/2768053 which has been reverted.
+ // Reland that CL and remove this part of the comment when doing so.
+ //
+ // If the `ThreadLocalRandom` class is not yet initialized, do the `VarHandle` operation
+ // without creating a managed `MethodType` object. This avoids a circular initialization
+ // issue when `ThreadLocalRandom.<clinit>` indirectly calls `AtomicLong.compareAndSet()`
+ // (implemented with a `VarHandle`) and the `MethodType` caching circles back to the
+ // `ThreadLocalRandom` with uninitialized `seeder` and throws NPE.
+ //
+ // Do a quick test for "visibly initialized" without a read barrier and, if that fails,
+ // do a thorough test for "initialized" (including load acquire) with the read barrier.
+ ArtField* field = WellKnownClasses::java_util_concurrent_ThreadLocalRandom_seeder;
+ if (UNLIKELY(!field->GetDeclaringClass<kWithoutReadBarrier>()->IsVisiblyInitialized()) &&
+ !field->GetDeclaringClass()->IsInitialized()) {
+ VariableSizedHandleScope callsite_type_hs(self);
+ mirror::RawMethodType callsite_type(&callsite_type_hs);
+ if (!class_linker->ResolveMethodType(self,
+ dex::ProtoIndex(vRegH),
+ dex_cache,
+ class_loader,
+ callsite_type)) {
+ CHECK(self->IsExceptionPending());
+ return false;
+ }
return VarHandleInvokeAccessor(self,
shadow_frame,
var_handle,
@@ -490,6 +509,22 @@ static bool DoVarHandleInvokeCommon(Thread* self,
&operands,
result);
}
+
+ Handle<mirror::MethodType> callsite_type(hs.NewHandle(
+ class_linker->ResolveMethodType(self, dex::ProtoIndex(vRegH), dex_cache, class_loader)));
+ // This implies we couldn't resolve one or more types in this VarHandle.
+ if (UNLIKELY(callsite_type == nullptr)) {
+ CHECK(self->IsExceptionPending());
+ return false;
+ }
+
+ return VarHandleInvokeAccessor(self,
+ shadow_frame,
+ var_handle,
+ callsite_type,
+ access_mode,
+ &operands,
+ result);
}
#define DO_VAR_HANDLE_ACCESSOR(_access_mode) \
diff --git a/runtime/method_handles-inl.h b/runtime/method_handles-inl.h
index 1a1507a06c..cdf9c837f8 100644
--- a/runtime/method_handles-inl.h
+++ b/runtime/method_handles-inl.h
@@ -105,20 +105,18 @@ class ShadowFrameSetter {
size_t arg_index_;
};
-inline bool ConvertArgumentValue(Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- ObjPtr<mirror::Class> from_class,
- ObjPtr<mirror::Class> to_class,
- JValue* value) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (from_class == to_class) {
+inline bool ConvertArgumentValue(const ThrowWrongMethodTypeFunction& throw_wmt,
+ ObjPtr<mirror::Class> from,
+ ObjPtr<mirror::Class> to,
+ /*inout*/ JValue* value) {
+ if (from == to) {
return true;
}
- // |value| may contain a bare heap pointer which is generally
- // |unsafe. ConvertJValueCommon() saves |value|, |from_class|, and
- // |to_class| to Handles where necessary to avoid issues if the heap
- // changes.
- if (ConvertJValueCommon(callsite_type, callee_type, from_class, to_class, value)) {
+ // `*value` may contain a bare heap pointer which is generally unsafe.
+ // `ConvertJValueCommon()` saves `*value`, `from`, and `to` to Handles
+ // where necessary to avoid issues if the heap changes.
+ if (ConvertJValueCommon(throw_wmt, from, to, value)) {
DCHECK(!Thread::Current()->IsExceptionPending());
return true;
} else {
@@ -128,31 +126,18 @@ inline bool ConvertArgumentValue(Handle<mirror::MethodType> callsite_type,
}
}
-inline bool ConvertArgumentValue(Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- int index,
- JValue* value) REQUIRES_SHARED(Locks::mutator_lock_) {
- return ConvertArgumentValue(callsite_type,
- callee_type,
- callsite_type->GetPTypes()->GetWithoutChecks(index),
- callee_type->GetPTypes()->GetWithoutChecks(index),
- value);
-}
-
-inline bool ConvertReturnValue(Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- JValue* value) REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> from_class(callee_type->GetRType());
- ObjPtr<mirror::Class> to_class(callsite_type->GetRType());
- if (to_class->GetPrimitiveType() == Primitive::kPrimVoid || from_class == to_class) {
+inline bool ConvertReturnValue(const ThrowWrongMethodTypeFunction& throw_wmt,
+ ObjPtr<mirror::Class> from,
+ ObjPtr<mirror::Class> to,
+ /*inout*/ JValue* value) {
+ if (to->GetPrimitiveType() == Primitive::kPrimVoid || from == to) {
return true;
}
- // |value| may contain a bare heap pointer which is generally
- // unsafe. ConvertJValueCommon() saves |value|, |from_class|, and
- // |to_class| to Handles where necessary to avoid issues if the heap
- // changes.
- if (ConvertJValueCommon(callsite_type, callee_type, from_class, to_class, value)) {
+ // `*value` may contain a bare heap pointer which is generally unsafe.
+ // `ConvertJValueCommon()` saves `*value`, `from`, and `to` to Handles
+ // where necessary to avoid issues if the heap changes.
+ if (ConvertJValueCommon(throw_wmt, from, to, value)) {
DCHECK(!Thread::Current()->IsExceptionPending());
return true;
} else {
@@ -162,21 +147,16 @@ inline bool ConvertReturnValue(Handle<mirror::MethodType> callsite_type,
}
}
-template <typename G, typename S>
-bool PerformConversions(Thread* self,
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
+template <typename FromPTypes, typename ToPTypes, typename G, typename S>
+bool PerformConversions(const ThrowWrongMethodTypeFunction& throw_wmt,
+ FromPTypes from_types,
+ ToPTypes to_types,
G* getter,
- S* setter,
- int32_t start_index,
- int32_t end_index) REQUIRES_SHARED(Locks::mutator_lock_) {
- StackHandleScope<2> hs(self);
- Handle<mirror::ObjectArray<mirror::Class>> from_types(hs.NewHandle(callsite_type->GetPTypes()));
- Handle<mirror::ObjectArray<mirror::Class>> to_types(hs.NewHandle(callee_type->GetPTypes()));
-
- for (int32_t i = start_index; i < end_index; ++i) {
- ObjPtr<mirror::Class> from(from_types->GetWithoutChecks(i));
- ObjPtr<mirror::Class> to(to_types->GetWithoutChecks(i - start_index));
+ S* setter) {
+ DCHECK_EQ(from_types.GetLength(), to_types.GetLength());
+ for (int32_t i = 0, length = to_types.GetLength(); i != length; ++i) {
+ ObjPtr<mirror::Class> from = from_types.Get(i);
+ ObjPtr<mirror::Class> to = to_types.Get(i);
const Primitive::Type from_type = from->GetPrimitiveType();
const Primitive::Type to_type = to->GetPrimitiveType();
if (from == to) {
@@ -199,8 +179,8 @@ bool PerformConversions(Thread* self,
value.SetI(getter->Get());
}
// Caveat emptor - ObjPtr's not guaranteed valid after this call.
- if (!ConvertArgumentValue(callsite_type, callee_type, from, to, &value)) {
- DCHECK(self->IsExceptionPending());
+ if (!ConvertArgumentValue(throw_wmt, from, to, &value)) {
+ DCHECK(Thread::Current()->IsExceptionPending());
return false;
}
if (Primitive::Is64BitType(to_type)) {
@@ -216,28 +196,6 @@ bool PerformConversions(Thread* self,
}
template <typename G, typename S>
-bool PerformConversions(Thread* self,
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- G* getter,
- S* setter,
- int32_t num_conversions)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- return PerformConversions(self, callsite_type, callee_type, getter, setter, 0, num_conversions);
-}
-
-template <typename G, typename S>
-bool PerformConversions(Thread* self,
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- G* getter,
- S* setter)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- int32_t num_conversions = callee_type->GetPTypes()->GetLength();
- return PerformConversions(self, callsite_type, callee_type, getter, setter, 0, num_conversions);
-}
-
-template <typename G, typename S>
bool CopyArguments(Thread* self,
Handle<mirror::MethodType> method_type,
G* getter,
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index c8c6ef9a73..a8f7a84e94 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -197,11 +197,10 @@ bool IsReturnTypeConvertible(ObjPtr<mirror::Class> from, ObjPtr<mirror::Class> t
}
bool ConvertJValueCommon(
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
+ const ThrowWrongMethodTypeFunction& throw_wmt,
ObjPtr<mirror::Class> from,
ObjPtr<mirror::Class> to,
- JValue* value) {
+ /*inout*/ JValue* value) {
// The reader maybe concerned about the safety of the heap object
// that may be in |value|. There is only one case where allocation
// is obviously needed and that's for boxing. However, in the case
@@ -226,7 +225,7 @@ bool ConvertJValueCommon(
if (IsPrimitiveType(from_type) && IsPrimitiveType(to_type)) {
// The source and target types are both primitives.
if (UNLIKELY(!ConvertPrimitiveValueNoThrow(from_type, to_type, src_value, value))) {
- ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+ throw_wmt();
return false;
}
return true;
@@ -258,18 +257,18 @@ bool ConvertJValueCommon(
if (LIKELY(boxed_from_class->IsSubClass(to))) {
type = from_type;
} else {
- ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+ throw_wmt();
return false;
}
}
if (UNLIKELY(from_type != type)) {
- ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+ throw_wmt();
return false;
}
if (UNLIKELY(!ConvertPrimitiveValueNoThrow(from_type, type, src_value, value))) {
- ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+ throw_wmt();
return false;
}
@@ -300,7 +299,7 @@ bool ConvertJValueCommon(
Primitive::Type unboxed_type;
JValue unboxed_value;
if (UNLIKELY(!GetUnboxedTypeAndValue(from_obj, &unboxed_type, &unboxed_value))) {
- ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+ throw_wmt();
return false;
}
@@ -311,7 +310,7 @@ bool ConvertJValueCommon(
ThrowClassCastException(from, to);
} else {
// CallSite is incompatible, e.g. Integer for a short.
- ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+ throw_wmt();
}
return false;
}
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 510b6e1678..d439d6238e 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -44,42 +44,47 @@ bool IsParameterTypeConvertible(ObjPtr<mirror::Class> from,
bool IsReturnTypeConvertible(ObjPtr<mirror::Class> from,
ObjPtr<mirror::Class> to);
-// Performs a conversion from type |from| to a distinct type |to| as
-// part of conversion of |caller_type| to |callee_type|. The value to
-// be converted is in |value|. Returns true on success and updates
-// |value| with the converted value, false otherwise.
-bool ConvertJValueCommon(Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
+// Interface for throwing `WrongMethodTypeException` by conversion functions.
+class ThrowWrongMethodTypeFunction {
+ public:
+ virtual void operator()() const REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+ protected:
+ ~ThrowWrongMethodTypeFunction() {}
+};
+
+// Performs a conversion from type `from` to a distinct type `to`.
+// The value to be converted is in `*value`. Returns true on success
+// and updates `*value` with the converted value, false otherwise.
+bool ConvertJValueCommon(const ThrowWrongMethodTypeFunction& throw_wmt,
ObjPtr<mirror::Class> from,
ObjPtr<mirror::Class> to,
- JValue* value)
+ /*inout*/ JValue* value)
REQUIRES_SHARED(Locks::mutator_lock_);
-// Converts the value of the argument at position |index| from type
-// expected by |callee_type| to type used by |callsite_type|. |value|
-// represents the value to be converted. Returns true on success and
-// updates |value|, false otherwise.
-ALWAYS_INLINE bool ConvertArgumentValue(Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- int index,
- JValue* value)
+// Converts the value of the argument from type `from` to type `to`.
+// `*value` represents the value to be converted. Returns true on success
+// and updates `*value`, false otherwise.
+ALWAYS_INLINE bool ConvertArgumentValue(const ThrowWrongMethodTypeFunction& throw_wmt,
+ ObjPtr<mirror::Class> from,
+ ObjPtr<mirror::Class> to,
+ /*inout*/ JValue* value)
REQUIRES_SHARED(Locks::mutator_lock_);
-// Converts the return value from return type yielded by
-// |callee_type| to the return type yielded by
-// |callsite_type|. |value| represents the value to be
-// converted. Returns true on success and updates |value|, false
-// otherwise.
-ALWAYS_INLINE bool ConvertReturnValue(Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- JValue* value)
+// Converts the return value from return type `from` to the return type `to`.
+// `*value` represents the value to be converted. Returns true on success and
+// updates `*value`, false otherwise.
+ALWAYS_INLINE bool ConvertReturnValue(const ThrowWrongMethodTypeFunction& throw_wmt,
+ ObjPtr<mirror::Class> from,
+ ObjPtr<mirror::Class> to,
+ /*inout*/ JValue* value)
REQUIRES_SHARED(Locks::mutator_lock_);
-// Perform argument conversions between |callsite_type| (the type of the
-// incoming arguments) and |callee_type| (the type of the method being
-// invoked). These include widening and narrowing conversions as well as
-// boxing and unboxing. Returns true on success, on false on failure. A
-// pending exception will always be set on failure.
+// Perform argument conversions between `from_types` (the types of the incoming
+// arguments) and `to_types` (the parameter types of the method being invoked).
+// These include widening and narrowing conversions as well as boxing and
+// unboxing. Returns true on success, false on failure. A pending exception
+// will always be set on failure.
//
// The values to be converted are read from an input source (of type G)
// that provides three methods :
@@ -119,14 +124,12 @@ ALWAYS_INLINE bool ConvertReturnValue(Handle<mirror::MethodType> callsite_type,
// TODO(narayan): If we find that the instantiations of this function take
// up too much space, we can make G / S abstract base classes that are
// overridden by concrete classes.
-template <typename G, typename S>
-bool PerformConversions(Thread* self,
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
+template <typename FromPTypes, typename ToPTypes, typename G, typename S>
+bool PerformConversions(const ThrowWrongMethodTypeFunction& throw_wmt,
+ FromPTypes from_types,
+ ToPTypes to_types,
G* getter,
- S* setter,
- int32_t start_index,
- int32_t end_index) REQUIRES_SHARED(Locks::mutator_lock_);
+ S* setter) REQUIRES_SHARED(Locks::mutator_lock_);
template <typename G, typename S>
bool CopyArguments(Thread* self,
diff --git a/runtime/method_handles_test.cc b/runtime/method_handles_test.cc
index 588f8612d0..d7740e3118 100644
--- a/runtime/method_handles_test.cc
+++ b/runtime/method_handles_test.cc
@@ -46,28 +46,15 @@ namespace {
return throwable->GetClass()->DescriptorEquals("Ljava/lang/invoke/WrongMethodTypeException;");
}
- static ObjPtr<mirror::MethodType> CreateVoidMethodType(Thread* self,
- Handle<mirror::Class> parameter_type)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- ClassLinker* cl = Runtime::Current()->GetClassLinker();
- StackHandleScope<2> hs(self);
- ObjPtr<mirror::Class> class_array_type = GetClassRoot<mirror::ObjectArray<mirror::Class>>(cl);
- auto parameter_types = hs.NewHandle(
- mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, 1));
- parameter_types->Set(0, parameter_type.Get());
- Handle<mirror::Class> void_class = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, cl));
- return mirror::MethodType::Create(self, void_class, parameter_types);
- }
-
- static bool TryConversion(Thread* self,
- Handle<mirror::Class> from,
- Handle<mirror::Class> to,
- JValue* value)
+ static bool TryConversion(Handle<mirror::Class> from, Handle<mirror::Class> to, JValue* value)
REQUIRES_SHARED(Locks::mutator_lock_) {
- StackHandleScope<2> hs(self);
- Handle<mirror::MethodType> from_mt = hs.NewHandle(CreateVoidMethodType(self, from));
- Handle<mirror::MethodType> to_mt = hs.NewHandle(CreateVoidMethodType(self, to));
- return ConvertJValueCommon(from_mt, to_mt, from.Get(), to.Get(), value);
+ class ThrowWrongMethodTypeFunctionImpl final : public ThrowWrongMethodTypeFunction {
+ void operator()() const override REQUIRES_SHARED(Locks::mutator_lock_) {
+ ThrowWrongMethodTypeException("<callee-descriptor>", "<callsite-descriptor>");
+ }
+ };
+ ThrowWrongMethodTypeFunctionImpl throw_wmt;
+ return ConvertJValueCommon(throw_wmt, from.Get(), to.Get(), value);
}
} // namespace
@@ -89,7 +76,7 @@ TEST_F(MethodHandlesTest, SupportedPrimitiveWideningBI) {
Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('B'));
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
JValue value = JValue::FromPrimitive(static_cast<int8_t>(3));
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_EQ(3, value.GetI());
ASSERT_FALSE(soa.Self()->IsExceptionPending());
}
@@ -102,7 +89,7 @@ TEST_F(MethodHandlesTest, SupportedPrimitiveWideningCJ) {
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J'));
uint16_t raw_value = 0x8000;
JValue value = JValue::FromPrimitive(raw_value);
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_FALSE(soa.Self()->IsExceptionPending());
ASSERT_EQ(static_cast<int64_t>(raw_value), value.GetJ());
}
@@ -114,7 +101,7 @@ TEST_F(MethodHandlesTest, SupportedPrimitiveWideningIF) {
Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('F'));
JValue value = JValue::FromPrimitive(-16);
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_FALSE(soa.Self()->IsExceptionPending());
ASSERT_FLOAT_EQ(-16.0f, value.GetF());
}
@@ -127,7 +114,7 @@ TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningBC) {
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('C'));
JValue value;
value.SetB(0);
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -141,7 +128,7 @@ TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningSC) {
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('C'));
JValue value;
value.SetS(0x1234);
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -155,7 +142,7 @@ TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningDJ) {
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J'));
JValue value;
value.SetD(1e72);
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -169,7 +156,7 @@ TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningZI) {
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
JValue value;
value.SetZ(true);
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -189,7 +176,7 @@ TEST_F(MethodHandlesTest, SupportedReferenceCast) {
Handle<mirror::Class> from = hs.NewHandle(boxed_value->GetClass());
Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
value.SetL(boxed_value.Get());
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_FALSE(soa.Self()->IsExceptionPending());
JValue unboxed_value;
ASSERT_TRUE(UnboxPrimitiveForResult(value.GetL(), cl->FindPrimitiveClass('I'), &unboxed_value));
@@ -206,7 +193,7 @@ TEST_F(MethodHandlesTest, UnsupportedReferenceCast) {
Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
value.SetL(boxed_value.Get());
ASSERT_FALSE(soa.Self()->IsExceptionPending());
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsClassCastException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -224,7 +211,7 @@ TEST_F(MethodHandlesTest, SupportedPrimitiveConversionPrimitiveToBoxed) {
JValue value = JValue::FromPrimitive(kInitialValue);
Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_FALSE(soa.Self()->IsExceptionPending());
JValue unboxed_to_value;
ASSERT_TRUE(UnboxPrimitiveForResult(value.GetL(), from.Get(), &unboxed_to_value));
@@ -239,7 +226,7 @@ TEST_F(MethodHandlesTest, SupportedPrimitiveConversionPrimitiveToBoxedSuper) {
JValue value = JValue::FromPrimitive(kInitialValue);
Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_FALSE(soa.Self()->IsExceptionPending());
JValue unboxed_to_value;
ASSERT_TRUE(UnboxPrimitiveForResult(value.GetL(), from.Get(), &unboxed_to_value));
@@ -254,7 +241,7 @@ TEST_F(MethodHandlesTest, UnsupportedPrimitiveConversionNotBoxable) {
JValue value = JValue::FromPrimitive(kInitialValue);
Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Runtime;"));
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -268,7 +255,7 @@ TEST_F(MethodHandlesTest, UnsupportedPrimitiveConversionPrimitiveToBoxedWider) {
JValue value = JValue::FromPrimitive(kInitialValue);
Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Long;"));
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -282,7 +269,7 @@ TEST_F(MethodHandlesTest, UnsupportedPrimitiveConversionPrimitiveToBoxedNarrower
JValue value = JValue::FromPrimitive(kInitialValue);
Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Byte;"));
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -302,7 +289,7 @@ TEST_F(MethodHandlesTest, SupportedBoxedToPrimitiveConversion) {
Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
value.SetL(boxed_value.Get());
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_FALSE(soa.Self()->IsExceptionPending());
ASSERT_EQ(kInitialValue, value.GetI());
}
@@ -317,7 +304,7 @@ TEST_F(MethodHandlesTest, SupportedBoxedToWiderPrimitiveConversion) {
Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J'));
value.SetL(boxed_value.Get());
- ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_TRUE(TryConversion(from, to, &value));
ASSERT_EQ(kInitialValue, value.GetJ());
}
@@ -330,7 +317,7 @@ TEST_F(MethodHandlesTest, UnsupportedNullBoxedToPrimitiveConversion) {
Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
value.SetL(boxed_value.Get());
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsNullPointerException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -345,7 +332,7 @@ TEST_F(MethodHandlesTest, UnsupportedNotBoxReferenceToPrimitiveConversion) {
// Set value to be converted as some non-primitive type.
JValue value;
value.SetL(cl->FindPrimitiveClass('V'));
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsClassCastException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -361,7 +348,7 @@ TEST_F(MethodHandlesTest, UnsupportedBoxedToNarrowerPrimitiveConversionNoCast) {
Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('S'));
value.SetL(boxed_value.Get());
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
soa.Self()->ClearException();
@@ -377,7 +364,7 @@ TEST_F(MethodHandlesTest, UnsupportedBoxedToNarrowerPrimitiveConversionWithCast)
Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('F'));
value.SetL(boxed_value.Get());
- ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
+ ASSERT_FALSE(TryConversion(from, to, &value));
ASSERT_TRUE(soa.Self()->IsExceptionPending());
ASSERT_TRUE(IsClassCastException(soa.Self()->GetException()));
soa.Self()->ClearException();
diff --git a/runtime/mirror/method_type-inl.h b/runtime/mirror/method_type-inl.h
index 86b8099f19..fca87fe944 100644
--- a/runtime/mirror/method_type-inl.h
+++ b/runtime/mirror/method_type-inl.h
@@ -19,11 +19,56 @@
#include "method_type.h"
+#include "base/casts.h"
+#include "handle_scope-inl.h"
#include "mirror/object-inl.h"
namespace art {
namespace mirror {
+inline RawMethodType::RawMethodType(VariableSizedHandleScope* hs)
+ : hs_(hs) {
+ DCHECK(hs != nullptr);
+}
+
+inline bool RawMethodType::IsValid() const {
+ return hs_->Size() != 0u;
+}
+
+inline void RawMethodType::SetRType(ObjPtr<mirror::Class> rtype) {
+ DCHECK(rtype != nullptr);
+ DCHECK_EQ(hs_->Size(), 0u);
+ hs_->NewHandle(rtype);
+ DCHECK_EQ(rtype, GetRType());
+}
+
+inline void RawMethodType::AddPType(ObjPtr<mirror::Class> ptype) {
+ DCHECK(ptype != nullptr);
+ DCHECK_NE(hs_->Size(), 0u);
+ hs_->NewHandle(ptype);
+ DCHECK_NE(GetNumberOfPTypes(), 0);
+ DCHECK_EQ(GetPType(GetNumberOfPTypes() - 1), ptype);
+}
+
+inline int32_t RawMethodType::GetNumberOfPTypes() const {
+ DCHECK_NE(hs_->Size(), 0u);
+ return dchecked_integral_cast<int32_t>(hs_->Size() - 1u);
+}
+
+inline ObjPtr<mirror::Class> RawMethodType::GetPType(int32_t i) const {
+ DCHECK_LT(i, GetNumberOfPTypes());
+ return hs_->GetHandle<mirror::Class>(i + 1).Get();
+}
+
+inline ObjPtr<mirror::Class> RawMethodType::GetRType() const {
+ return GetRTypeHandle().Get();
+}
+
+inline Handle<mirror::Class> RawMethodType::GetRTypeHandle() const {
+ DCHECK_NE(hs_->Size(), 0u);
+ return hs_->GetHandle<mirror::Class>(0u);
+}
+
inline ObjPtr<ObjectArray<Class>> MethodType::GetPTypes() {
return GetFieldObject<ObjectArray<Class>>(OFFSET_OF_OBJECT_MEMBER(MethodType, p_types_));
}
@@ -36,6 +81,71 @@ inline ObjPtr<Class> MethodType::GetRType() {
return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(MethodType, r_type_));
}
+template <typename PTypesType>
+inline MethodType::PTypesAccessor<PTypesType>::PTypesAccessor(PTypesType p_types)
+ : p_types_(p_types) {}
+
+template <typename PTypesType>
+inline int32_t MethodType::PTypesAccessor<PTypesType>::GetLength() const {
+ return p_types_->GetLength();
+}
+
+template <typename PTypesType>
+inline ObjPtr<mirror::Class> MethodType::PTypesAccessor<PTypesType>::Get(int32_t i) const {
+ DCHECK_LT(i, GetLength());
+ return p_types_->GetWithoutChecks(i);
+}
+
+inline MethodType::RawPTypesAccessor::RawPTypesAccessor(RawMethodType method_type)
+ : method_type_(method_type) {
+ DCHECK(method_type.IsValid());
+}
+
+inline int32_t MethodType::RawPTypesAccessor::GetLength() const {
+ return method_type_.GetNumberOfPTypes();
+}
+
+inline ObjPtr<mirror::Class> MethodType::RawPTypesAccessor::Get(int32_t i) const {
+ return method_type_.GetPType(i);
+}
+
+template <typename HandleScopeType>
+inline MethodType::HandlePTypesAccessor MethodType::NewHandlePTypes(
+ Handle<MethodType> method_type, HandleScopeType* hs) {
+ Handle<ObjectArray<mirror::Class>> p_types = hs->NewHandle(method_type->GetPTypes());
+ return HandlePTypesAccessor(p_types);
+}
+
+template <typename HandleScopeType>
+inline MethodType::RawPTypesAccessor MethodType::NewHandlePTypes(
+ RawMethodType method_type, [[maybe_unused]] HandleScopeType* hs) {
+ return RawPTypesAccessor(method_type);
+}
+
+inline MethodType::ObjPtrPTypesAccessor MethodType::GetPTypes(ObjPtr<MethodType> method_type) {
+ return ObjPtrPTypesAccessor(method_type->GetPTypes());
+}
+
+inline MethodType::ObjPtrPTypesAccessor MethodType::GetPTypes(Handle<MethodType> method_type) {
+ return GetPTypes(method_type.Get());
+}
+
+inline MethodType::RawPTypesAccessor MethodType::GetPTypes(RawMethodType method_type) {
+ return RawPTypesAccessor(method_type);
+}
+
+inline ObjPtr<mirror::Class> MethodType::GetRType(ObjPtr<MethodType> method_type) {
+ return method_type->GetRType();
+}
+
+inline ObjPtr<mirror::Class> MethodType::GetRType(Handle<MethodType> method_type) {
+ return GetRType(method_type.Get());
+}
+
+inline ObjPtr<mirror::Class> MethodType::GetRType(RawMethodType method_type) {
+ return method_type.GetRType();
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/method_type.cc b/runtime/mirror/method_type.cc
index ccc2b9d679..fc3dcb969a 100644
--- a/runtime/mirror/method_type.cc
+++ b/runtime/mirror/method_type.cc
@@ -18,6 +18,7 @@
#include "class-alloc-inl.h"
#include "class_root-inl.h"
+#include "handle_scope-inl.h"
#include "method_handles.h"
#include "obj_ptr-inl.h"
#include "object_array-alloc-inl.h"
@@ -36,7 +37,7 @@ ObjPtr<ObjectArray<Class>> AllocatePTypesArray(Thread* self, int count)
} // namespace
-ObjPtr<MethodType> MethodType::Create(Thread* const self,
+ObjPtr<MethodType> MethodType::Create(Thread* self,
Handle<Class> return_type,
Handle<ObjectArray<Class>> parameter_types) {
StackHandleScope<1> hs(self);
@@ -64,7 +65,29 @@ ObjPtr<MethodType> MethodType::Create(Thread* const self,
return mt.Get();
}
-ObjPtr<MethodType> MethodType::CloneWithoutLeadingParameter(Thread* const self,
+ObjPtr<MethodType> MethodType::Create(Thread* self, RawMethodType method_type) {
+ Handle<mirror::Class> return_type = method_type.GetRTypeHandle();
+ RawPTypesAccessor p_types(method_type);
+ int32_t num_method_args = p_types.GetLength();
+
+ // Create the argument types array.
+ StackHandleScope<1u> hs(self);
+ Handle<mirror::ObjectArray<mirror::Class>> method_params = hs.NewHandle(
+ mirror::ObjectArray<mirror::Class>::Alloc(
+ self, GetClassRoot<mirror::ObjectArray<mirror::Class>>(), num_method_args));
+ if (method_params == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
+
+ for (int32_t i = 0; i != num_method_args; ++i) {
+ method_params->Set(i, p_types.Get(i));
+ }
+
+ return Create(self, return_type, method_params);
+}
+
+ObjPtr<MethodType> MethodType::CloneWithoutLeadingParameter(Thread* self,
ObjPtr<MethodType> method_type) {
StackHandleScope<3> hs(self);
Handle<ObjectArray<Class>> src_ptypes = hs.NewHandle(method_type->GetPTypes());
@@ -104,15 +127,16 @@ ObjPtr<MethodType> MethodType::CollectTrailingArguments(Thread* self,
return Create(self, dst_rtype, dst_ptypes);
}
-size_t MethodType::NumberOfVRegs() {
- const ObjPtr<ObjectArray<Class>> p_types = GetPTypes();
- const int32_t p_types_length = p_types->GetLength();
+template <typename MethodTypeType>
+size_t NumberOfVRegsImpl(MethodTypeType method_type) REQUIRES_SHARED(Locks::mutator_lock_) {
+ auto p_types = MethodType::GetPTypes(method_type);
+ const int32_t p_types_length = p_types.GetLength();
// Initialize |num_vregs| with number of parameters and only increment it for
// types requiring a second vreg.
size_t num_vregs = static_cast<size_t>(p_types_length);
for (int32_t i = 0; i < p_types_length; ++i) {
- ObjPtr<Class> klass = p_types->GetWithoutChecks(i);
+ ObjPtr<Class> klass = p_types.Get(i);
if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
++num_vregs;
}
@@ -120,6 +144,24 @@ size_t MethodType::NumberOfVRegs() {
return num_vregs;
}
+size_t MethodType::NumberOfVRegs() {
+ return NumberOfVRegs(this);
+}
+
+size_t MethodType::NumberOfVRegs(ObjPtr<mirror::MethodType> method_type) {
+ DCHECK(method_type != nullptr);
+ return NumberOfVRegsImpl(method_type);
+}
+
+size_t MethodType::NumberOfVRegs(Handle<mirror::MethodType> method_type) {
+ return NumberOfVRegs(method_type.Get());
+}
+
+size_t MethodType::NumberOfVRegs(RawMethodType method_type) {
+ DCHECK(method_type.IsValid());
+ return NumberOfVRegsImpl(method_type);
+}
+
bool MethodType::IsExactMatch(ObjPtr<MethodType> target) {
const ObjPtr<ObjectArray<Class>> p_types = GetPTypes();
const int32_t params_length = p_types->GetLength();
@@ -212,24 +254,46 @@ bool MethodType::IsInPlaceConvertible(ObjPtr<MethodType> target) {
IsParameterInPlaceConvertible(target->GetRType(), GetRType());
}
-std::string MethodType::PrettyDescriptor() {
+template <typename MethodTypeType>
+std::string PrettyDescriptorImpl(MethodTypeType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ auto p_types = MethodType::GetPTypes(method_type);
+ ObjPtr<mirror::Class> r_type = MethodType::GetRType(method_type);
+
std::ostringstream ss;
ss << "(";
- const ObjPtr<ObjectArray<Class>> p_types = GetPTypes();
- const int32_t params_length = p_types->GetLength();
+ const int32_t params_length = p_types.GetLength();
for (int32_t i = 0; i < params_length; ++i) {
- ss << p_types->GetWithoutChecks(i)->PrettyDescriptor();
+ ss << p_types.Get(i)->PrettyDescriptor();
if (i != (params_length - 1)) {
ss << ", ";
}
}
ss << ")";
- ss << GetRType()->PrettyDescriptor();
+ ss << r_type->PrettyDescriptor();
return ss.str();
}
+std::string MethodType::PrettyDescriptor() {
+ return PrettyDescriptor(this);
+}
+
+std::string MethodType::PrettyDescriptor(ObjPtr<mirror::MethodType> method_type) {
+ DCHECK(method_type != nullptr);
+ return PrettyDescriptorImpl(method_type);
+}
+
+std::string MethodType::PrettyDescriptor(Handle<MethodType> method_type) {
+ return PrettyDescriptor(method_type.Get());
+}
+
+std::string MethodType::PrettyDescriptor(RawMethodType method_type) {
+ DCHECK(method_type.IsValid());
+ return PrettyDescriptorImpl(method_type);
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
index 19444bb6ce..bbb4a47f19 100644
--- a/runtime/mirror/method_type.h
+++ b/runtime/mirror/method_type.h
@@ -24,26 +24,52 @@
namespace art {
struct MethodTypeOffsets;
+class VariableSizedHandleScope;
namespace mirror {
+// We use a wrapped `VariableSizedHandleScope` as a raw method type without allocating a managed
+// object. It must contain the return type followed by argument types and no other handles.
+// The data is filled by calling `SetRType()` followed by `AddPType()` for each argument.
+class RawMethodType {
+ public:
+ explicit RawMethodType(VariableSizedHandleScope* hs);
+
+ bool IsValid() const;
+
+ void SetRType(ObjPtr<mirror::Class> rtype) REQUIRES_SHARED(Locks::mutator_lock_);
+ void AddPType(ObjPtr<mirror::Class> ptype) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ int32_t GetNumberOfPTypes() const REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> GetPType(int32_t i) const REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> GetRType() const REQUIRES_SHARED(Locks::mutator_lock_);
+ Handle<mirror::Class> GetRTypeHandle() const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ VariableSizedHandleScope* hs_;
+};
+
// C++ mirror of java.lang.invoke.MethodType
class MANAGED MethodType : public Object {
public:
MIRROR_CLASS("Ljava/lang/invoke/MethodType;");
- static ObjPtr<MethodType> Create(Thread* const self,
+ static ObjPtr<MethodType> Create(Thread* self,
Handle<Class> return_type,
Handle<ObjectArray<Class>> param_types)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
- static ObjPtr<MethodType> CloneWithoutLeadingParameter(Thread* const self,
+ // Create a `MethodType` from a `RawMethodType`.
+ static ObjPtr<MethodType> Create(Thread* self, RawMethodType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ static ObjPtr<MethodType> CloneWithoutLeadingParameter(Thread* self,
ObjPtr<MethodType> method_type)
REQUIRES_SHARED(Locks::mutator_lock_);
// Collects trailing parameter types into an array. Assumes caller
// has checked trailing arguments are all of the same type.
- static ObjPtr<MethodType> CollectTrailingArguments(Thread* const self,
+ static ObjPtr<MethodType> CollectTrailingArguments(Thread* self,
ObjPtr<MethodType> method_type,
ObjPtr<Class> collector_array_class,
int32_t start_index)
@@ -76,6 +102,71 @@ class MANAGED MethodType : public Object {
// exception messages and the like.
std::string PrettyDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
+ // The `PTypesType` is either `ObjPtr<>` or `Handle<>`.
+ template <typename PTypesType>
+ class PTypesAccessor {
+ public:
+ explicit PTypesAccessor(PTypesType p_types) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ int32_t GetLength() const REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> Get(int32_t i) const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ static_assert(std::is_same_v<PTypesType, ObjPtr<ObjectArray<Class>>> ||
+ std::is_same_v<PTypesType, Handle<ObjectArray<Class>>>);
+
+ const PTypesType p_types_;
+ };
+
+ using ObjPtrPTypesAccessor = PTypesAccessor<ObjPtr<ObjectArray<Class>>>;
+ using HandlePTypesAccessor = PTypesAccessor<Handle<ObjectArray<Class>>>;
+
+ class RawPTypesAccessor {
+ public:
+ explicit RawPTypesAccessor(RawMethodType method_type);
+
+ int32_t GetLength() const REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> Get(int32_t i) const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ RawMethodType method_type_;
+ };
+
+ template <typename HandleScopeType>
+ static HandlePTypesAccessor NewHandlePTypes(Handle<MethodType> method_type, HandleScopeType* hs)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ template <typename HandleScopeType>
+ static RawPTypesAccessor NewHandlePTypes(RawMethodType method_type, HandleScopeType* hs)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static ObjPtrPTypesAccessor GetPTypes(ObjPtr<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static ObjPtrPTypesAccessor GetPTypes(Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static RawPTypesAccessor GetPTypes(RawMethodType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static ObjPtr<mirror::Class> GetRType(ObjPtr<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static ObjPtr<mirror::Class> GetRType(Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static ObjPtr<mirror::Class> GetRType(RawMethodType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static size_t NumberOfVRegs(ObjPtr<mirror::MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static size_t NumberOfVRegs(Handle<mirror::MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static size_t NumberOfVRegs(RawMethodType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static std::string PrettyDescriptor(ObjPtr<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static std::string PrettyDescriptor(Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static std::string PrettyDescriptor(RawMethodType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
static MemberOffset FormOffset() {
return MemberOffset(OFFSETOF_MEMBER(MethodType, form_));
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index 2220f92e75..c923075099 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1335,13 +1335,13 @@ int32_t VarHandle::GetAccessModesBitMask() {
return GetField32(AccessModesBitMaskOffset());
}
-VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode access_mode,
- ObjPtr<MethodType> method_type) {
+template <typename MethodTypeType>
+VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessModeImpl(
+ AccessMode access_mode, ObjPtr<VarHandle> var_handle, MethodTypeType method_type) {
MatchKind match = MatchKind::kExact;
- ObjPtr<VarHandle> vh = this;
- ObjPtr<Class> var_type = vh->GetVarType();
- ObjPtr<Class> mt_rtype = method_type->GetRType();
+ ObjPtr<Class> var_type = var_handle->GetVarType();
+ ObjPtr<Class> mt_rtype = MethodType::GetRType(method_type);
ObjPtr<Class> void_type = WellKnownClasses::ToClass(WellKnownClasses::java_lang_Void);
AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
@@ -1358,28 +1358,28 @@ VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode acces
}
// Check the number of parameters matches.
- ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters];
+ ObjPtr<Class> vh_ptypes[kMaxAccessorParameters];
const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
access_mode_template,
var_type,
- GetCoordinateType0(),
- GetCoordinateType1());
- if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) {
+ var_handle->GetCoordinateType0(),
+ var_handle->GetCoordinateType1());
+ auto mt_ptypes = MethodType::GetPTypes(method_type);
+ if (vh_ptypes_count != mt_ptypes.GetLength()) {
return MatchKind::kNone;
}
// Check the parameter types are compatible.
- ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes();
for (int32_t i = 0; i < vh_ptypes_count; ++i) {
- if (vh_ptypes[i]->IsAssignableFrom(mt_ptypes->Get(i))) {
+ if (vh_ptypes[i]->IsAssignableFrom(mt_ptypes.Get(i))) {
continue;
}
- if (mt_ptypes->Get(i) == void_type && !vh_ptypes[i]->IsPrimitive()) {
+ if (mt_ptypes.Get(i) == void_type && !vh_ptypes[i]->IsPrimitive()) {
// The expected parameter is a reference and the parameter type from the call site is j.l.Void
// which means the value is null. It is always valid for a reference parameter to be null.
continue;
}
- if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) {
+ if (!IsParameterTypeConvertible(mt_ptypes.Get(i), vh_ptypes[i])) {
return MatchKind::kNone;
}
match = MatchKind::kWithConversions;
@@ -1387,39 +1387,46 @@ VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode acces
return match;
}
-ObjPtr<MethodType> VarHandle::GetMethodTypeForAccessMode(Thread* self,
- ObjPtr<VarHandle> var_handle,
- AccessMode access_mode) {
- // This is a static method as the var_handle might be moved by the GC during it's execution.
- AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
+VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(
+ AccessMode access_mode, ObjPtr<MethodType> method_type) {
+ return GetMethodTypeMatchForAccessModeImpl(access_mode, this, method_type);
+}
- StackHandleScope<3> hs(self);
- Handle<VarHandle> vh = hs.NewHandle(var_handle);
- Handle<Class> rtype = hs.NewHandle(GetReturnType(access_mode_template, vh->GetVarType()));
- const int32_t ptypes_count = GetNumberOfParameters(access_mode_template,
- vh->GetCoordinateType0(),
- vh->GetCoordinateType1());
- ObjPtr<Class> array_of_class = GetClassRoot<ObjectArray<Class>>();
- Handle<ObjectArray<Class>> ptypes =
- hs.NewHandle(ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, ptypes_count));
- if (ptypes == nullptr) {
- return nullptr;
- }
+VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(
+ AccessMode access_mode, Handle<MethodType> method_type) {
+ return GetMethodTypeMatchForAccessMode(access_mode, method_type.Get());
+}
- ObjPtr<Class> ptypes_array[VarHandle::kMaxAccessorParameters];
- BuildParameterArray(ptypes_array,
- access_mode_template,
- vh->GetVarType(),
- vh->GetCoordinateType0(),
- vh->GetCoordinateType1());
- for (int32_t i = 0; i < ptypes_count; ++i) {
- ptypes->Set(i, ptypes_array[i]);
- }
- return MethodType::Create(self, rtype, ptypes);
+VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(
+ AccessMode access_mode, RawMethodType method_type) {
+ return GetMethodTypeMatchForAccessModeImpl(access_mode, this, method_type);
}
ObjPtr<MethodType> VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode) {
- return GetMethodTypeForAccessMode(self, this, access_mode);
+ VariableSizedHandleScope method_type_hs(self);
+ RawMethodType method_type(&method_type_hs);
+ GetMethodTypeForAccessMode(access_mode, method_type);
+ return MethodType::Create(self, method_type);
+}
+
+void VarHandle::GetMethodTypeForAccessMode(AccessMode access_mode,
+ /*out*/ RawMethodType method_type) {
+ DCHECK(!method_type.IsValid());
+ AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
+
+ // Store return type in `method_type`.
+ method_type.SetRType(GetReturnType(access_mode_template, GetVarType()));
+
+ // Store parameter types in `method_type`.
+ ObjPtr<Class> ptypes_array[kMaxAccessorParameters];
+ int32_t ptypes_count = BuildParameterArray(ptypes_array,
+ access_mode_template,
+ GetVarType(),
+ GetCoordinateType0(),
+ GetCoordinateType1());
+ for (int32_t i = 0; i < ptypes_count; ++i) {
+ method_type.AddPType(ptypes_array[i]);
+ }
}
std::string VarHandle::PrettyDescriptorForAccessMode(AccessMode access_mode) {
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index 18e0c3a482..1419bd013f 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -43,6 +43,7 @@ class ShadowFrameGetter;
namespace mirror {
class MethodType;
+class RawMethodType;
class VarHandleTest;
// C++ mirror of java.lang.invoke.VarHandle
@@ -128,12 +129,21 @@ class MANAGED VarHandle : public Object {
// 'access_mode' and the provided 'method_type'.
MatchKind GetMethodTypeMatchForAccessMode(AccessMode access_mode, ObjPtr<MethodType> method_type)
REQUIRES_SHARED(Locks::mutator_lock_);
+ MatchKind GetMethodTypeMatchForAccessMode(AccessMode access_mode, Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ MatchKind GetMethodTypeMatchForAccessMode(AccessMode access_mode, RawMethodType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Allocates and returns the MethodType associated with the
// AccessMode. No check is made for whether the AccessMode is a
// supported operation so the MethodType can be used when raising a
// WrongMethodTypeException exception.
- ObjPtr<MethodType> GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode)
+ ObjPtr<MethodType> GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Overload that fills a handle scope with the return type and argument types
+ // instead of creating an actual `MethodType`.
+ void GetMethodTypeForAccessMode(AccessMode access_mode, /*out*/ RawMethodType method_type)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a string representing the descriptor of the MethodType associated with
@@ -193,10 +203,11 @@ class MANAGED VarHandle : public Object {
ObjPtr<Class> GetCoordinateType1() REQUIRES_SHARED(Locks::mutator_lock_);
int32_t GetAccessModesBitMask() REQUIRES_SHARED(Locks::mutator_lock_);
- static ObjPtr<MethodType> GetMethodTypeForAccessMode(Thread* self,
+ template <typename MethodTypeType>
+ static MatchKind GetMethodTypeMatchForAccessModeImpl(AccessMode access_mode,
ObjPtr<VarHandle> var_handle,
- AccessMode access_mode)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ MethodTypeType method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
HeapReference<mirror::Class> coordinate_type0_;
HeapReference<mirror::Class> coordinate_type1_;
diff --git a/runtime/var_handles.cc b/runtime/var_handles.cc
index 0c7e3bd476..884dd5c8a1 100644
--- a/runtime/var_handles.cc
+++ b/runtime/var_handles.cc
@@ -27,44 +27,80 @@ namespace art {
namespace {
+template <typename CallSiteType, typename CalleeType>
+class ThrowWrongMethodTypeFunctionImpl final : public ThrowWrongMethodTypeFunction {
+ public:
+ ThrowWrongMethodTypeFunctionImpl(CallSiteType callsite_type, CalleeType callee_type)
+ : callsite_type_(callsite_type),
+ callee_type_(callee_type) {}
+
+ ~ThrowWrongMethodTypeFunctionImpl() {}
+
+ void operator()() const override REQUIRES_SHARED(Locks::mutator_lock_) {
+ ThrowWrongMethodTypeException(mirror::MethodType::PrettyDescriptor(callee_type_),
+ mirror::MethodType::PrettyDescriptor(callsite_type_));
+ }
+
+ private:
+ CallSiteType callsite_type_;
+ CalleeType callee_type_;
+};
+
+template <typename CallSiteType>
bool VarHandleInvokeAccessorWithConversions(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::VarHandle> var_handle,
- Handle<mirror::MethodType> callsite_type,
- const mirror::VarHandle::AccessMode access_mode,
- const InstructionOperands* const operands,
+ CallSiteType callsite_type,
+ mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
- StackHandleScope<1> hs(self);
- Handle<mirror::MethodType> accessor_type(hs.NewHandle(
- var_handle->GetMethodTypeForAccessMode(self, access_mode)));
- const size_t num_vregs = accessor_type->NumberOfVRegs();
- const int num_params = accessor_type->GetPTypes()->GetLength();
+ // Use a raw method handle for `accessor_type`, avoid allocating a managed `MethodType`.
+ VariableSizedHandleScope accessor_type_hs(self);
+ mirror::RawMethodType accessor_type(&accessor_type_hs);
+ var_handle->GetMethodTypeForAccessMode(access_mode, accessor_type);
+ using HandleScopeType = std::conditional_t<
+ std::is_same_v<VariableSizedHandleScope*, CallSiteType>,
+ Thread*, // No handle scope needed, use `Thread*` that can be initialized from `self`.
+ StackHandleScope<3>>;
+ HandleScopeType hs(self);
+ ThrowWrongMethodTypeFunctionImpl throw_wmt(callsite_type, accessor_type);
+ auto from_types = mirror::MethodType::NewHandlePTypes(callsite_type, &hs);
+ auto to_types = mirror::MethodType::NewHandlePTypes(accessor_type, &hs);
+ const size_t num_vregs = mirror::MethodType::NumberOfVRegs(accessor_type);
ShadowFrameAllocaUniquePtr accessor_frame =
CREATE_SHADOW_FRAME(num_vregs, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
ShadowFrameGetter getter(shadow_frame, operands);
static const uint32_t kFirstDestinationReg = 0;
ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
- if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) {
+ if (!PerformConversions(throw_wmt, from_types, to_types, &getter, &setter)) {
+ DCHECK(self->IsExceptionPending());
return false;
}
RangeInstructionOperands accessor_operands(kFirstDestinationReg,
kFirstDestinationReg + num_vregs);
if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
+ DCHECK(self->IsExceptionPending());
return false;
}
- return ConvertReturnValue(callsite_type, accessor_type, result);
+ if (!ConvertReturnValue(throw_wmt,
+ mirror::MethodType::GetRType(accessor_type),
+ mirror::MethodType::GetRType(callsite_type),
+ result)) {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ return true;
}
-} // namespace
-
-bool VarHandleInvokeAccessor(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::VarHandle> var_handle,
- Handle<mirror::MethodType> callsite_type,
- const mirror::VarHandle::AccessMode access_mode,
- const InstructionOperands* const operands,
- JValue* result) {
+template <typename CallSiteType>
+bool VarHandleInvokeAccessorImpl(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ CallSiteType callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
if (var_handle.IsNull()) {
ThrowNullPointerExceptionFromDexPC();
return false;
@@ -76,7 +112,7 @@ bool VarHandleInvokeAccessor(Thread* self,
}
mirror::VarHandle::MatchKind match_kind =
- var_handle->GetMethodTypeMatchForAccessMode(access_mode, callsite_type.Get());
+ var_handle->GetMethodTypeMatchForAccessMode(access_mode, callsite_type);
if (LIKELY(match_kind == mirror::VarHandle::MatchKind::kExact)) {
return var_handle->Access(access_mode, &shadow_frame, operands, result);
} else if (match_kind == mirror::VarHandle::MatchKind::kWithConversions) {
@@ -90,9 +126,33 @@ bool VarHandleInvokeAccessor(Thread* self,
} else {
DCHECK_EQ(match_kind, mirror::VarHandle::MatchKind::kNone);
ThrowWrongMethodTypeException(var_handle->PrettyDescriptorForAccessMode(access_mode),
- callsite_type->PrettyDescriptor());
+ mirror::MethodType::PrettyDescriptor(callsite_type));
return false;
}
}
+} // namespace
+
+bool VarHandleInvokeAccessor(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result) {
+ return VarHandleInvokeAccessorImpl(
+ self, shadow_frame, var_handle, callsite_type, access_mode, operands, result);
+}
+
+bool VarHandleInvokeAccessor(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ mirror::RawMethodType callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result) {
+ return VarHandleInvokeAccessorImpl(
+ self, shadow_frame, var_handle, callsite_type, access_mode, operands, result);
+}
+
} // namespace art
diff --git a/runtime/var_handles.h b/runtime/var_handles.h
index 2ff8405f03..dd04a544b7 100644
--- a/runtime/var_handles.h
+++ b/runtime/var_handles.h
@@ -21,6 +21,10 @@
namespace art {
+namespace mirror {
+class RawMethodType;
+} // namespace mirror
+
bool VarHandleInvokeAccessor(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::VarHandle> var_handle,
@@ -30,6 +34,15 @@ bool VarHandleInvokeAccessor(Thread* self,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
+bool VarHandleInvokeAccessor(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ mirror::RawMethodType callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
} // namespace art
#endif // ART_RUNTIME_VAR_HANDLES_H_
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 7c77af9479..0569964f71 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -154,6 +154,7 @@ ArtField* WellKnownClasses::java_nio_ByteBuffer_hb;
ArtField* WellKnownClasses::java_nio_ByteBuffer_isReadOnly;
ArtField* WellKnownClasses::java_nio_ByteBuffer_offset;
ArtField* WellKnownClasses::java_util_Collections_EMPTY_LIST;
+ArtField* WellKnownClasses::java_util_concurrent_ThreadLocalRandom_seeder;
ArtField* WellKnownClasses::jdk_internal_math_FloatingDecimal_BinaryToASCIIBuffer_buffer;
ArtField* WellKnownClasses::jdk_internal_math_FloatingDecimal_ExceptionalBinaryToASCIIBuffer_image;
ArtField* WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT;
@@ -414,7 +415,7 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) {
java_lang_Long_value = CacheValueInBoxField(
class_linker, self, "Ljava/lang/Long;", "J");
- StackHandleScope<42u> hs(self);
+ StackHandleScope<43u> hs(self);
Handle<mirror::Class> d_s_bdcl =
hs.NewHandle(FindSystemClass(class_linker, self, "Ldalvik/system/BaseDexClassLoader;"));
Handle<mirror::Class> d_s_dlcl =
@@ -481,6 +482,8 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) {
hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/nio/DirectByteBuffer;"));
Handle<mirror::Class> j_u_c =
hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/util/Collections;"));
+ Handle<mirror::Class> j_u_c_tlr =
+ hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/util/concurrent/ThreadLocalRandom;"));
Handle<mirror::Class> j_u_f_c =
hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/util/function/Consumer;"));
Handle<mirror::Class> j_i_m_fd =
@@ -797,6 +800,9 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) {
java_util_Collections_EMPTY_LIST =
CacheField(j_u_c.Get(), /*is_static=*/ true, "EMPTY_LIST", "Ljava/util/List;");
+ java_util_concurrent_ThreadLocalRandom_seeder = CacheField(
+ j_u_c_tlr.Get(), /*is_static=*/ true, "seeder", "Ljava/util/concurrent/atomic/AtomicLong;");
+
jdk_internal_math_FloatingDecimal_BinaryToASCIIBuffer_buffer =
CacheField(j_i_m_fd_btab.Get(), /*is_static=*/ false, "buffer", "[C");
jdk_internal_math_FloatingDecimal_ExceptionalBinaryToASCIIBuffer_image = CacheField(
@@ -953,6 +959,7 @@ void WellKnownClasses::Clear() {
java_nio_ByteBuffer_isReadOnly = nullptr;
java_nio_ByteBuffer_offset = nullptr;
java_util_Collections_EMPTY_LIST = nullptr;
+ java_util_concurrent_ThreadLocalRandom_seeder = nullptr;
jdk_internal_math_FloatingDecimal_BinaryToASCIIBuffer_buffer = nullptr;
jdk_internal_math_FloatingDecimal_ExceptionalBinaryToASCIIBuffer_image = nullptr;
libcore_util_EmptyArray_STACK_TRACE_ELEMENT = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index f717030d82..203a061db8 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -199,6 +199,7 @@ struct WellKnownClasses {
static ArtField* java_nio_ByteBuffer_isReadOnly;
static ArtField* java_nio_ByteBuffer_offset;
static ArtField* java_util_Collections_EMPTY_LIST;
+ static ArtField* java_util_concurrent_ThreadLocalRandom_seeder;
static ArtField* jdk_internal_math_FloatingDecimal_BinaryToASCIIBuffer_buffer;
static ArtField* jdk_internal_math_FloatingDecimal_ExceptionalBinaryToASCIIBuffer_image;
static ArtField* libcore_util_EmptyArray_STACK_TRACE_ELEMENT;