Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 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" |
Vladimir Marko | 5868ada | 2020-05-12 11:50:34 +0100 | [diff] [blame] | 20 | #include "class_root-inl.h" |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 21 | #include "common_runtime_test.h" |
| 22 | #include "handle_scope-inl.h" |
| 23 | #include "jvalue-inl.h" |
| 24 | #include "mirror/method_type.h" |
Andreas Gampe | 52ecb65 | 2018-10-24 15:18:21 -0700 | [diff] [blame] | 25 | #include "mirror/object_array-alloc-inl.h" |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 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 { |
| 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 Marko | 5aead70 | 2019-03-27 11:00:36 +0000 | [diff] [blame] | 49 | static ObjPtr<mirror::MethodType> CreateVoidMethodType(Thread* self, |
| 50 | Handle<mirror::Class> parameter_type) |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 51 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 52 | ClassLinker* cl = Runtime::Current()->GetClassLinker(); |
| 53 | StackHandleScope<2> hs(self); |
Vladimir Marko | a8bba7d | 2018-05-30 15:18:48 +0100 | [diff] [blame] | 54 | ObjPtr<mirror::Class> class_array_type = GetClassRoot<mirror::ObjectArray<mirror::Class>>(cl); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 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()); |
Vladimir Marko | a8bba7d | 2018-05-30 15:18:48 +0100 | [diff] [blame] | 58 | Handle<mirror::Class> void_class = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, cl)); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 59 | 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 | |
| 74 | class MethodHandlesTest : public CommonRuntimeTest {}; |
| 75 | |
| 76 | // |
| 77 | // Primitive -> Primitive Conversions |
| 78 | // |
| 79 | |
| 80 | TEST_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 | |
| 92 | TEST_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 | |
| 105 | TEST_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 | |
| 117 | TEST_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 | |
| 131 | TEST_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 | |
| 145 | TEST_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 | |
| 159 | TEST_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 | |
| 177 | TEST_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 Marko | bcf1752 | 2018-06-01 13:14:32 +0100 | [diff] [blame] | 183 | Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 184 | 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 | |
| 194 | TEST_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 Marko | bcf1752 | 2018-06-01 13:14:32 +0100 | [diff] [blame] | 199 | Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value)); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 200 | 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 | |
| 214 | TEST_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 | |
| 229 | TEST_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 | |
| 244 | TEST_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 | |
| 258 | TEST_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 | |
| 272 | TEST_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 | |
| 290 | TEST_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 Marko | bcf1752 | 2018-06-01 13:14:32 +0100 | [diff] [blame] | 296 | Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 297 | 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 | |
| 305 | TEST_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 Marko | bcf1752 | 2018-06-01 13:14:32 +0100 | [diff] [blame] | 311 | Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 312 | 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 | |
| 319 | TEST_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 | |
| 334 | TEST_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 | |
| 349 | TEST_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 Marko | bcf1752 | 2018-06-01 13:14:32 +0100 | [diff] [blame] | 355 | Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value)); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 356 | 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 | |
| 365 | TEST_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 Marko | bcf1752 | 2018-06-01 13:14:32 +0100 | [diff] [blame] | 371 | Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value)); |
Orion Hodson | c1d3bac | 2018-01-26 14:38:55 +0000 | [diff] [blame] | 372 | 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 |