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