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