1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2024 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 "interpreter/unstarted_runtime_test.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "common_transaction_test.h"
21*795d594fSAndroid Build Coastguard Worker #include "dex/descriptors_names.h"
22*795d594fSAndroid Build Coastguard Worker #include "interpreter/interpreter_common.h"
23*795d594fSAndroid Build Coastguard Worker #include "handle.h"
24*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
28*795d594fSAndroid Build Coastguard Worker namespace interpreter {
29*795d594fSAndroid Build Coastguard Worker
30*795d594fSAndroid Build Coastguard Worker class UnstartedRuntimeTransactionTest : public CommonTransactionTestBase<UnstartedRuntimeTestBase> {
31*795d594fSAndroid Build Coastguard Worker protected:
32*795d594fSAndroid Build Coastguard Worker // Prepare for aborts. Aborts assume that the exception class is already resolved, as the
33*795d594fSAndroid Build Coastguard Worker // loading code doesn't work under transactions.
PrepareForAborts()34*795d594fSAndroid Build Coastguard Worker void PrepareForAborts() REQUIRES_SHARED(Locks::mutator_lock_) {
35*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> result =
36*795d594fSAndroid Build Coastguard Worker FindClass(kTransactionAbortErrorDescriptor, ScopedNullHandle<mirror::ClassLoader>());
37*795d594fSAndroid Build Coastguard Worker CHECK(result != nullptr);
38*795d594fSAndroid Build Coastguard Worker }
39*795d594fSAndroid Build Coastguard Worker };
40*795d594fSAndroid Build Coastguard Worker
TEST_F(UnstartedRuntimeTransactionTest,ToLowerUpper)41*795d594fSAndroid Build Coastguard Worker TEST_F(UnstartedRuntimeTransactionTest, ToLowerUpper) {
42*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
43*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
44*795d594fSAndroid Build Coastguard Worker UniqueDeoptShadowFramePtr tmp = CreateShadowFrame(10, nullptr, 0);
45*795d594fSAndroid Build Coastguard Worker
46*795d594fSAndroid Build Coastguard Worker PrepareForAborts();
47*795d594fSAndroid Build Coastguard Worker
48*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 128; i < 256; ++i) {
49*795d594fSAndroid Build Coastguard Worker {
50*795d594fSAndroid Build Coastguard Worker JValue result;
51*795d594fSAndroid Build Coastguard Worker tmp->SetVReg(0, static_cast<int32_t>(i));
52*795d594fSAndroid Build Coastguard Worker EnterTransactionMode();
53*795d594fSAndroid Build Coastguard Worker UnstartedCharacterToLowerCase(self, tmp.get(), &result, 0);
54*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsTransactionAborted());
55*795d594fSAndroid Build Coastguard Worker ExitTransactionMode();
56*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(self->IsExceptionPending());
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker {
59*795d594fSAndroid Build Coastguard Worker JValue result;
60*795d594fSAndroid Build Coastguard Worker tmp->SetVReg(0, static_cast<int32_t>(i));
61*795d594fSAndroid Build Coastguard Worker EnterTransactionMode();
62*795d594fSAndroid Build Coastguard Worker UnstartedCharacterToUpperCase(self, tmp.get(), &result, 0);
63*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsTransactionAborted());
64*795d594fSAndroid Build Coastguard Worker ExitTransactionMode();
65*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(self->IsExceptionPending());
66*795d594fSAndroid Build Coastguard Worker }
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker for (uint64_t i = 256; i <= std::numeric_limits<uint32_t>::max(); i <<= 1) {
69*795d594fSAndroid Build Coastguard Worker {
70*795d594fSAndroid Build Coastguard Worker JValue result;
71*795d594fSAndroid Build Coastguard Worker tmp->SetVReg(0, static_cast<int32_t>(i));
72*795d594fSAndroid Build Coastguard Worker EnterTransactionMode();
73*795d594fSAndroid Build Coastguard Worker UnstartedCharacterToLowerCase(self, tmp.get(), &result, 0);
74*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsTransactionAborted());
75*795d594fSAndroid Build Coastguard Worker ExitTransactionMode();
76*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(self->IsExceptionPending());
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker {
79*795d594fSAndroid Build Coastguard Worker JValue result;
80*795d594fSAndroid Build Coastguard Worker tmp->SetVReg(0, static_cast<int32_t>(i));
81*795d594fSAndroid Build Coastguard Worker EnterTransactionMode();
82*795d594fSAndroid Build Coastguard Worker UnstartedCharacterToUpperCase(self, tmp.get(), &result, 0);
83*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsTransactionAborted());
84*795d594fSAndroid Build Coastguard Worker ExitTransactionMode();
85*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(self->IsExceptionPending());
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker }
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker
TEST_F(UnstartedRuntimeTransactionTest,ThreadLocalGet)90*795d594fSAndroid Build Coastguard Worker TEST_F(UnstartedRuntimeTransactionTest, ThreadLocalGet) {
91*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
92*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
93*795d594fSAndroid Build Coastguard Worker UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, nullptr, 0);
94*795d594fSAndroid Build Coastguard Worker
95*795d594fSAndroid Build Coastguard Worker // Negative test.
96*795d594fSAndroid Build Coastguard Worker PrepareForAborts();
97*795d594fSAndroid Build Coastguard Worker
98*795d594fSAndroid Build Coastguard Worker // Just use a method in Class.
99*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> class_class = GetClassRoot<mirror::Class>();
100*795d594fSAndroid Build Coastguard Worker ArtMethod* caller_method =
101*795d594fSAndroid Build Coastguard Worker &*class_class->GetDeclaredMethods(class_linker_->GetImagePointerSize()).begin();
102*795d594fSAndroid Build Coastguard Worker UniqueDeoptShadowFramePtr caller_frame = CreateShadowFrame(10, caller_method, 0);
103*795d594fSAndroid Build Coastguard Worker shadow_frame->SetLink(caller_frame.get());
104*795d594fSAndroid Build Coastguard Worker
105*795d594fSAndroid Build Coastguard Worker JValue result;
106*795d594fSAndroid Build Coastguard Worker EnterTransactionMode();
107*795d594fSAndroid Build Coastguard Worker UnstartedThreadLocalGet(self, shadow_frame.get(), &result, 0);
108*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsTransactionAborted());
109*795d594fSAndroid Build Coastguard Worker ExitTransactionMode();
110*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(self->IsExceptionPending());
111*795d594fSAndroid Build Coastguard Worker self->ClearException();
112*795d594fSAndroid Build Coastguard Worker
113*795d594fSAndroid Build Coastguard Worker shadow_frame->ClearLink();
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker
TEST_F(UnstartedRuntimeTransactionTest,ThreadCurrentThread)116*795d594fSAndroid Build Coastguard Worker TEST_F(UnstartedRuntimeTransactionTest, ThreadCurrentThread) {
117*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
118*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
119*795d594fSAndroid Build Coastguard Worker UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, nullptr, 0);
120*795d594fSAndroid Build Coastguard Worker
121*795d594fSAndroid Build Coastguard Worker // Negative test. In general, currentThread should fail (as we should not leak a peer that will
122*795d594fSAndroid Build Coastguard Worker // be recreated at runtime).
123*795d594fSAndroid Build Coastguard Worker PrepareForAborts();
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker JValue result;
126*795d594fSAndroid Build Coastguard Worker EnterTransactionMode();
127*795d594fSAndroid Build Coastguard Worker UnstartedThreadCurrentThread(self, shadow_frame.get(), &result, 0);
128*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsTransactionAborted());
129*795d594fSAndroid Build Coastguard Worker ExitTransactionMode();
130*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(self->IsExceptionPending());
131*795d594fSAndroid Build Coastguard Worker self->ClearException();
132*795d594fSAndroid Build Coastguard Worker }
133*795d594fSAndroid Build Coastguard Worker
134*795d594fSAndroid Build Coastguard Worker class UnstartedClassForNameTransactionTest : public UnstartedRuntimeTransactionTest {
135*795d594fSAndroid Build Coastguard Worker public:
136*795d594fSAndroid Build Coastguard Worker template <typename T>
RunTest(T && runner,bool should_succeed)137*795d594fSAndroid Build Coastguard Worker void RunTest(T&& runner, bool should_succeed) {
138*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
139*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
140*795d594fSAndroid Build Coastguard Worker
141*795d594fSAndroid Build Coastguard Worker // Ensure that Class is initialized.
142*795d594fSAndroid Build Coastguard Worker CHECK(GetClassRoot<mirror::Class>()->IsInitialized());
143*795d594fSAndroid Build Coastguard Worker
144*795d594fSAndroid Build Coastguard Worker // A selection of classes from different core classpath components.
145*795d594fSAndroid Build Coastguard Worker constexpr const char* kTestCases[] = {
146*795d594fSAndroid Build Coastguard Worker "java.net.CookieManager", // From libcore.
147*795d594fSAndroid Build Coastguard Worker "dalvik.system.ClassExt", // From libart.
148*795d594fSAndroid Build Coastguard Worker };
149*795d594fSAndroid Build Coastguard Worker
150*795d594fSAndroid Build Coastguard Worker // For transaction mode, we cannot load any classes, as the pre-fence initialization of
151*795d594fSAndroid Build Coastguard Worker // classes isn't transactional. Load them ahead of time.
152*795d594fSAndroid Build Coastguard Worker for (const char* name : kTestCases) {
153*795d594fSAndroid Build Coastguard Worker FindClass(DotToDescriptor(name).c_str(), ScopedNullHandle<mirror::ClassLoader>());
154*795d594fSAndroid Build Coastguard Worker CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker
157*795d594fSAndroid Build Coastguard Worker if (!should_succeed) {
158*795d594fSAndroid Build Coastguard Worker // Negative test. In general, currentThread should fail (as we should not leak a peer that will
159*795d594fSAndroid Build Coastguard Worker // be recreated at runtime).
160*795d594fSAndroid Build Coastguard Worker PrepareForAborts();
161*795d594fSAndroid Build Coastguard Worker }
162*795d594fSAndroid Build Coastguard Worker
163*795d594fSAndroid Build Coastguard Worker JValue result;
164*795d594fSAndroid Build Coastguard Worker UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, nullptr, 0);
165*795d594fSAndroid Build Coastguard Worker
166*795d594fSAndroid Build Coastguard Worker for (const char* name : kTestCases) {
167*795d594fSAndroid Build Coastguard Worker EnterTransactionMode();
168*795d594fSAndroid Build Coastguard Worker
169*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::String> name_string = mirror::String::AllocFromModifiedUtf8(self, name);
170*795d594fSAndroid Build Coastguard Worker CHECK(name_string != nullptr);
171*795d594fSAndroid Build Coastguard Worker CHECK(!self->IsExceptionPending());
172*795d594fSAndroid Build Coastguard Worker
173*795d594fSAndroid Build Coastguard Worker runner(self, shadow_frame.get(), name_string, &result);
174*795d594fSAndroid Build Coastguard Worker
175*795d594fSAndroid Build Coastguard Worker if (should_succeed) {
176*795d594fSAndroid Build Coastguard Worker CHECK(!self->IsExceptionPending()) << name << " " << self->GetException()->Dump();
177*795d594fSAndroid Build Coastguard Worker CHECK(result.GetL() != nullptr) << name;
178*795d594fSAndroid Build Coastguard Worker } else {
179*795d594fSAndroid Build Coastguard Worker CHECK(self->IsExceptionPending()) << name;
180*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsTransactionAborted());
181*795d594fSAndroid Build Coastguard Worker self->ClearException();
182*795d594fSAndroid Build Coastguard Worker }
183*795d594fSAndroid Build Coastguard Worker
184*795d594fSAndroid Build Coastguard Worker ExitTransactionMode();
185*795d594fSAndroid Build Coastguard Worker }
186*795d594fSAndroid Build Coastguard Worker }
187*795d594fSAndroid Build Coastguard Worker };
188*795d594fSAndroid Build Coastguard Worker
TEST_F(UnstartedClassForNameTransactionTest,ClassForNameLongWithClassLoader)189*795d594fSAndroid Build Coastguard Worker TEST_F(UnstartedClassForNameTransactionTest, ClassForNameLongWithClassLoader) {
190*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
191*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
192*795d594fSAndroid Build Coastguard Worker
193*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> hs(self);
194*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> boot_cp = hs.NewHandle(GetBootClassLoader());
195*795d594fSAndroid Build Coastguard Worker
196*795d594fSAndroid Build Coastguard Worker auto runner = [&](Thread* th,
197*795d594fSAndroid Build Coastguard Worker ShadowFrame* shadow_frame,
198*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::String> name,
199*795d594fSAndroid Build Coastguard Worker JValue* result)
200*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
201*795d594fSAndroid Build Coastguard Worker shadow_frame->SetVRegReference(0, name);
202*795d594fSAndroid Build Coastguard Worker shadow_frame->SetVReg(1, 0);
203*795d594fSAndroid Build Coastguard Worker shadow_frame->SetVRegReference(2, boot_cp.Get());
204*795d594fSAndroid Build Coastguard Worker UnstartedClassForNameLong(th, shadow_frame, result, 0);
205*795d594fSAndroid Build Coastguard Worker };
206*795d594fSAndroid Build Coastguard Worker RunTest(runner, /*should_succeed=*/ true);
207*795d594fSAndroid Build Coastguard Worker }
208*795d594fSAndroid Build Coastguard Worker
TEST_F(UnstartedClassForNameTransactionTest,ClassForNameLongWithClassLoaderFail)209*795d594fSAndroid Build Coastguard Worker TEST_F(UnstartedClassForNameTransactionTest, ClassForNameLongWithClassLoaderFail) {
210*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
211*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
212*795d594fSAndroid Build Coastguard Worker
213*795d594fSAndroid Build Coastguard Worker StackHandleScope<2> hs(self);
214*795d594fSAndroid Build Coastguard Worker jobject path_jobj = class_linker_->CreatePathClassLoader(self, {});
215*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(path_jobj != nullptr);
216*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> path_cp = hs.NewHandle<mirror::ClassLoader>(
217*795d594fSAndroid Build Coastguard Worker self->DecodeJObject(path_jobj)->AsClassLoader());
218*795d594fSAndroid Build Coastguard Worker
219*795d594fSAndroid Build Coastguard Worker auto runner = [&](Thread* th,
220*795d594fSAndroid Build Coastguard Worker ShadowFrame* shadow_frame,
221*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::String> name,
222*795d594fSAndroid Build Coastguard Worker JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
223*795d594fSAndroid Build Coastguard Worker shadow_frame->SetVRegReference(0, name);
224*795d594fSAndroid Build Coastguard Worker shadow_frame->SetVReg(1, 0);
225*795d594fSAndroid Build Coastguard Worker shadow_frame->SetVRegReference(2, path_cp.Get());
226*795d594fSAndroid Build Coastguard Worker UnstartedClassForNameLong(th, shadow_frame, result, 0);
227*795d594fSAndroid Build Coastguard Worker };
228*795d594fSAndroid Build Coastguard Worker RunTest(runner, /*should_succeed=*/ false);
229*795d594fSAndroid Build Coastguard Worker }
230*795d594fSAndroid Build Coastguard Worker
231*795d594fSAndroid Build Coastguard Worker } // namespace interpreter
232*795d594fSAndroid Build Coastguard Worker } // namespace art
233