xref: /aosp_15_r20/art/runtime/mirror/method_type.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "method_type-inl.h"
18 
19 #include "class-alloc-inl.h"
20 #include "class_root-inl.h"
21 #include "handle_scope-inl.h"
22 #include "method_handles.h"
23 #include "obj_ptr-inl.h"
24 #include "object_array-alloc-inl.h"
25 #include "object_array-inl.h"
26 #include "well_known_classes.h"
27 
28 namespace art HIDDEN {
29 namespace mirror {
30 
31 namespace {
32 
AllocatePTypesArray(Thread * self,int count)33 ObjPtr<ObjectArray<Class>> AllocatePTypesArray(Thread* self, int count)
34     REQUIRES_SHARED(Locks::mutator_lock_) {
35   ObjPtr<Class> class_array_type = GetClassRoot<mirror::ObjectArray<mirror::Class>>();
36   return ObjectArray<Class>::Alloc(self, class_array_type, count);
37 }
38 
39 }  // namespace
40 
Create(Thread * self,Handle<Class> return_type,Handle<ObjectArray<Class>> parameter_types)41 ObjPtr<MethodType> MethodType::Create(Thread* self,
42                                       Handle<Class> return_type,
43                                       Handle<ObjectArray<Class>> parameter_types) {
44   ArtMethod* make_impl = WellKnownClasses::java_lang_invoke_MethodType_makeImpl;
45 
46   const bool is_trusted = true;
47   ObjPtr<MethodType> mt = ObjPtr<MethodType>::DownCast(make_impl->InvokeStatic<'L', 'L', 'L', 'Z'>(
48       self, return_type.Get(), parameter_types.Get(), is_trusted));
49 
50   if (self->IsExceptionPending()) {
51     return nullptr;
52   }
53 
54   return mt;
55 }
56 
Create(Thread * self,RawMethodType method_type)57 ObjPtr<MethodType> MethodType::Create(Thread* self, RawMethodType method_type) {
58   Handle<mirror::Class> return_type = method_type.GetRTypeHandle();
59   RawPTypesAccessor p_types(method_type);
60   int32_t num_method_args = p_types.GetLength();
61 
62   // Create the argument types array.
63   StackHandleScope<1u> hs(self);
64   Handle<mirror::ObjectArray<mirror::Class>> method_params = hs.NewHandle(
65       mirror::ObjectArray<mirror::Class>::Alloc(
66           self, GetClassRoot<mirror::ObjectArray<mirror::Class>>(), num_method_args));
67   if (method_params == nullptr) {
68     DCHECK(self->IsExceptionPending());
69     return nullptr;
70   }
71 
72   for (int32_t i = 0; i != num_method_args; ++i) {
73     method_params->Set(i, p_types.Get(i));
74   }
75 
76   return Create(self, return_type, method_params);
77 }
78 
CloneWithoutLeadingParameter(Thread * self,ObjPtr<MethodType> method_type)79 ObjPtr<MethodType> MethodType::CloneWithoutLeadingParameter(Thread* self,
80                                                             ObjPtr<MethodType> method_type) {
81   StackHandleScope<3> hs(self);
82   Handle<ObjectArray<Class>> src_ptypes = hs.NewHandle(method_type->GetPTypes());
83   Handle<Class> dst_rtype = hs.NewHandle(method_type->GetRType());
84   const int32_t dst_ptypes_count = method_type->GetNumberOfPTypes() - 1;
85   Handle<ObjectArray<Class>> dst_ptypes = hs.NewHandle(AllocatePTypesArray(self, dst_ptypes_count));
86   if (dst_ptypes.IsNull()) {
87     return nullptr;
88   }
89   for (int32_t i = 0; i < dst_ptypes_count; ++i) {
90     dst_ptypes->Set(i, src_ptypes->Get(i + 1));
91   }
92   return Create(self, dst_rtype, dst_ptypes);
93 }
94 
CollectTrailingArguments(Thread * self,ObjPtr<MethodType> method_type,ObjPtr<Class> collector_array_class,int32_t start_index)95 ObjPtr<MethodType> MethodType::CollectTrailingArguments(Thread* self,
96                                                         ObjPtr<MethodType> method_type,
97                                                         ObjPtr<Class> collector_array_class,
98                                                         int32_t start_index) {
99   int32_t ptypes_length = method_type->GetNumberOfPTypes();
100   if (start_index > ptypes_length) {
101     return method_type;
102   }
103 
104   StackHandleScope<4> hs(self);
105   Handle<Class> collector_class = hs.NewHandle(collector_array_class);
106   Handle<Class> dst_rtype = hs.NewHandle(method_type->GetRType());
107   Handle<ObjectArray<Class>> src_ptypes = hs.NewHandle(method_type->GetPTypes());
108   Handle<ObjectArray<Class>> dst_ptypes = hs.NewHandle(AllocatePTypesArray(self, start_index + 1));
109   if (dst_ptypes.IsNull()) {
110     return nullptr;
111   }
112   for (int32_t i = 0; i < start_index; ++i) {
113     dst_ptypes->Set(i, src_ptypes->Get(i));
114   }
115   dst_ptypes->Set(start_index, collector_class.Get());
116   return Create(self, dst_rtype, dst_ptypes);
117 }
118 
119 template <typename MethodTypeType>
NumberOfVRegsImpl(MethodTypeType method_type)120 size_t NumberOfVRegsImpl(MethodTypeType method_type) REQUIRES_SHARED(Locks::mutator_lock_) {
121   auto p_types = MethodType::GetPTypes(method_type);
122   const int32_t p_types_length = p_types.GetLength();
123 
124   // Initialize |num_vregs| with number of parameters and only increment it for
125   // types requiring a second vreg.
126   size_t num_vregs = static_cast<size_t>(p_types_length);
127   for (int32_t i = 0; i < p_types_length; ++i) {
128     ObjPtr<Class> klass = p_types.Get(i);
129     if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
130       ++num_vregs;
131     }
132   }
133   return num_vregs;
134 }
135 
NumberOfVRegs()136 size_t MethodType::NumberOfVRegs() {
137   return NumberOfVRegs(this);
138 }
139 
NumberOfVRegs(ObjPtr<mirror::MethodType> method_type)140 size_t MethodType::NumberOfVRegs(ObjPtr<mirror::MethodType> method_type) {
141   DCHECK(method_type != nullptr);
142   return NumberOfVRegsImpl(method_type);
143 }
144 
NumberOfVRegs(Handle<mirror::MethodType> method_type)145 size_t MethodType::NumberOfVRegs(Handle<mirror::MethodType> method_type) {
146   return NumberOfVRegs(method_type.Get());
147 }
148 
NumberOfVRegs(RawMethodType method_type)149 size_t MethodType::NumberOfVRegs(RawMethodType method_type) {
150   DCHECK(method_type.IsValid());
151   return NumberOfVRegsImpl(method_type);
152 }
153 
IsExactMatch(ObjPtr<MethodType> target)154 bool MethodType::IsExactMatch(ObjPtr<MethodType> target) {
155   const ObjPtr<ObjectArray<Class>> p_types = GetPTypes();
156   const int32_t params_length = p_types->GetLength();
157 
158   const ObjPtr<ObjectArray<Class>> target_p_types = target->GetPTypes();
159   if (params_length != target_p_types->GetLength()) {
160     return false;
161   }
162   for (int32_t i = 0; i < params_length; ++i) {
163     if (p_types->GetWithoutChecks(i) != target_p_types->GetWithoutChecks(i)) {
164       return false;
165     }
166   }
167   return GetRType() == target->GetRType();
168 }
169 
IsConvertible(ObjPtr<MethodType> target)170 bool MethodType::IsConvertible(ObjPtr<MethodType> target) {
171   const ObjPtr<ObjectArray<Class>> p_types = GetPTypes();
172   const int32_t params_length = p_types->GetLength();
173 
174   const ObjPtr<ObjectArray<Class>> target_p_types = target->GetPTypes();
175   if (params_length != target_p_types->GetLength()) {
176     return false;
177   }
178 
179   // Perform return check before invoking method handle otherwise side
180   // effects from the invocation may be observable before
181   // WrongMethodTypeException is raised.
182   if (!IsReturnTypeConvertible(target->GetRType(), GetRType())) {
183     return false;
184   }
185 
186   for (int32_t i = 0; i < params_length; ++i) {
187     if (!IsParameterTypeConvertible(p_types->GetWithoutChecks(i),
188                                     target_p_types->GetWithoutChecks(i))) {
189       return false;
190     }
191   }
192   return true;
193 }
194 
IsParameterInPlaceConvertible(ObjPtr<Class> from,ObjPtr<Class> to)195 static bool IsParameterInPlaceConvertible(ObjPtr<Class> from, ObjPtr<Class> to)
196     REQUIRES_SHARED(Locks::mutator_lock_) {
197   if (from == to) {
198     return true;
199   }
200 
201   if (from->IsPrimitive() != to->IsPrimitive()) {
202     return false;  // No in-place conversion from place conversion for box/unboxing.
203   }
204 
205   if (from->IsPrimitive()) {
206     // `from` and `to` are both primitives. The supported in-place conversions use a 32-bit
207     // interpreter representation and are a subset of permitted conversions for MethodHandles.
208     // Conversions are documented in JLS 11 S5.1.2 "Widening Primitive Conversion".
209     Primitive::Type src = from->GetPrimitiveType();
210     Primitive::Type dst = to->GetPrimitiveType();
211     switch (src) {
212       case Primitive::Type::kPrimByte:
213         return dst == Primitive::Type::kPrimShort || dst == Primitive::Type::kPrimInt;
214       case Primitive::Type::kPrimChar:
215         FALLTHROUGH_INTENDED;
216       case Primitive::Type::kPrimShort:
217         return dst == Primitive::Type::kPrimInt;
218       default:
219         return false;
220     }
221   }
222 
223   // `from` and `to` are both references, apply an assignability check.
224   return to->IsAssignableFrom(from);
225 }
226 
IsInPlaceConvertible(ObjPtr<MethodType> target)227 bool MethodType::IsInPlaceConvertible(ObjPtr<MethodType> target) {
228   const ObjPtr<ObjectArray<Class>> ptypes = GetPTypes();
229   const ObjPtr<ObjectArray<Class>> target_ptypes = target->GetPTypes();
230   const int32_t ptypes_length = ptypes->GetLength();
231   if (ptypes_length != target_ptypes->GetLength()) {
232     return false;
233   }
234 
235   for (int32_t i = 0; i < ptypes_length; ++i) {
236     if (!IsParameterInPlaceConvertible(ptypes->GetWithoutChecks(i),
237                                        target_ptypes->GetWithoutChecks(i))) {
238       return false;
239     }
240   }
241 
242   return GetRType()->IsPrimitiveVoid() ||
243          IsParameterInPlaceConvertible(target->GetRType(), GetRType());
244 }
245 
246 template <typename MethodTypeType>
PrettyDescriptorImpl(MethodTypeType method_type)247 std::string PrettyDescriptorImpl(MethodTypeType method_type)
248     REQUIRES_SHARED(Locks::mutator_lock_) {
249   auto p_types = MethodType::GetPTypes(method_type);
250   ObjPtr<mirror::Class> r_type = MethodType::GetRType(method_type);
251 
252   std::ostringstream ss;
253   ss << "(";
254 
255   const int32_t params_length = p_types.GetLength();
256   for (int32_t i = 0; i < params_length; ++i) {
257     ss << p_types.Get(i)->PrettyDescriptor();
258     if (i != (params_length - 1)) {
259       ss << ", ";
260     }
261   }
262 
263   ss << ")";
264   ss << r_type->PrettyDescriptor();
265 
266   return ss.str();
267 }
268 
PrettyDescriptor()269 std::string MethodType::PrettyDescriptor() {
270   return PrettyDescriptor(this);
271 }
272 
PrettyDescriptor(ObjPtr<mirror::MethodType> method_type)273 std::string MethodType::PrettyDescriptor(ObjPtr<mirror::MethodType> method_type) {
274   DCHECK(method_type != nullptr);
275   return PrettyDescriptorImpl(method_type);
276 }
277 
PrettyDescriptor(Handle<MethodType> method_type)278 std::string MethodType::PrettyDescriptor(Handle<MethodType> method_type) {
279   return PrettyDescriptor(method_type.Get());
280 }
281 
PrettyDescriptor(RawMethodType method_type)282 std::string MethodType::PrettyDescriptor(RawMethodType method_type) {
283   DCHECK(method_type.IsValid());
284   return PrettyDescriptorImpl(method_type);
285 }
286 
287 }  // namespace mirror
288 }  // namespace art
289