blob: d123754e47005aa52496a7071767bc7cc649d9a5 [file] [log] [blame]
Orion Hodsonc1d3bac2018-01-26 14:38:55 +00001/*
2 * Copyright (C) 2018 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_handles.h"
18
19#include "class_linker-inl.h"
Vladimir Markoa8bba7d2018-05-30 15:18:48 +010020#include "class_root.h"
Orion Hodsonc1d3bac2018-01-26 14:38:55 +000021#include "common_runtime_test.h"
22#include "handle_scope-inl.h"
23#include "jvalue-inl.h"
24#include "mirror/method_type.h"
25#include "mirror/object_array-inl.h"
26#include "reflection.h"
27#include "scoped_thread_state_change-inl.h"
28#include "thread-current-inl.h"
29
30namespace art {
31
32namespace {
33 bool IsClassCastException(ObjPtr<mirror::Throwable> throwable)
34 REQUIRES_SHARED(Locks::mutator_lock_) {
35 return throwable->GetClass()->DescriptorEquals("Ljava/lang/ClassCastException;");
36 }
37
38 bool IsNullPointerException(ObjPtr<mirror::Throwable> throwable)
39 REQUIRES_SHARED(Locks::mutator_lock_) {
40 return throwable->GetClass()->DescriptorEquals("Ljava/lang/NullPointerException;");
41 }
42
43 bool IsWrongMethodTypeException(ObjPtr<mirror::Throwable> throwable)
44 REQUIRES_SHARED(Locks::mutator_lock_) {
45 return throwable->GetClass()->DescriptorEquals("Ljava/lang/invoke/WrongMethodTypeException;");
46 }
47
48 static mirror::MethodType* CreateVoidMethodType(Thread* self,
49 Handle<mirror::Class> parameter_type)
50 REQUIRES_SHARED(Locks::mutator_lock_) {
51 ClassLinker* cl = Runtime::Current()->GetClassLinker();
52 StackHandleScope<2> hs(self);
Vladimir Markoa8bba7d2018-05-30 15:18:48 +010053 ObjPtr<mirror::Class> class_array_type = GetClassRoot<mirror::ObjectArray<mirror::Class>>(cl);
Orion Hodsonc1d3bac2018-01-26 14:38:55 +000054 auto parameter_types = hs.NewHandle(
55 mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, 1));
56 parameter_types->Set(0, parameter_type.Get());
Vladimir Markoa8bba7d2018-05-30 15:18:48 +010057 Handle<mirror::Class> void_class = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, cl));
Orion Hodsonc1d3bac2018-01-26 14:38:55 +000058 return mirror::MethodType::Create(self, void_class, parameter_types);
59 }
60
61 static bool TryConversion(Thread* self,
62 Handle<mirror::Class> from,
63 Handle<mirror::Class> to,
64 JValue* value)
65 REQUIRES_SHARED(Locks::mutator_lock_) {
66 StackHandleScope<2> hs(self);
67 Handle<mirror::MethodType> from_mt = hs.NewHandle(CreateVoidMethodType(self, from));
68 Handle<mirror::MethodType> to_mt = hs.NewHandle(CreateVoidMethodType(self, to));
69 return ConvertJValueCommon(from_mt, to_mt, from.Get(), to.Get(), value);
70 }
71} // namespace
72
73class MethodHandlesTest : public CommonRuntimeTest {};
74
75//
76// Primitive -> Primitive Conversions
77//
78
79TEST_F(MethodHandlesTest, SupportedPrimitiveWideningBI) {
80 ScopedObjectAccess soa(Thread::Current());
81 ClassLinker* cl = Runtime::Current()->GetClassLinker();
82 StackHandleScope<2> hs(soa.Self());
83 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('B'));
84 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
85 JValue value = JValue::FromPrimitive(static_cast<int8_t>(3));
86 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
87 ASSERT_EQ(3, value.GetI());
88 ASSERT_FALSE(soa.Self()->IsExceptionPending());
89}
90
91TEST_F(MethodHandlesTest, SupportedPrimitiveWideningCJ) {
92 ScopedObjectAccess soa(Thread::Current());
93 ClassLinker* cl = Runtime::Current()->GetClassLinker();
94 StackHandleScope<2> hs(soa.Self());
95 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('C'));
96 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J'));
97 uint16_t raw_value = 0x8000;
98 JValue value = JValue::FromPrimitive(raw_value);
99 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
100 ASSERT_FALSE(soa.Self()->IsExceptionPending());
101 ASSERT_EQ(static_cast<int64_t>(raw_value), value.GetJ());
102}
103
104TEST_F(MethodHandlesTest, SupportedPrimitiveWideningIF) {
105 ScopedObjectAccess soa(Thread::Current());
106 ClassLinker* cl = Runtime::Current()->GetClassLinker();
107 StackHandleScope<2> hs(soa.Self());
108 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
109 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('F'));
110 JValue value = JValue::FromPrimitive(-16);
111 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
112 ASSERT_FALSE(soa.Self()->IsExceptionPending());
113 ASSERT_FLOAT_EQ(-16.0f, value.GetF());
114}
115
116TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningBC) {
117 ScopedObjectAccess soa(Thread::Current());
118 ClassLinker* cl = Runtime::Current()->GetClassLinker();
119 StackHandleScope<2> hs(soa.Self());
120 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('B'));
121 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('C'));
122 JValue value;
123 value.SetB(0);
124 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
125 ASSERT_TRUE(soa.Self()->IsExceptionPending());
126 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
127 soa.Self()->ClearException();
128}
129
130TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningSC) {
131 ScopedObjectAccess soa(Thread::Current());
132 ClassLinker* cl = Runtime::Current()->GetClassLinker();
133 StackHandleScope<2> hs(soa.Self());
134 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('S'));
135 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('C'));
136 JValue value;
137 value.SetS(0x1234);
138 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
139 ASSERT_TRUE(soa.Self()->IsExceptionPending());
140 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
141 soa.Self()->ClearException();
142}
143
144TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningDJ) {
145 ScopedObjectAccess soa(Thread::Current());
146 ClassLinker* cl = Runtime::Current()->GetClassLinker();
147 StackHandleScope<2> hs(soa.Self());
148 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('D'));
149 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J'));
150 JValue value;
151 value.SetD(1e72);
152 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
153 ASSERT_TRUE(soa.Self()->IsExceptionPending());
154 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
155 soa.Self()->ClearException();
156}
157
158TEST_F(MethodHandlesTest, UnsupportedPrimitiveWideningZI) {
159 ScopedObjectAccess soa(Thread::Current());
160 ClassLinker* cl = Runtime::Current()->GetClassLinker();
161 StackHandleScope<2> hs(soa.Self());
162 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('Z'));
163 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
164 JValue value;
165 value.SetZ(true);
166 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
167 ASSERT_TRUE(soa.Self()->IsExceptionPending());
168 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
169 soa.Self()->ClearException();
170}
171
172//
173// Reference -> Reference Conversions
174//
175
176TEST_F(MethodHandlesTest, SupportedReferenceCast) {
177 ScopedObjectAccess soa(Thread::Current());
178 ClassLinker* cl = Runtime::Current()->GetClassLinker();
179 StackHandleScope<3> hs(soa.Self());
180 static const int32_t kInitialValue = 101;
181 JValue value = JValue::FromPrimitive(kInitialValue);
Vladimir Markobcf17522018-06-01 13:14:32 +0100182 Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
Orion Hodsonc1d3bac2018-01-26 14:38:55 +0000183 Handle<mirror::Class> from = hs.NewHandle(boxed_value->GetClass());
184 Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
185 value.SetL(boxed_value.Get());
186 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
187 ASSERT_FALSE(soa.Self()->IsExceptionPending());
188 JValue unboxed_value;
189 ASSERT_TRUE(UnboxPrimitiveForResult(value.GetL(), cl->FindPrimitiveClass('I'), &unboxed_value));
190 ASSERT_EQ(kInitialValue, unboxed_value.GetI());
191}
192
193TEST_F(MethodHandlesTest, UnsupportedReferenceCast) {
194 ScopedObjectAccess soa(Thread::Current());
195 ClassLinker* cl = Runtime::Current()->GetClassLinker();
196 StackHandleScope<3> hs(soa.Self());
197 JValue value = JValue::FromPrimitive(3.733e2);
Vladimir Markobcf17522018-06-01 13:14:32 +0100198 Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value));
Orion Hodsonc1d3bac2018-01-26 14:38:55 +0000199 Handle<mirror::Class> from = hs.NewHandle(boxed_value->GetClass());
200 Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
201 value.SetL(boxed_value.Get());
202 ASSERT_FALSE(soa.Self()->IsExceptionPending());
203 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
204 ASSERT_TRUE(soa.Self()->IsExceptionPending());
205 ASSERT_TRUE(IsClassCastException(soa.Self()->GetException()));
206 soa.Self()->ClearException();
207}
208
209//
210// Primitive -> Reference Conversions
211//
212
213TEST_F(MethodHandlesTest, SupportedPrimitiveConversionPrimitiveToBoxed) {
214 ScopedObjectAccess soa(Thread::Current());
215 ClassLinker* cl = Runtime::Current()->GetClassLinker();
216 StackHandleScope<2> hs(soa.Self());
217 const int32_t kInitialValue = 1;
218 JValue value = JValue::FromPrimitive(kInitialValue);
219 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
220 Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
221 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
222 ASSERT_FALSE(soa.Self()->IsExceptionPending());
223 JValue unboxed_to_value;
224 ASSERT_TRUE(UnboxPrimitiveForResult(value.GetL(), from.Get(), &unboxed_to_value));
225 ASSERT_EQ(kInitialValue, unboxed_to_value.GetI());
226}
227
228TEST_F(MethodHandlesTest, SupportedPrimitiveConversionPrimitiveToBoxedSuper) {
229 ScopedObjectAccess soa(Thread::Current());
230 ClassLinker* cl = Runtime::Current()->GetClassLinker();
231 StackHandleScope<2> hs(soa.Self());
232 const int32_t kInitialValue = 1;
233 JValue value = JValue::FromPrimitive(kInitialValue);
234 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
235 Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
236 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
237 ASSERT_FALSE(soa.Self()->IsExceptionPending());
238 JValue unboxed_to_value;
239 ASSERT_TRUE(UnboxPrimitiveForResult(value.GetL(), from.Get(), &unboxed_to_value));
240 ASSERT_EQ(kInitialValue, unboxed_to_value.GetI());
241}
242
243TEST_F(MethodHandlesTest, UnsupportedPrimitiveConversionNotBoxable) {
244 ScopedObjectAccess soa(Thread::Current());
245 ClassLinker* cl = Runtime::Current()->GetClassLinker();
246 StackHandleScope<2> hs(soa.Self());
247 const int32_t kInitialValue = 1;
248 JValue value = JValue::FromPrimitive(kInitialValue);
249 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
250 Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Runtime;"));
251 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
252 ASSERT_TRUE(soa.Self()->IsExceptionPending());
253 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
254 soa.Self()->ClearException();
255}
256
257TEST_F(MethodHandlesTest, UnsupportedPrimitiveConversionPrimitiveToBoxedWider) {
258 ScopedObjectAccess soa(Thread::Current());
259 ClassLinker* cl = Runtime::Current()->GetClassLinker();
260 StackHandleScope<2> hs(soa.Self());
261 const int32_t kInitialValue = 1;
262 JValue value = JValue::FromPrimitive(kInitialValue);
263 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
264 Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Long;"));
265 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
266 ASSERT_TRUE(soa.Self()->IsExceptionPending());
267 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
268 soa.Self()->ClearException();
269}
270
271TEST_F(MethodHandlesTest, UnsupportedPrimitiveConversionPrimitiveToBoxedNarrower) {
272 ScopedObjectAccess soa(Thread::Current());
273 ClassLinker* cl = Runtime::Current()->GetClassLinker();
274 StackHandleScope<2> hs(soa.Self());
275 const int32_t kInitialValue = 1;
276 JValue value = JValue::FromPrimitive(kInitialValue);
277 Handle<mirror::Class> from = hs.NewHandle(cl->FindPrimitiveClass('I'));
278 Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Byte;"));
279 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
280 ASSERT_TRUE(soa.Self()->IsExceptionPending());
281 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
282 soa.Self()->ClearException();
283}
284
285//
286// Reference -> Primitive Conversions
287//
288
289TEST_F(MethodHandlesTest, SupportedBoxedToPrimitiveConversion) {
290 ScopedObjectAccess soa(Thread::Current());
291 ClassLinker* cl = Runtime::Current()->GetClassLinker();
292 StackHandleScope<3> hs(soa.Self());
293 const int32_t kInitialValue = 101;
294 JValue value = JValue::FromPrimitive(kInitialValue);
Vladimir Markobcf17522018-06-01 13:14:32 +0100295 Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
Orion Hodsonc1d3bac2018-01-26 14:38:55 +0000296 Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
297 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
298 value.SetL(boxed_value.Get());
299 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
300 ASSERT_FALSE(soa.Self()->IsExceptionPending());
301 ASSERT_EQ(kInitialValue, value.GetI());
302}
303
304TEST_F(MethodHandlesTest, SupportedBoxedToWiderPrimitiveConversion) {
305 ScopedObjectAccess soa(Thread::Current());
306 ClassLinker* cl = Runtime::Current()->GetClassLinker();
307 StackHandleScope<3> hs(soa.Self());
308 static const int32_t kInitialValue = 101;
309 JValue value = JValue::FromPrimitive(kInitialValue);
Vladimir Markobcf17522018-06-01 13:14:32 +0100310 Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
Orion Hodsonc1d3bac2018-01-26 14:38:55 +0000311 Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
312 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J'));
313 value.SetL(boxed_value.Get());
314 ASSERT_TRUE(TryConversion(soa.Self(), from, to, &value));
315 ASSERT_EQ(kInitialValue, value.GetJ());
316}
317
318TEST_F(MethodHandlesTest, UnsupportedNullBoxedToPrimitiveConversion) {
319 ScopedObjectAccess soa(Thread::Current());
320 ClassLinker* cl = Runtime::Current()->GetClassLinker();
321 StackHandleScope<3> hs(soa.Self());
322 JValue value = JValue::FromPrimitive(101);
323 ScopedNullHandle<mirror::Object> boxed_value;
324 Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
325 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
326 value.SetL(boxed_value.Get());
327 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
328 ASSERT_TRUE(soa.Self()->IsExceptionPending());
329 ASSERT_TRUE(IsNullPointerException(soa.Self()->GetException()));
330 soa.Self()->ClearException();
331}
332
333TEST_F(MethodHandlesTest, UnsupportedNotBoxReferenceToPrimitiveConversion) {
334 ScopedObjectAccess soa(Thread::Current());
335 ClassLinker* cl = Runtime::Current()->GetClassLinker();
336 StackHandleScope<2> hs(soa.Self());
337 Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Class;"));
338 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
339 // Set value to be converted as some non-primitive type.
340 JValue value;
341 value.SetL(cl->FindPrimitiveClass('V'));
342 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
343 ASSERT_TRUE(soa.Self()->IsExceptionPending());
344 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
345 soa.Self()->ClearException();
346}
347
348TEST_F(MethodHandlesTest, UnsupportedBoxedToNarrowerPrimitiveConversionNoCast) {
349 ScopedObjectAccess soa(Thread::Current());
350 ClassLinker* cl = Runtime::Current()->GetClassLinker();
351 StackHandleScope<3> hs(soa.Self());
352 static const int32_t kInitialValue = 101;
353 JValue value = JValue::FromPrimitive(kInitialValue);
Vladimir Markobcf17522018-06-01 13:14:32 +0100354 Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
Orion Hodsonc1d3bac2018-01-26 14:38:55 +0000355 Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
356 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('S'));
357 value.SetL(boxed_value.Get());
358 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
359 ASSERT_TRUE(soa.Self()->IsExceptionPending());
360 ASSERT_TRUE(IsWrongMethodTypeException(soa.Self()->GetException()));
361 soa.Self()->ClearException();
362}
363
364TEST_F(MethodHandlesTest, UnsupportedBoxedToNarrowerPrimitiveConversionWithCast) {
365 ScopedObjectAccess soa(Thread::Current());
366 ClassLinker* cl = Runtime::Current()->GetClassLinker();
367 StackHandleScope<3> hs(soa.Self());
368 static const double kInitialValue = 1e77;
369 JValue value = JValue::FromPrimitive(kInitialValue);
Vladimir Markobcf17522018-06-01 13:14:32 +0100370 Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value));
Orion Hodsonc1d3bac2018-01-26 14:38:55 +0000371 Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
372 Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('F'));
373 value.SetL(boxed_value.Get());
374 ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
375 ASSERT_TRUE(soa.Self()->IsExceptionPending());
376 ASSERT_TRUE(IsClassCastException(soa.Self()->GetException()));
377 soa.Self()->ClearException();
378}
379
380} // namespace art