xref: /aosp_15_r20/art/runtime/mirror/method_type_test.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.h"
18 
19 #include <string>
20 #include <vector>
21 
22 #include "class-inl.h"
23 #include "class_linker-inl.h"
24 #include "class_loader.h"
25 #include "class_root-inl.h"
26 #include "common_runtime_test.h"
27 #include "handle_scope-inl.h"
28 #include "object_array-alloc-inl.h"
29 #include "object_array-inl.h"
30 #include "scoped_thread_state_change-inl.h"
31 
32 namespace art HIDDEN {
33 namespace mirror {
34 
35 class MethodTypeTest : public CommonRuntimeTest {
36  protected:
37   ObjPtr<mirror::MethodType> CreateMethodType(const std::string& return_type,
38                                               const std::vector<std::string>& param_types);
39 };
40 
FullyQualifiedType(const std::string & shorthand)41 static std::string FullyQualifiedType(const std::string& shorthand) {
42   return "Ljava/lang/" + shorthand + ";";
43 }
44 
ExpandShortHand(const std::string & shorthand)45 std::string ExpandShortHand(const std::string& shorthand) {
46   if (shorthand.size() == 1) {
47     return shorthand;
48   } else if (shorthand.find('/') == std::string::npos) {
49     return FullyQualifiedType(shorthand);
50   } else {
51     return shorthand;
52   }
53 }
54 
CreateMethodType(const std::string & return_type,const std::vector<std::string> & param_types)55 ObjPtr<mirror::MethodType> MethodTypeTest::CreateMethodType(
56     const std::string& return_type,
57     const std::vector<std::string>& param_types) {
58   Runtime* const runtime = Runtime::Current();
59   Thread* const self = Thread::Current();
60 
61   ScopedObjectAccess soa(self);
62   StackHandleScope<2> hs(soa.Self());
63 
64   ScopedNullHandle<mirror::ClassLoader> boot_class_loader;
65   Handle<mirror::Class> return_clazz =
66       hs.NewHandle(FindClass(ExpandShortHand(return_type).c_str(), boot_class_loader));
67   CHECK(return_clazz != nullptr);
68 
69   ObjPtr<mirror::Class> class_array_type =
70       GetClassRoot<mirror::ObjectArray<mirror::Class>>(class_linker_);
71   Handle<mirror::ObjectArray<mirror::Class>> param_classes = hs.NewHandle(
72       mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, param_types.size()));
73   CHECK(param_classes != nullptr);
74   for (uint32_t i = 0; i < param_types.size(); ++i) {
75     ObjPtr<mirror::Class> param =
76         FindClass(ExpandShortHand(param_types[i]).c_str(), boot_class_loader);
77     CHECK(!param.IsNull());
78     param_classes->Set(i, param);
79   }
80 
81   return mirror::MethodType::Create(self, return_clazz, param_classes);
82 }
83 
84 
TEST_F(MethodTypeTest,IsExactMatch)85 TEST_F(MethodTypeTest, IsExactMatch) {
86   ScopedObjectAccess soa(Thread::Current());
87   {
88     StackHandleScope<2> hs(soa.Self());
89     Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
90     Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
91     ASSERT_TRUE(mt1->IsExactMatch(mt2.Get()));
92   }
93 
94   // Mismatched return type.
95   {
96     StackHandleScope<2> hs(soa.Self());
97     Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
98     Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("Integer", { "Integer" }));
99     ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
100   }
101 
102   // Mismatched param types.
103   {
104     StackHandleScope<2> hs(soa.Self());
105     Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
106     Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
107     ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
108   }
109 
110   // Wrong number of param types.
111   {
112     StackHandleScope<2> hs(soa.Self());
113     Handle<mirror::MethodType> mt1 = hs.NewHandle(
114         CreateMethodType("String", { "String", "String" }));
115     Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
116     ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
117   }
118 }
119 
TEST_F(MethodTypeTest,IsInPlaceConvertible)120 TEST_F(MethodTypeTest, IsInPlaceConvertible) {
121   ScopedObjectAccess soa(Thread::Current());
122 
123   // Call site has void return type, value is discarded.
124   {
125     StackHandleScope<2> hs(soa.Self());
126     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "Integer" }));
127     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("String", { "Integer" }));
128     ASSERT_TRUE(cs->IsInPlaceConvertible(mh.Get()));
129   }
130 
131   // MethodHandle has void return type, value is required
132   {
133     StackHandleScope<2> hs(soa.Self());
134     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("String", { "Integer" }));
135     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "Integer" }));
136     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
137   }
138 
139   // Assignable Reference Types
140   {
141     StackHandleScope<2> hs(soa.Self());
142     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("Object", { "Integer" }));
143     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("String", { "Object" }));
144     ASSERT_TRUE(cs->IsInPlaceConvertible(mh.Get()));
145   }
146 
147   // Not assignable Reference Types
148   {
149     StackHandleScope<2> hs(soa.Self());
150     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("Integer", { "Object" }));
151     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("Object", { "String" }));
152     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
153   }
154 
155   // Widenable primitives
156   {
157     StackHandleScope<2> hs(soa.Self());
158     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("I", { "B", "C", "S" }));
159     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("S", { "I", "I", "I" }));
160     ASSERT_TRUE(cs->IsInPlaceConvertible(mh.Get()));
161   }
162 
163   // Non-widenable primitives
164   {
165     StackHandleScope<2> hs(soa.Self());
166     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "Z" }));
167     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "I" }));
168     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
169   }
170   {
171     StackHandleScope<2> hs(soa.Self());
172     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "I" }));
173     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "Z" }));
174     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
175   }
176   {
177     StackHandleScope<2> hs(soa.Self());
178     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "S" }));
179     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "C" }));
180     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
181     ASSERT_FALSE(mh->IsInPlaceConvertible(cs.Get()));
182   }
183   {
184     StackHandleScope<2> hs(soa.Self());
185     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "C" }));
186     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "S" }));
187     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
188   }
189   {
190     StackHandleScope<2> hs(soa.Self());
191     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "I" }));
192     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "J" }));
193     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
194   }
195   {
196     StackHandleScope<2> hs(soa.Self());
197     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "F" }));
198     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "D" }));
199     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
200   }
201   {
202     StackHandleScope<2> hs(soa.Self());
203     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("V", { "D" }));
204     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("V", { "F" }));
205     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
206   }
207   {
208     StackHandleScope<2> hs(soa.Self());
209     Handle<mirror::MethodType> cs = hs.NewHandle(CreateMethodType("I", {}));
210     Handle<mirror::MethodType> mh = hs.NewHandle(CreateMethodType("Z", {}));
211     ASSERT_FALSE(cs->IsInPlaceConvertible(mh.Get()));
212   }
213 }
214 
215 }  // namespace mirror
216 }  // namespace art
217