xref: /aosp_15_r20/art/runtime/interpreter/interpreter_switch_impl0.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2018 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 // The interpreter function takes considerable time to compile and link.
18*795d594fSAndroid Build Coastguard Worker // We compile the explicit definitions separately to speed up the build.
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "interpreter_switch_impl-inl.h"
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
23*795d594fSAndroid Build Coastguard Worker namespace interpreter {
24*795d594fSAndroid Build Coastguard Worker 
25*795d594fSAndroid Build Coastguard Worker // Define the helper class that does not do any transaction checks.
26*795d594fSAndroid Build Coastguard Worker class InactiveTransactionChecker {
27*795d594fSAndroid Build Coastguard Worker  public:
WriteConstraint(Thread * self,ObjPtr<mirror::Object> obj)28*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool WriteConstraint([[maybe_unused]] Thread* self,
29*795d594fSAndroid Build Coastguard Worker                                             [[maybe_unused]] ObjPtr<mirror::Object> obj)
30*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
31*795d594fSAndroid Build Coastguard Worker     return false;
32*795d594fSAndroid Build Coastguard Worker   }
33*795d594fSAndroid Build Coastguard Worker 
WriteValueConstraint(Thread * self,ObjPtr<mirror::Object> value)34*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool WriteValueConstraint([[maybe_unused]] Thread* self,
35*795d594fSAndroid Build Coastguard Worker                                                  [[maybe_unused]] ObjPtr<mirror::Object> value)
36*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
37*795d594fSAndroid Build Coastguard Worker     return false;
38*795d594fSAndroid Build Coastguard Worker   }
39*795d594fSAndroid Build Coastguard Worker 
ReadConstraint(Thread * self,ObjPtr<mirror::Object> value)40*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool ReadConstraint([[maybe_unused]] Thread* self,
41*795d594fSAndroid Build Coastguard Worker                                            [[maybe_unused]] ObjPtr<mirror::Object> value)
42*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
43*795d594fSAndroid Build Coastguard Worker     return false;
44*795d594fSAndroid Build Coastguard Worker   }
45*795d594fSAndroid Build Coastguard Worker 
AllocationConstraint(Thread * self,ObjPtr<mirror::Class> klass)46*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool AllocationConstraint([[maybe_unused]] Thread* self,
47*795d594fSAndroid Build Coastguard Worker                                                  [[maybe_unused]] ObjPtr<mirror::Class> klass)
48*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
49*795d594fSAndroid Build Coastguard Worker     return false;
50*795d594fSAndroid Build Coastguard Worker   }
51*795d594fSAndroid Build Coastguard Worker 
IsTransactionAborted()52*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static bool IsTransactionAborted() {
53*795d594fSAndroid Build Coastguard Worker     return false;
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker 
RecordArrayElementsInTransaction(ObjPtr<mirror::Object> array,int32_t count)56*795d594fSAndroid Build Coastguard Worker   static void RecordArrayElementsInTransaction([[maybe_unused]] ObjPtr<mirror::Object> array,
57*795d594fSAndroid Build Coastguard Worker                                                [[maybe_unused]] int32_t count)
58*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {}
59*795d594fSAndroid Build Coastguard Worker 
RecordNewObject(ObjPtr<mirror::Object> new_object)60*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static void RecordNewObject([[maybe_unused]] ObjPtr<mirror::Object> new_object)
61*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {}
62*795d594fSAndroid Build Coastguard Worker 
RecordNewArray(ObjPtr<mirror::Array> new_array)63*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE static void RecordNewArray([[maybe_unused]] ObjPtr<mirror::Array> new_array)
64*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {}
65*795d594fSAndroid Build Coastguard Worker };
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker class ActiveInstrumentationHandler {
68*795d594fSAndroid Build Coastguard Worker  public:
69*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE WARN_UNUSED
HasFieldReadListeners(const instrumentation::Instrumentation * instrumentation)70*795d594fSAndroid Build Coastguard Worker   static bool HasFieldReadListeners(const instrumentation::Instrumentation* instrumentation)
71*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
72*795d594fSAndroid Build Coastguard Worker     return instrumentation->HasFieldReadListeners();
73*795d594fSAndroid Build Coastguard Worker   }
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE WARN_UNUSED
HasFieldWriteListeners(const instrumentation::Instrumentation * instrumentation)76*795d594fSAndroid Build Coastguard Worker   static bool HasFieldWriteListeners(const instrumentation::Instrumentation* instrumentation)
77*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
78*795d594fSAndroid Build Coastguard Worker     return instrumentation->HasFieldWriteListeners();
79*795d594fSAndroid Build Coastguard Worker   }
80*795d594fSAndroid Build Coastguard Worker 
81*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE WARN_UNUSED
HasBranchListeners(const instrumentation::Instrumentation * instrumentation)82*795d594fSAndroid Build Coastguard Worker   static bool HasBranchListeners(const instrumentation::Instrumentation* instrumentation)
83*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
84*795d594fSAndroid Build Coastguard Worker     return instrumentation->HasBranchListeners();
85*795d594fSAndroid Build Coastguard Worker   }
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE WARN_UNUSED
NeedsDexPcEvents(ShadowFrame & shadow_frame)88*795d594fSAndroid Build Coastguard Worker   static bool NeedsDexPcEvents(ShadowFrame& shadow_frame)
89*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
90*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(shadow_frame.GetNotifyDexPcMoveEvents(),
91*795d594fSAndroid Build Coastguard Worker                    Runtime::Current()->GetInstrumentation()->HasDexPcListeners());
92*795d594fSAndroid Build Coastguard Worker     return shadow_frame.GetNotifyDexPcMoveEvents();
93*795d594fSAndroid Build Coastguard Worker   }
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE WARN_UNUSED
NeedsMethodExitEvent(const instrumentation::Instrumentation * instrumentation)96*795d594fSAndroid Build Coastguard Worker   static bool NeedsMethodExitEvent(const instrumentation::Instrumentation* instrumentation)
97*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
98*795d594fSAndroid Build Coastguard Worker     return interpreter::NeedsMethodExitEvent(instrumentation);
99*795d594fSAndroid Build Coastguard Worker   }
100*795d594fSAndroid Build Coastguard Worker 
101*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE WARN_UNUSED
GetForcePopFrame(ShadowFrame & shadow_frame)102*795d594fSAndroid Build Coastguard Worker   static bool GetForcePopFrame(ShadowFrame& shadow_frame) {
103*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(shadow_frame.GetForcePopFrame(),
104*795d594fSAndroid Build Coastguard Worker                    Runtime::Current()->AreNonStandardExitsEnabled());
105*795d594fSAndroid Build Coastguard Worker     return shadow_frame.GetForcePopFrame();
106*795d594fSAndroid Build Coastguard Worker   }
107*795d594fSAndroid Build Coastguard Worker 
108*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE
Branch(Thread * self,ArtMethod * method,uint32_t dex_pc,int32_t dex_pc_offset,const instrumentation::Instrumentation * instrumentation)109*795d594fSAndroid Build Coastguard Worker   static void Branch(Thread* self,
110*795d594fSAndroid Build Coastguard Worker                      ArtMethod* method,
111*795d594fSAndroid Build Coastguard Worker                      uint32_t dex_pc,
112*795d594fSAndroid Build Coastguard Worker                      int32_t dex_pc_offset,
113*795d594fSAndroid Build Coastguard Worker                      const instrumentation::Instrumentation* instrumentation)
114*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
115*795d594fSAndroid Build Coastguard Worker     instrumentation->Branch(self, method, dex_pc, dex_pc_offset);
116*795d594fSAndroid Build Coastguard Worker   }
117*795d594fSAndroid Build Coastguard Worker 
ExceptionHandledEvent(Thread * self,bool is_move_exception,const instrumentation::Instrumentation * instrumentation)118*795d594fSAndroid Build Coastguard Worker   static bool ExceptionHandledEvent(Thread* self,
119*795d594fSAndroid Build Coastguard Worker                                     bool is_move_exception,
120*795d594fSAndroid Build Coastguard Worker                                     const instrumentation::Instrumentation* instrumentation)
121*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
122*795d594fSAndroid Build Coastguard Worker     StackHandleScope<1> hs(self);
123*795d594fSAndroid Build Coastguard Worker     Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException()));
124*795d594fSAndroid Build Coastguard Worker     // Clear any exception while reporting the ExceptionHandled event. We should not run the handler
125*795d594fSAndroid Build Coastguard Worker     // with an exception set.
126*795d594fSAndroid Build Coastguard Worker     self->ClearException();
127*795d594fSAndroid Build Coastguard Worker     instrumentation->ExceptionHandledEvent(self, exception.Get());
128*795d594fSAndroid Build Coastguard Worker     // If there is an exception then that is the exception thrown by the exception handled event
129*795d594fSAndroid Build Coastguard Worker     // and we should just handle the new exception. The earlier exception if any is ignored.
130*795d594fSAndroid Build Coastguard Worker     if (self->IsExceptionPending()) {
131*795d594fSAndroid Build Coastguard Worker       return false;  // Pending exception.
132*795d594fSAndroid Build Coastguard Worker     }
133*795d594fSAndroid Build Coastguard Worker 
134*795d594fSAndroid Build Coastguard Worker     // Restore the original exception if the instruction we are going to execute is a move exception
135*795d594fSAndroid Build Coastguard Worker     // instruction.
136*795d594fSAndroid Build Coastguard Worker     if (is_move_exception) {
137*795d594fSAndroid Build Coastguard Worker       self->SetException(exception.Get());
138*795d594fSAndroid Build Coastguard Worker     }
139*795d594fSAndroid Build Coastguard Worker     return true;
140*795d594fSAndroid Build Coastguard Worker   }
141*795d594fSAndroid Build Coastguard Worker 
142*795d594fSAndroid Build Coastguard Worker   // Unlike most other events the DexPcMovedEvent can be sent when there is a pending exception (if
143*795d594fSAndroid Build Coastguard Worker   // the next instruction is MOVE_EXCEPTION). This means it needs to be handled carefully to be able
144*795d594fSAndroid Build Coastguard Worker   // to detect exceptions thrown by the DexPcMovedEvent itself. These exceptions could be thrown by
145*795d594fSAndroid Build Coastguard Worker   // jvmti-agents while handling breakpoint or single step events. We had to move this into its own
146*795d594fSAndroid Build Coastguard Worker   // function because it was making ExecuteSwitchImpl have too large a stack.
DoDexPcMoveEvent(Thread * self,const CodeItemDataAccessor & accessor,const ShadowFrame & shadow_frame,uint32_t dex_pc,const instrumentation::Instrumentation * instrumentation,JValue * save_ref)147*795d594fSAndroid Build Coastguard Worker   NO_INLINE static bool DoDexPcMoveEvent(Thread* self,
148*795d594fSAndroid Build Coastguard Worker                                          const CodeItemDataAccessor& accessor,
149*795d594fSAndroid Build Coastguard Worker                                          const ShadowFrame& shadow_frame,
150*795d594fSAndroid Build Coastguard Worker                                          uint32_t dex_pc,
151*795d594fSAndroid Build Coastguard Worker                                          const instrumentation::Instrumentation* instrumentation,
152*795d594fSAndroid Build Coastguard Worker                                          JValue* save_ref)
153*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
154*795d594fSAndroid Build Coastguard Worker     DCHECK(instrumentation->HasDexPcListeners());
155*795d594fSAndroid Build Coastguard Worker     StackHandleScope<2> hs(self);
156*795d594fSAndroid Build Coastguard Worker     Handle<mirror::Throwable> thr(hs.NewHandle(self->GetException()));
157*795d594fSAndroid Build Coastguard Worker     mirror::Object* null_obj = nullptr;
158*795d594fSAndroid Build Coastguard Worker     HandleWrapper<mirror::Object> h(
159*795d594fSAndroid Build Coastguard Worker         hs.NewHandleWrapper(LIKELY(save_ref == nullptr) ? &null_obj : save_ref->GetGCRoot()));
160*795d594fSAndroid Build Coastguard Worker     self->ClearException();
161*795d594fSAndroid Build Coastguard Worker     instrumentation->DexPcMovedEvent(self,
162*795d594fSAndroid Build Coastguard Worker                                      shadow_frame.GetThisObject(accessor.InsSize()),
163*795d594fSAndroid Build Coastguard Worker                                      shadow_frame.GetMethod(),
164*795d594fSAndroid Build Coastguard Worker                                      dex_pc);
165*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(self->IsExceptionPending())) {
166*795d594fSAndroid Build Coastguard Worker       // We got a new exception in the dex-pc-moved event.
167*795d594fSAndroid Build Coastguard Worker       // We just let this exception replace the old one.
168*795d594fSAndroid Build Coastguard Worker       // TODO It would be good to add the old exception to the
169*795d594fSAndroid Build Coastguard Worker       // suppressed exceptions of the new one if possible.
170*795d594fSAndroid Build Coastguard Worker       return false;  // Pending exception.
171*795d594fSAndroid Build Coastguard Worker     }
172*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(!thr.IsNull())) {
173*795d594fSAndroid Build Coastguard Worker       self->SetException(thr.Get());
174*795d594fSAndroid Build Coastguard Worker     }
175*795d594fSAndroid Build Coastguard Worker     return true;
176*795d594fSAndroid Build Coastguard Worker   }
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker   template <typename T>
179*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE WARN_UNUSED
SendMethodExitEvents(Thread * self,const instrumentation::Instrumentation * instrumentation,ShadowFrame & frame,ArtMethod * method,T & result)180*795d594fSAndroid Build Coastguard Worker   static bool SendMethodExitEvents(
181*795d594fSAndroid Build Coastguard Worker       Thread* self,
182*795d594fSAndroid Build Coastguard Worker       const instrumentation::Instrumentation* instrumentation,
183*795d594fSAndroid Build Coastguard Worker       ShadowFrame& frame,
184*795d594fSAndroid Build Coastguard Worker       ArtMethod* method,
185*795d594fSAndroid Build Coastguard Worker       T& result) REQUIRES_SHARED(Locks::mutator_lock_) {
186*795d594fSAndroid Build Coastguard Worker     return interpreter::SendMethodExitEvents(self, instrumentation, frame, method, result);
187*795d594fSAndroid Build Coastguard Worker   }
188*795d594fSAndroid Build Coastguard Worker };
189*795d594fSAndroid Build Coastguard Worker 
190*795d594fSAndroid Build Coastguard Worker // Explicit definition of ExecuteSwitchImplCpp.
191*795d594fSAndroid Build Coastguard Worker template HOT_ATTR
192*795d594fSAndroid Build Coastguard Worker void ExecuteSwitchImplCpp<false>(SwitchImplContext* ctx);
193*795d594fSAndroid Build Coastguard Worker 
194*795d594fSAndroid Build Coastguard Worker }  // namespace interpreter
195*795d594fSAndroid Build Coastguard Worker }  // namespace art
196