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