1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include <type_traits>
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "art_method-alloc-inl.h"
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include "base/casts.h"
22*795d594fSAndroid Build Coastguard Worker #include "common_runtime_test.h"
23*795d594fSAndroid Build Coastguard Worker #include "mirror/class-alloc-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker namespace {
29*795d594fSAndroid Build Coastguard Worker // Helper function to avoid `ASSERT_EQ` with floating point types.
ToIntegralType(float value)30*795d594fSAndroid Build Coastguard Worker int32_t ToIntegralType(float value) { return bit_cast<int32_t>(value); }
ToIntegralType(double value)31*795d594fSAndroid Build Coastguard Worker int64_t ToIntegralType(double value) { return bit_cast<int64_t>(value); }
ToIntegralType(T value)32*795d594fSAndroid Build Coastguard Worker template <typename T> T ToIntegralType(T value) { return value; }
33*795d594fSAndroid Build Coastguard Worker }
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker class ArtMethodTest : public CommonRuntimeTest {
36*795d594fSAndroid Build Coastguard Worker protected:
ArtMethodTest()37*795d594fSAndroid Build Coastguard Worker ArtMethodTest() {
38*795d594fSAndroid Build Coastguard Worker use_boot_image_ = true; // Make the Runtime creation cheaper.
39*795d594fSAndroid Build Coastguard Worker }
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker // Test primitive type boxing and unboxing.
42*795d594fSAndroid Build Coastguard Worker //
43*795d594fSAndroid Build Coastguard Worker // This provides basic checks that the translation of the compile-time shorty
44*795d594fSAndroid Build Coastguard Worker // to argument types and return type are correct and that values are passed
45*795d594fSAndroid Build Coastguard Worker // correctly for these single-argument calls (`ArtMethod::InvokeStatic()` with
46*795d594fSAndroid Build Coastguard Worker // primitive args and `ArtMethod::InvokeInstance()` with a reference arg).
47*795d594fSAndroid Build Coastguard Worker template <typename Type, char kPrimitive>
TestBoxUnbox(ArtMethod * value_of,const char * unbox_name,Type value)48*795d594fSAndroid Build Coastguard Worker void TestBoxUnbox(ArtMethod* value_of, const char* unbox_name, Type value) {
49*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
50*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
51*795d594fSAndroid Build Coastguard Worker ASSERT_STREQ(value_of->GetName(), "valueOf");
52*795d594fSAndroid Build Coastguard Worker std::string unbox_signature = std::string("()") + kPrimitive;
53*795d594fSAndroid Build Coastguard Worker ArtMethod* unbox_method = value_of->GetDeclaringClass()->FindClassMethod(
54*795d594fSAndroid Build Coastguard Worker unbox_name, unbox_signature, kRuntimePointerSize);
55*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(unbox_method != nullptr);
56*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(unbox_method->IsStatic());
57*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(value_of->GetDeclaringClass()->IsFinal());
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker static_assert(std::is_same_v<ObjPtr<mirror::Object> (ArtMethod::*)(Thread*, Type),
60*795d594fSAndroid Build Coastguard Worker decltype(&ArtMethod::InvokeStatic<'L', kPrimitive>)>);
61*795d594fSAndroid Build Coastguard Worker StackHandleScope<1u> hs(self);
62*795d594fSAndroid Build Coastguard Worker Handle<mirror::Object> boxed =
63*795d594fSAndroid Build Coastguard Worker hs.NewHandle(value_of->InvokeStatic<'L', kPrimitive>(self, value));
64*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(boxed != nullptr);
65*795d594fSAndroid Build Coastguard Worker ASSERT_OBJ_PTR_EQ(boxed->GetClass(), value_of->GetDeclaringClass());
66*795d594fSAndroid Build Coastguard Worker static_assert(std::is_same_v<Type (ArtMethod::*)(Thread*, ObjPtr<mirror::Object>),
67*795d594fSAndroid Build Coastguard Worker decltype(&ArtMethod::InvokeInstance<kPrimitive>)>);
68*795d594fSAndroid Build Coastguard Worker // Exercise both `InvokeInstance()` and `InvokeFinal()` (boxing classes are final).
69*795d594fSAndroid Build Coastguard Worker Type unboxed1 = unbox_method->InvokeInstance<kPrimitive>(self, boxed.Get());
70*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(ToIntegralType(value), ToIntegralType(unboxed1));
71*795d594fSAndroid Build Coastguard Worker Type unboxed2 = unbox_method->InvokeFinal<kPrimitive>(self, boxed.Get());
72*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(ToIntegralType(value), ToIntegralType(unboxed2));
73*795d594fSAndroid Build Coastguard Worker }
74*795d594fSAndroid Build Coastguard Worker };
75*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxBoolean)76*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxBoolean) {
77*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<bool, 'Z'>(WellKnownClasses::java_lang_Boolean_valueOf, "booleanValue", true);
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxByte)80*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxByte) {
81*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<int8_t, 'B'>(WellKnownClasses::java_lang_Byte_valueOf, "byteValue", -12);
82*795d594fSAndroid Build Coastguard Worker }
83*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxChar)84*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxChar) {
85*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<uint16_t, 'C'>(WellKnownClasses::java_lang_Character_valueOf, "charValue", 0xffaa);
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxShort)88*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxShort) {
89*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<int16_t, 'S'>(WellKnownClasses::java_lang_Short_valueOf, "shortValue", -0x1234);
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxInt)92*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxInt) {
93*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<int32_t, 'I'>(WellKnownClasses::java_lang_Integer_valueOf, "intValue", -0x12345678);
94*795d594fSAndroid Build Coastguard Worker }
95*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxLong)96*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxLong) {
97*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<int64_t, 'J'>(
98*795d594fSAndroid Build Coastguard Worker WellKnownClasses::java_lang_Long_valueOf, "longValue", UINT64_C(-0x1234567887654321));
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxFloat)101*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxFloat) {
102*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<float, 'F'>(WellKnownClasses::java_lang_Float_valueOf, "floatValue", -2.0f);
103*795d594fSAndroid Build Coastguard Worker }
104*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,BoxUnboxDouble)105*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, BoxUnboxDouble) {
106*795d594fSAndroid Build Coastguard Worker TestBoxUnbox<double, 'D'>(WellKnownClasses::java_lang_Double_valueOf, "doubleValue", 8.0);
107*795d594fSAndroid Build Coastguard Worker }
108*795d594fSAndroid Build Coastguard Worker
TEST_F(ArtMethodTest,ArrayList)109*795d594fSAndroid Build Coastguard Worker TEST_F(ArtMethodTest, ArrayList) {
110*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
111*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
112*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
113*795d594fSAndroid Build Coastguard Worker StackHandleScope<4u> hs(self);
114*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> list_class =
115*795d594fSAndroid Build Coastguard Worker hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/util/List;"));
116*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(list_class != nullptr);
117*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> abstract_list_class =
118*795d594fSAndroid Build Coastguard Worker hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/util/AbstractList;"));
119*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(abstract_list_class != nullptr);
120*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> array_list_class =
121*795d594fSAndroid Build Coastguard Worker hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/util/ArrayList;"));
122*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(array_list_class != nullptr);
123*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(abstract_list_class->Implements(list_class.Get()));
124*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(array_list_class->IsSubClass(abstract_list_class.Get()));
125*795d594fSAndroid Build Coastguard Worker
126*795d594fSAndroid Build Coastguard Worker ArtMethod* init = array_list_class->FindClassMethod("<init>", "()V", kRuntimePointerSize);
127*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(init != nullptr);
128*795d594fSAndroid Build Coastguard Worker ArtMethod* array_list_size_method =
129*795d594fSAndroid Build Coastguard Worker array_list_class->FindClassMethod("size", "()I", kRuntimePointerSize);
130*795d594fSAndroid Build Coastguard Worker DCHECK(array_list_size_method != nullptr);
131*795d594fSAndroid Build Coastguard Worker ArtMethod* abstract_list_size_method =
132*795d594fSAndroid Build Coastguard Worker abstract_list_class->FindClassMethod("size", "()I", kRuntimePointerSize);
133*795d594fSAndroid Build Coastguard Worker DCHECK(abstract_list_size_method != nullptr);
134*795d594fSAndroid Build Coastguard Worker ArtMethod* list_size_method =
135*795d594fSAndroid Build Coastguard Worker list_class->FindInterfaceMethod("size", "()I", kRuntimePointerSize);
136*795d594fSAndroid Build Coastguard Worker DCHECK(list_size_method != nullptr);
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker Handle<mirror::Object> array_list = init->NewObject<>(hs, self);
139*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(self->IsExceptionPending());
140*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(array_list != nullptr);
141*795d594fSAndroid Build Coastguard Worker
142*795d594fSAndroid Build Coastguard Worker // Invoke `ArrayList.size()` directly, with virtual dispatch from
143*795d594fSAndroid Build Coastguard Worker // `AbstractList.size()` and with interface dispatch from `List.size()`.
144*795d594fSAndroid Build Coastguard Worker int32_t size = array_list_size_method->InvokeInstance<'I'>(self, array_list.Get());
145*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(self->IsExceptionPending());
146*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(0, size);
147*795d594fSAndroid Build Coastguard Worker size = abstract_list_size_method->InvokeVirtual<'I'>(self, array_list.Get());
148*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(self->IsExceptionPending());
149*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(0, size);
150*795d594fSAndroid Build Coastguard Worker size = list_size_method->InvokeInterface<'I'>(self, array_list.Get());
151*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(self->IsExceptionPending());
152*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(0, size);
153*795d594fSAndroid Build Coastguard Worker
154*795d594fSAndroid Build Coastguard Worker // Try to invoke abstract method `AbstractList.size()` directly.
155*795d594fSAndroid Build Coastguard Worker abstract_list_size_method->InvokeInstance<'I'>(self, array_list.Get());
156*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(self->IsExceptionPending());
157*795d594fSAndroid Build Coastguard Worker self->ClearException();
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker
160*795d594fSAndroid Build Coastguard Worker } // namespace art
161