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