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