xref: /aosp_15_r20/art/runtime/var_handles.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 #include "var_handles.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "art_method.h"
20*795d594fSAndroid Build Coastguard Worker #include "common_throws.h"
21*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction.h"
22*795d594fSAndroid Build Coastguard Worker #include "handle.h"
23*795d594fSAndroid Build Coastguard Worker #include "method_handles-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "mirror/method_type-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "mirror/var_handle.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace {
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker template <typename CallSiteType, typename CalleeType>
32*795d594fSAndroid Build Coastguard Worker class ThrowWrongMethodTypeFunctionImpl final : public ThrowWrongMethodTypeFunction {
33*795d594fSAndroid Build Coastguard Worker  public:
ThrowWrongMethodTypeFunctionImpl(CallSiteType callsite_type,CalleeType callee_type)34*795d594fSAndroid Build Coastguard Worker   ThrowWrongMethodTypeFunctionImpl(CallSiteType callsite_type, CalleeType callee_type)
35*795d594fSAndroid Build Coastguard Worker       : callsite_type_(callsite_type),
36*795d594fSAndroid Build Coastguard Worker         callee_type_(callee_type) {}
37*795d594fSAndroid Build Coastguard Worker 
~ThrowWrongMethodTypeFunctionImpl()38*795d594fSAndroid Build Coastguard Worker   ~ThrowWrongMethodTypeFunctionImpl() {}
39*795d594fSAndroid Build Coastguard Worker 
operator ()() const40*795d594fSAndroid Build Coastguard Worker   void operator()() const override REQUIRES_SHARED(Locks::mutator_lock_) {
41*795d594fSAndroid Build Coastguard Worker     ThrowWrongMethodTypeException(mirror::MethodType::PrettyDescriptor(callee_type_),
42*795d594fSAndroid Build Coastguard Worker                                   mirror::MethodType::PrettyDescriptor(callsite_type_));
43*795d594fSAndroid Build Coastguard Worker   }
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker  private:
46*795d594fSAndroid Build Coastguard Worker   CallSiteType callsite_type_;
47*795d594fSAndroid Build Coastguard Worker   CalleeType callee_type_;
48*795d594fSAndroid Build Coastguard Worker };
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker template <typename CallSiteType>
VarHandleInvokeAccessorWithConversions(Thread * self,ShadowFrame & shadow_frame,Handle<mirror::VarHandle> var_handle,CallSiteType callsite_type,mirror::VarHandle::AccessMode access_mode,const InstructionOperands * operands,JValue * result)51*795d594fSAndroid Build Coastguard Worker bool VarHandleInvokeAccessorWithConversions(Thread* self,
52*795d594fSAndroid Build Coastguard Worker                                             ShadowFrame& shadow_frame,
53*795d594fSAndroid Build Coastguard Worker                                             Handle<mirror::VarHandle> var_handle,
54*795d594fSAndroid Build Coastguard Worker                                             CallSiteType callsite_type,
55*795d594fSAndroid Build Coastguard Worker                                             mirror::VarHandle::AccessMode access_mode,
56*795d594fSAndroid Build Coastguard Worker                                             const InstructionOperands* operands,
57*795d594fSAndroid Build Coastguard Worker                                             JValue* result)
58*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
59*795d594fSAndroid Build Coastguard Worker   // Use a raw method handle for `accessor_type`, avoid allocating a managed `MethodType`.
60*795d594fSAndroid Build Coastguard Worker   VariableSizedHandleScope accessor_type_hs(self);
61*795d594fSAndroid Build Coastguard Worker   mirror::RawMethodType accessor_type(&accessor_type_hs);
62*795d594fSAndroid Build Coastguard Worker   var_handle->GetMethodTypeForAccessMode(access_mode, accessor_type);
63*795d594fSAndroid Build Coastguard Worker   using HandleScopeType = std::conditional_t<
64*795d594fSAndroid Build Coastguard Worker       std::is_same_v<VariableSizedHandleScope*, CallSiteType>,
65*795d594fSAndroid Build Coastguard Worker       Thread*,  // No handle scope needed, use `Thread*` that can be initialized from `self`.
66*795d594fSAndroid Build Coastguard Worker       StackHandleScope<3>>;
67*795d594fSAndroid Build Coastguard Worker   HandleScopeType hs(self);
68*795d594fSAndroid Build Coastguard Worker   ThrowWrongMethodTypeFunctionImpl throw_wmt(callsite_type, accessor_type);
69*795d594fSAndroid Build Coastguard Worker   auto from_types = mirror::MethodType::NewHandlePTypes(callsite_type, &hs);
70*795d594fSAndroid Build Coastguard Worker   auto to_types = mirror::MethodType::NewHandlePTypes(accessor_type, &hs);
71*795d594fSAndroid Build Coastguard Worker   const size_t num_vregs = mirror::MethodType::NumberOfVRegs(accessor_type);
72*795d594fSAndroid Build Coastguard Worker   ShadowFrameAllocaUniquePtr accessor_frame =
73*795d594fSAndroid Build Coastguard Worker       CREATE_SHADOW_FRAME(num_vregs, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
74*795d594fSAndroid Build Coastguard Worker   ShadowFrameGetter getter(shadow_frame, operands);
75*795d594fSAndroid Build Coastguard Worker   static const uint32_t kFirstDestinationReg = 0;
76*795d594fSAndroid Build Coastguard Worker   ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
77*795d594fSAndroid Build Coastguard Worker   if (!PerformConversions(throw_wmt, from_types, to_types, &getter, &setter)) {
78*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
79*795d594fSAndroid Build Coastguard Worker     return false;
80*795d594fSAndroid Build Coastguard Worker   }
81*795d594fSAndroid Build Coastguard Worker   RangeInstructionOperands accessor_operands(kFirstDestinationReg,
82*795d594fSAndroid Build Coastguard Worker                                              kFirstDestinationReg + num_vregs);
83*795d594fSAndroid Build Coastguard Worker   if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
84*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
85*795d594fSAndroid Build Coastguard Worker     return false;
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker   if (!ConvertReturnValue(throw_wmt,
88*795d594fSAndroid Build Coastguard Worker                           mirror::MethodType::GetRType(accessor_type),
89*795d594fSAndroid Build Coastguard Worker                           mirror::MethodType::GetRType(callsite_type),
90*795d594fSAndroid Build Coastguard Worker                           result)) {
91*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
92*795d594fSAndroid Build Coastguard Worker     return false;
93*795d594fSAndroid Build Coastguard Worker   }
94*795d594fSAndroid Build Coastguard Worker   return true;
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker template <typename CallSiteType>
VarHandleInvokeAccessorImpl(Thread * self,ShadowFrame & shadow_frame,Handle<mirror::VarHandle> var_handle,CallSiteType callsite_type,const mirror::VarHandle::AccessMode access_mode,const InstructionOperands * const operands,JValue * result)98*795d594fSAndroid Build Coastguard Worker bool VarHandleInvokeAccessorImpl(Thread* self,
99*795d594fSAndroid Build Coastguard Worker                                  ShadowFrame& shadow_frame,
100*795d594fSAndroid Build Coastguard Worker                                  Handle<mirror::VarHandle> var_handle,
101*795d594fSAndroid Build Coastguard Worker                                  CallSiteType callsite_type,
102*795d594fSAndroid Build Coastguard Worker                                  const mirror::VarHandle::AccessMode access_mode,
103*795d594fSAndroid Build Coastguard Worker                                  const InstructionOperands* const operands,
104*795d594fSAndroid Build Coastguard Worker                                  JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
105*795d594fSAndroid Build Coastguard Worker   if (var_handle.IsNull()) {
106*795d594fSAndroid Build Coastguard Worker     ThrowNullPointerExceptionFromDexPC();
107*795d594fSAndroid Build Coastguard Worker     return false;
108*795d594fSAndroid Build Coastguard Worker   }
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker   if (!var_handle->IsAccessModeSupported(access_mode)) {
111*795d594fSAndroid Build Coastguard Worker     ThrowUnsupportedOperationException();
112*795d594fSAndroid Build Coastguard Worker     return false;
113*795d594fSAndroid Build Coastguard Worker   }
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker   mirror::VarHandle::MatchKind match_kind =
116*795d594fSAndroid Build Coastguard Worker       var_handle->GetMethodTypeMatchForAccessMode(access_mode, callsite_type);
117*795d594fSAndroid Build Coastguard Worker   if (LIKELY(match_kind == mirror::VarHandle::MatchKind::kExact)) {
118*795d594fSAndroid Build Coastguard Worker     return var_handle->Access(access_mode, &shadow_frame, operands, result);
119*795d594fSAndroid Build Coastguard Worker   } else if (match_kind == mirror::VarHandle::MatchKind::kWithConversions) {
120*795d594fSAndroid Build Coastguard Worker     return VarHandleInvokeAccessorWithConversions(self,
121*795d594fSAndroid Build Coastguard Worker                                                   shadow_frame,
122*795d594fSAndroid Build Coastguard Worker                                                   var_handle,
123*795d594fSAndroid Build Coastguard Worker                                                   callsite_type,
124*795d594fSAndroid Build Coastguard Worker                                                   access_mode,
125*795d594fSAndroid Build Coastguard Worker                                                   operands,
126*795d594fSAndroid Build Coastguard Worker                                                   result);
127*795d594fSAndroid Build Coastguard Worker   } else {
128*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(match_kind, mirror::VarHandle::MatchKind::kNone);
129*795d594fSAndroid Build Coastguard Worker     ThrowWrongMethodTypeException(var_handle->PrettyDescriptorForAccessMode(access_mode),
130*795d594fSAndroid Build Coastguard Worker                                   mirror::MethodType::PrettyDescriptor(callsite_type));
131*795d594fSAndroid Build Coastguard Worker     return false;
132*795d594fSAndroid Build Coastguard Worker   }
133*795d594fSAndroid Build Coastguard Worker }
134*795d594fSAndroid Build Coastguard Worker 
135*795d594fSAndroid Build Coastguard Worker }  // namespace
136*795d594fSAndroid Build Coastguard Worker 
VarHandleInvokeAccessor(Thread * self,ShadowFrame & shadow_frame,Handle<mirror::VarHandle> var_handle,Handle<mirror::MethodType> callsite_type,const mirror::VarHandle::AccessMode access_mode,const InstructionOperands * const operands,JValue * result)137*795d594fSAndroid Build Coastguard Worker bool VarHandleInvokeAccessor(Thread* self,
138*795d594fSAndroid Build Coastguard Worker                              ShadowFrame& shadow_frame,
139*795d594fSAndroid Build Coastguard Worker                              Handle<mirror::VarHandle> var_handle,
140*795d594fSAndroid Build Coastguard Worker                              Handle<mirror::MethodType> callsite_type,
141*795d594fSAndroid Build Coastguard Worker                              const mirror::VarHandle::AccessMode access_mode,
142*795d594fSAndroid Build Coastguard Worker                              const InstructionOperands* const operands,
143*795d594fSAndroid Build Coastguard Worker                              JValue* result) {
144*795d594fSAndroid Build Coastguard Worker   return VarHandleInvokeAccessorImpl(
145*795d594fSAndroid Build Coastguard Worker       self, shadow_frame, var_handle, callsite_type, access_mode, operands, result);
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker 
VarHandleInvokeAccessor(Thread * self,ShadowFrame & shadow_frame,Handle<mirror::VarHandle> var_handle,mirror::RawMethodType callsite_type,const mirror::VarHandle::AccessMode access_mode,const InstructionOperands * const operands,JValue * result)148*795d594fSAndroid Build Coastguard Worker bool VarHandleInvokeAccessor(Thread* self,
149*795d594fSAndroid Build Coastguard Worker                              ShadowFrame& shadow_frame,
150*795d594fSAndroid Build Coastguard Worker                              Handle<mirror::VarHandle> var_handle,
151*795d594fSAndroid Build Coastguard Worker                              mirror::RawMethodType callsite_type,
152*795d594fSAndroid Build Coastguard Worker                              const mirror::VarHandle::AccessMode access_mode,
153*795d594fSAndroid Build Coastguard Worker                              const InstructionOperands* const operands,
154*795d594fSAndroid Build Coastguard Worker                              JValue* result) {
155*795d594fSAndroid Build Coastguard Worker   return VarHandleInvokeAccessorImpl(
156*795d594fSAndroid Build Coastguard Worker       self, shadow_frame, var_handle, callsite_type, access_mode, operands, result);
157*795d594fSAndroid Build Coastguard Worker }
158*795d594fSAndroid Build Coastguard Worker 
VarHandleInvokeAccessor(Thread * self,ShadowFrame & shadow_frame,Handle<mirror::VarHandle> var_handle,ArtMethod * caller_method,const dex::ProtoIndex callsite_type_id,const mirror::VarHandle::AccessMode access_mode,const InstructionOperands * const operands,JValue * result)159*795d594fSAndroid Build Coastguard Worker bool VarHandleInvokeAccessor(Thread* self,
160*795d594fSAndroid Build Coastguard Worker                              ShadowFrame& shadow_frame,
161*795d594fSAndroid Build Coastguard Worker                              Handle<mirror::VarHandle> var_handle,
162*795d594fSAndroid Build Coastguard Worker                              ArtMethod* caller_method,
163*795d594fSAndroid Build Coastguard Worker                              const dex::ProtoIndex callsite_type_id,
164*795d594fSAndroid Build Coastguard Worker                              const mirror::VarHandle::AccessMode access_mode,
165*795d594fSAndroid Build Coastguard Worker                              const InstructionOperands* const operands,
166*795d594fSAndroid Build Coastguard Worker                              JValue* result) {
167*795d594fSAndroid Build Coastguard Worker   StackHandleScope<3> hs(self);
168*795d594fSAndroid Build Coastguard Worker   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker   Handle<mirror::DexCache> dex_cache = hs.NewHandle(caller_method->GetDexCache());
171*795d594fSAndroid Build Coastguard Worker   Handle<mirror::ClassLoader> class_loader = hs.NewHandle(caller_method->GetClassLoader());
172*795d594fSAndroid Build Coastguard Worker 
173*795d594fSAndroid Build Coastguard Worker   // If the `ThreadLocalRandom` class is not yet initialized, do the `VarHandle` operation
174*795d594fSAndroid Build Coastguard Worker   // without creating a managed `MethodType` object. This avoids a circular initialization
175*795d594fSAndroid Build Coastguard Worker   // issue when `ThreadLocalRandom.<clinit>` indirectly calls `AtomicLong.compareAndSet()`
176*795d594fSAndroid Build Coastguard Worker   // (implemented with a `VarHandle`) and the `MethodType` caching circles back to the
177*795d594fSAndroid Build Coastguard Worker   // `ThreadLocalRandom` with uninitialized `seeder` and throws NPE.
178*795d594fSAndroid Build Coastguard Worker   //
179*795d594fSAndroid Build Coastguard Worker   // Do a quick test for "visibly initialized" without a read barrier and, if that fails,
180*795d594fSAndroid Build Coastguard Worker   // do a thorough test for "initialized" (including load acquire) with the read barrier.
181*795d594fSAndroid Build Coastguard Worker   ArtField* field = WellKnownClasses::java_util_concurrent_ThreadLocalRandom_seeder;
182*795d594fSAndroid Build Coastguard Worker   if (LIKELY(field->GetDeclaringClass<kWithoutReadBarrier>()->IsVisiblyInitialized()) ||
183*795d594fSAndroid Build Coastguard Worker       field->GetDeclaringClass()->IsInitialized()) {
184*795d594fSAndroid Build Coastguard Worker     Handle<mirror::MethodType> callsite_type(hs.NewHandle(
185*795d594fSAndroid Build Coastguard Worker         class_linker->ResolveMethodType(self, callsite_type_id, dex_cache, class_loader)));
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker     if (LIKELY(callsite_type != nullptr)) {
188*795d594fSAndroid Build Coastguard Worker       return VarHandleInvokeAccessor(self,
189*795d594fSAndroid Build Coastguard Worker                                      shadow_frame,
190*795d594fSAndroid Build Coastguard Worker                                      var_handle,
191*795d594fSAndroid Build Coastguard Worker                                      callsite_type,
192*795d594fSAndroid Build Coastguard Worker                                      access_mode,
193*795d594fSAndroid Build Coastguard Worker                                      operands,
194*795d594fSAndroid Build Coastguard Worker                                      result);
195*795d594fSAndroid Build Coastguard Worker     }
196*795d594fSAndroid Build Coastguard Worker     // This implies we couldn't resolve one or more types in this VarHandle,
197*795d594fSAndroid Build Coastguard Worker     // or we could not allocate the `MethodType` object.
198*795d594fSAndroid Build Coastguard Worker     CHECK(self->IsExceptionPending());
199*795d594fSAndroid Build Coastguard Worker     if (self->GetException()->GetClass() != WellKnownClasses::java_lang_OutOfMemoryError.Get()) {
200*795d594fSAndroid Build Coastguard Worker       return false;
201*795d594fSAndroid Build Coastguard Worker     }
202*795d594fSAndroid Build Coastguard Worker     // Clear the OOME and retry without creating an actual `MethodType` object.
203*795d594fSAndroid Build Coastguard Worker     // This prevents unexpected OOME for trivial `VarHandle` operations.
204*795d594fSAndroid Build Coastguard Worker     // It also prevents odd situations where a `VarHandle` operation succeeds but the same
205*795d594fSAndroid Build Coastguard Worker     // operation fails later because the `MethodType` object was evicted from the `DexCache`
206*795d594fSAndroid Build Coastguard Worker     // and we suddenly run out of memory to allocate a new one.
207*795d594fSAndroid Build Coastguard Worker     //
208*795d594fSAndroid Build Coastguard Worker     // We have previously seen OOMEs in the run-test `183-rmw-stress-test` with
209*795d594fSAndroid Build Coastguard Worker     // `--optimizng --no-image` (boot class path methods run in interpreter without JIT)
210*795d594fSAndroid Build Coastguard Worker     // but it probably happened on the first execution of a trivial `VarHandle` operation
211*795d594fSAndroid Build Coastguard Worker     // and not due to the `DexCache` eviction mentioned above.
212*795d594fSAndroid Build Coastguard Worker     self->ClearException();
213*795d594fSAndroid Build Coastguard Worker   }
214*795d594fSAndroid Build Coastguard Worker 
215*795d594fSAndroid Build Coastguard Worker   VariableSizedHandleScope callsite_type_hs(self);
216*795d594fSAndroid Build Coastguard Worker   mirror::RawMethodType callsite_type(&callsite_type_hs);
217*795d594fSAndroid Build Coastguard Worker   if (!class_linker->ResolveMethodType(self,
218*795d594fSAndroid Build Coastguard Worker                                        callsite_type_id,
219*795d594fSAndroid Build Coastguard Worker                                        dex_cache,
220*795d594fSAndroid Build Coastguard Worker                                        class_loader,
221*795d594fSAndroid Build Coastguard Worker                                        callsite_type)) {
222*795d594fSAndroid Build Coastguard Worker     CHECK(self->IsExceptionPending());
223*795d594fSAndroid Build Coastguard Worker     return false;
224*795d594fSAndroid Build Coastguard Worker   }
225*795d594fSAndroid Build Coastguard Worker   return VarHandleInvokeAccessor(self,
226*795d594fSAndroid Build Coastguard Worker                                  shadow_frame,
227*795d594fSAndroid Build Coastguard Worker                                  var_handle,
228*795d594fSAndroid Build Coastguard Worker                                  callsite_type,
229*795d594fSAndroid Build Coastguard Worker                                  access_mode,
230*795d594fSAndroid Build Coastguard Worker                                  operands,
231*795d594fSAndroid Build Coastguard Worker                                  result);
232*795d594fSAndroid Build Coastguard Worker }
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker }  // namespace art
235