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 "common_throws.h"
20 #include "dex/dex_instruction.h"
21 #include "handle.h"
22 #include "method_handles-inl.h"
23 #include "mirror/method_type-inl.h"
24 #include "mirror/var_handle.h"
25 
26 namespace art HIDDEN {
27 
28 namespace {
29 
30 template <typename CallSiteType, typename CalleeType>
31 class ThrowWrongMethodTypeFunctionImpl final : public ThrowWrongMethodTypeFunction {
32  public:
ThrowWrongMethodTypeFunctionImpl(CallSiteType callsite_type,CalleeType callee_type)33   ThrowWrongMethodTypeFunctionImpl(CallSiteType callsite_type, CalleeType callee_type)
34       : callsite_type_(callsite_type),
35         callee_type_(callee_type) {}
36 
~ThrowWrongMethodTypeFunctionImpl()37   ~ThrowWrongMethodTypeFunctionImpl() {}
38 
operator ()() const39   void operator()() const override REQUIRES_SHARED(Locks::mutator_lock_) {
40     ThrowWrongMethodTypeException(mirror::MethodType::PrettyDescriptor(callee_type_),
41                                   mirror::MethodType::PrettyDescriptor(callsite_type_));
42   }
43 
44  private:
45   CallSiteType callsite_type_;
46   CalleeType callee_type_;
47 };
48 
49 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)50 bool VarHandleInvokeAccessorWithConversions(Thread* self,
51                                             ShadowFrame& shadow_frame,
52                                             Handle<mirror::VarHandle> var_handle,
53                                             CallSiteType callsite_type,
54                                             mirror::VarHandle::AccessMode access_mode,
55                                             const InstructionOperands* operands,
56                                             JValue* result)
57     REQUIRES_SHARED(Locks::mutator_lock_) {
58   // Use a raw method handle for `accessor_type`, avoid allocating a managed `MethodType`.
59   VariableSizedHandleScope accessor_type_hs(self);
60   mirror::RawMethodType accessor_type(&accessor_type_hs);
61   var_handle->GetMethodTypeForAccessMode(access_mode, accessor_type);
62   using HandleScopeType = std::conditional_t<
63       std::is_same_v<VariableSizedHandleScope*, CallSiteType>,
64       Thread*,  // No handle scope needed, use `Thread*` that can be initialized from `self`.
65       StackHandleScope<3>>;
66   HandleScopeType hs(self);
67   ThrowWrongMethodTypeFunctionImpl throw_wmt(callsite_type, accessor_type);
68   auto from_types = mirror::MethodType::NewHandlePTypes(callsite_type, &hs);
69   auto to_types = mirror::MethodType::NewHandlePTypes(accessor_type, &hs);
70   const size_t num_vregs = mirror::MethodType::NumberOfVRegs(accessor_type);
71   ShadowFrameAllocaUniquePtr accessor_frame =
72       CREATE_SHADOW_FRAME(num_vregs, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
73   ShadowFrameGetter getter(shadow_frame, operands);
74   static const uint32_t kFirstDestinationReg = 0;
75   ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
76   if (!PerformConversions(throw_wmt, from_types, to_types, &getter, &setter)) {
77     DCHECK(self->IsExceptionPending());
78     return false;
79   }
80   RangeInstructionOperands accessor_operands(kFirstDestinationReg,
81                                              kFirstDestinationReg + num_vregs);
82   if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
83     DCHECK(self->IsExceptionPending());
84     return false;
85   }
86   if (!ConvertReturnValue(throw_wmt,
87                           mirror::MethodType::GetRType(accessor_type),
88                           mirror::MethodType::GetRType(callsite_type),
89                           result)) {
90     DCHECK(self->IsExceptionPending());
91     return false;
92   }
93   return true;
94 }
95 
96 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)97 bool VarHandleInvokeAccessorImpl(Thread* self,
98                                  ShadowFrame& shadow_frame,
99                                  Handle<mirror::VarHandle> var_handle,
100                                  CallSiteType callsite_type,
101                                  const mirror::VarHandle::AccessMode access_mode,
102                                  const InstructionOperands* const operands,
103                                  JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
104   if (var_handle.IsNull()) {
105     ThrowNullPointerExceptionFromDexPC();
106     return false;
107   }
108 
109   if (!var_handle->IsAccessModeSupported(access_mode)) {
110     ThrowUnsupportedOperationException();
111     return false;
112   }
113 
114   mirror::VarHandle::MatchKind match_kind =
115       var_handle->GetMethodTypeMatchForAccessMode(access_mode, callsite_type);
116   if (LIKELY(match_kind == mirror::VarHandle::MatchKind::kExact)) {
117     return var_handle->Access(access_mode, &shadow_frame, operands, result);
118   } else if (match_kind == mirror::VarHandle::MatchKind::kWithConversions) {
119     return VarHandleInvokeAccessorWithConversions(self,
120                                                   shadow_frame,
121                                                   var_handle,
122                                                   callsite_type,
123                                                   access_mode,
124                                                   operands,
125                                                   result);
126   } else {
127     DCHECK_EQ(match_kind, mirror::VarHandle::MatchKind::kNone);
128     ThrowWrongMethodTypeException(var_handle->PrettyDescriptorForAccessMode(access_mode),
129                                   mirror::MethodType::PrettyDescriptor(callsite_type));
130     return false;
131   }
132 }
133 
134 }  // namespace
135 
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)136 bool VarHandleInvokeAccessor(Thread* self,
137                              ShadowFrame& shadow_frame,
138                              Handle<mirror::VarHandle> var_handle,
139                              Handle<mirror::MethodType> callsite_type,
140                              const mirror::VarHandle::AccessMode access_mode,
141                              const InstructionOperands* const operands,
142                              JValue* result) {
143   return VarHandleInvokeAccessorImpl(
144       self, shadow_frame, var_handle, callsite_type, access_mode, operands, result);
145 }
146 
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)147 bool VarHandleInvokeAccessor(Thread* self,
148                              ShadowFrame& shadow_frame,
149                              Handle<mirror::VarHandle> var_handle,
150                              mirror::RawMethodType callsite_type,
151                              const mirror::VarHandle::AccessMode access_mode,
152                              const InstructionOperands* const operands,
153                              JValue* result) {
154   return VarHandleInvokeAccessorImpl(
155       self, shadow_frame, var_handle, callsite_type, access_mode, operands, result);
156 }
157 
158 }  // namespace art
159