Home | History | Annotate | Download | only in runtime
      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 "common_runtime_test.h"
     21 #include "handle_scope-inl.h"
     22 #include "jvalue-inl.h"
     23 #include "mirror/method_type.h"
     24 #include "mirror/object_array-inl.h"
     25 #include "reflection.h"
     26 #include "scoped_thread_state_change-inl.h"
     27 #include "thread-current-inl.h"
     28 
     29 namespace art {
     30 
     31 namespace {
     32   bool IsClassCastException(ObjPtr<mirror::Throwable> throwable)
     33       REQUIRES_SHARED(Locks::mutator_lock_) {
     34     return throwable->GetClass()->DescriptorEquals("Ljava/lang/ClassCastException;");
     35   }
     36 
     37   bool IsNullPointerException(ObjPtr<mirror::Throwable> throwable)
     38       REQUIRES_SHARED(Locks::mutator_lock_) {
     39     return throwable->GetClass()->DescriptorEquals("Ljava/lang/NullPointerException;");
     40   }
     41 
     42   bool IsWrongMethodTypeException(ObjPtr<mirror::Throwable> throwable)
     43       REQUIRES_SHARED(Locks::mutator_lock_) {
     44     return throwable->GetClass()->DescriptorEquals("Ljava/lang/invoke/WrongMethodTypeException;");
     45   }
     46 
     47   static mirror::MethodType* CreateVoidMethodType(Thread* self,
     48                                                   Handle<mirror::Class> parameter_type)
     49         REQUIRES_SHARED(Locks::mutator_lock_) {
     50     ClassLinker* cl = Runtime::Current()->GetClassLinker();
     51     StackHandleScope<2> hs(self);
     52     ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
     53     ObjPtr<mirror::Class> class_array_type = cl->FindArrayClass(self, &class_type);
     54     auto parameter_types = hs.NewHandle(
     55         mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, 1));
     56     parameter_types->Set(0, parameter_type.Get());
     57     Handle<mirror::Class> void_class = hs.NewHandle(cl->FindPrimitiveClass('V'));
     58     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 
     73 class MethodHandlesTest : public CommonRuntimeTest {};
     74 
     75 //
     76 // Primitive -> Primitive Conversions
     77 //
     78 
     79 TEST_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 
     91 TEST_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 
    104 TEST_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 
    116 TEST_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 
    130 TEST_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 
    144 TEST_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 
    158 TEST_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 
    176 TEST_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);
    182   Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
    183   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 
    193 TEST_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);
    198   Handle<mirror::Object> boxed_value =
    199       hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value).Ptr());
    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);
    296   Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
    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);
    311   Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
    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);
    355   Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
    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);
    371   Handle<mirror::Object> boxed_value =
    372       hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value).Ptr());
    373   Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
    374   Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('F'));
    375   value.SetL(boxed_value.Get());
    376   ASSERT_FALSE(TryConversion(soa.Self(), from, to, &value));
    377   ASSERT_TRUE(soa.Self()->IsExceptionPending());
    378   ASSERT_TRUE(IsClassCastException(soa.Self()->GetException()));
    379   soa.Self()->ClearException();
    380 }
    381 
    382 }  // namespace art
    383