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