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