1 /*
2  * Copyright (C) 2016 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 #ifndef ART_RUNTIME_METHOD_HANDLES_INL_H_
18 #define ART_RUNTIME_METHOD_HANDLES_INL_H_
19 
20 #include "method_handles.h"
21 
22 #include "common_throws.h"
23 #include "dex/dex_instruction.h"
24 #include "interpreter/interpreter_common.h"
25 #include "interpreter/shadow_frame-inl.h"
26 #include "jvalue-inl.h"
27 #include "mirror/class.h"
28 #include "mirror/method_type-inl.h"
29 #include "mirror/object.h"
30 #include "reflection.h"
31 #include "stack.h"
32 
33 namespace art HIDDEN {
34 
35 // A convenience class that allows for iteration through a list of
36 // input argument registers. This is used to iterate over input
37 // arguments while performing standard argument conversions.
38 class ShadowFrameGetter {
39  public:
40   ShadowFrameGetter(const ShadowFrame& shadow_frame,
41                     const InstructionOperands* const operands,
42                     size_t operand_index = 0u)
shadow_frame_(shadow_frame)43       : shadow_frame_(shadow_frame), operands_(operands), operand_index_(operand_index)  {}
44 
Get()45   ALWAYS_INLINE uint32_t Get() REQUIRES_SHARED(Locks::mutator_lock_) {
46     return shadow_frame_.GetVReg(Next());
47   }
48 
GetLong()49   ALWAYS_INLINE int64_t GetLong() REQUIRES_SHARED(Locks::mutator_lock_) {
50     return shadow_frame_.GetVRegLong(NextLong());
51   }
52 
GetReference()53   ALWAYS_INLINE ObjPtr<mirror::Object> GetReference() REQUIRES_SHARED(Locks::mutator_lock_) {
54     return shadow_frame_.GetVRegReference(Next());
55   }
56 
57  private:
Next()58   uint32_t Next() {
59     const uint32_t next = operands_->GetOperand(operand_index_);
60     operand_index_ += 1;
61     return next;
62   }
63 
NextLong()64   uint32_t NextLong() {
65     const uint32_t next = operands_->GetOperand(operand_index_);
66     operand_index_ += 2;
67     return next;
68   }
69 
70   const ShadowFrame& shadow_frame_;
71   const InstructionOperands* const operands_;  // the set of register operands to read
72   size_t operand_index_;  // the next register operand to read from frame
73 };
74 
75 // A convenience class that allows values to be written to a given shadow frame,
76 // starting at location |first_dst_reg|.
77 class ShadowFrameSetter {
78  public:
ShadowFrameSetter(ShadowFrame * shadow_frame,size_t first_dst_reg)79   ShadowFrameSetter(ShadowFrame* shadow_frame, size_t first_dst_reg)
80       : shadow_frame_(shadow_frame), arg_index_(first_dst_reg) {}
81 
Set(uint32_t value)82   ALWAYS_INLINE void Set(uint32_t value) REQUIRES_SHARED(Locks::mutator_lock_) {
83     DCHECK_LT(arg_index_, shadow_frame_->NumberOfVRegs());
84     shadow_frame_->SetVReg(arg_index_++, value);
85   }
86 
SetReference(ObjPtr<mirror::Object> value)87   ALWAYS_INLINE void SetReference(ObjPtr<mirror::Object> value)
88       REQUIRES_SHARED(Locks::mutator_lock_) {
89     DCHECK_LT(arg_index_, shadow_frame_->NumberOfVRegs());
90     shadow_frame_->SetVRegReference(arg_index_++, value);
91   }
92 
SetLong(int64_t value)93   ALWAYS_INLINE void SetLong(int64_t value) REQUIRES_SHARED(Locks::mutator_lock_) {
94     DCHECK_LT(arg_index_, shadow_frame_->NumberOfVRegs());
95     shadow_frame_->SetVRegLong(arg_index_, value);
96     arg_index_ += 2;
97   }
98 
Done()99   ALWAYS_INLINE bool Done() const {
100     return arg_index_ == shadow_frame_->NumberOfVRegs();
101   }
102 
103  private:
104   ShadowFrame* shadow_frame_;
105   size_t arg_index_;
106 };
107 
ConvertArgumentValue(const ThrowWrongMethodTypeFunction & throw_wmt,ObjPtr<mirror::Class> from,ObjPtr<mirror::Class> to,JValue * value)108 inline bool ConvertArgumentValue(const ThrowWrongMethodTypeFunction& throw_wmt,
109                                  ObjPtr<mirror::Class> from,
110                                  ObjPtr<mirror::Class> to,
111                                  /*inout*/ JValue* value) {
112   if (from == to) {
113     return true;
114   }
115 
116   // `*value` may contain a bare heap pointer which is generally unsafe.
117   // `ConvertJValueCommon()` saves `*value`, `from`, and `to` to Handles
118   // where necessary to avoid issues if the heap changes.
119   if (ConvertJValueCommon(throw_wmt, from, to, value)) {
120     DCHECK(!Thread::Current()->IsExceptionPending());
121     return true;
122   } else {
123     DCHECK(Thread::Current()->IsExceptionPending());
124     value->SetJ(0);
125     return false;
126   }
127 }
128 
ConvertReturnValue(const ThrowWrongMethodTypeFunction & throw_wmt,ObjPtr<mirror::Class> from,ObjPtr<mirror::Class> to,JValue * value)129 inline bool ConvertReturnValue(const ThrowWrongMethodTypeFunction& throw_wmt,
130                                ObjPtr<mirror::Class> from,
131                                ObjPtr<mirror::Class> to,
132                                /*inout*/ JValue* value) {
133   if (to->GetPrimitiveType() == Primitive::kPrimVoid || from == to) {
134     return true;
135   }
136 
137   // `*value` may contain a bare heap pointer which is generally unsafe.
138   // `ConvertJValueCommon()` saves `*value`, `from`, and `to` to Handles
139   // where necessary to avoid issues if the heap changes.
140   if (ConvertJValueCommon(throw_wmt, from, to, value)) {
141     DCHECK(!Thread::Current()->IsExceptionPending());
142     return true;
143   } else {
144     DCHECK(Thread::Current()->IsExceptionPending());
145     value->SetJ(0);
146     return false;
147   }
148 }
149 
150 template <typename FromPTypes, typename ToPTypes, typename G, typename S>
PerformConversions(const ThrowWrongMethodTypeFunction & throw_wmt,FromPTypes from_types,ToPTypes to_types,G * getter,S * setter)151 bool PerformConversions(const ThrowWrongMethodTypeFunction& throw_wmt,
152                         FromPTypes from_types,
153                         ToPTypes to_types,
154                         G* getter,
155                         S* setter) {
156   DCHECK_EQ(from_types.GetLength(), to_types.GetLength());
157   for (int32_t i = 0, length = to_types.GetLength(); i != length; ++i) {
158     ObjPtr<mirror::Class> from = from_types.Get(i);
159     ObjPtr<mirror::Class> to = to_types.Get(i);
160     const Primitive::Type from_type = from->GetPrimitiveType();
161     const Primitive::Type to_type = to->GetPrimitiveType();
162     if (from == to) {
163       // Easy case - the types are identical. Nothing left to do except to pass
164       // the arguments along verbatim.
165       if (Primitive::Is64BitType(from_type)) {
166         setter->SetLong(getter->GetLong());
167       } else if (from_type == Primitive::kPrimNot) {
168         setter->SetReference(getter->GetReference());
169       } else {
170         setter->Set(getter->Get());
171       }
172     } else {
173       JValue value;
174       if (Primitive::Is64BitType(from_type)) {
175         value.SetJ(getter->GetLong());
176       } else if (from_type == Primitive::kPrimNot) {
177         value.SetL(getter->GetReference());
178       } else {
179         value.SetI(getter->Get());
180       }
181       // Caveat emptor - ObjPtr's not guaranteed valid after this call.
182       if (!ConvertArgumentValue(throw_wmt, from, to, &value)) {
183         DCHECK(Thread::Current()->IsExceptionPending());
184         return false;
185       }
186       if (Primitive::Is64BitType(to_type)) {
187         setter->SetLong(value.GetJ());
188       } else if (to_type == Primitive::kPrimNot) {
189         setter->SetReference(value.GetL());
190       } else {
191         setter->Set(value.GetI());
192       }
193     }
194   }
195   return true;
196 }
197 
198 template <typename G, typename S>
CopyArguments(Thread * self,Handle<mirror::MethodType> method_type,G * getter,S * setter)199 bool CopyArguments(Thread* self,
200                    Handle<mirror::MethodType> method_type,
201                    G* getter,
202                    S* setter) REQUIRES_SHARED(Locks::mutator_lock_) {
203   StackHandleScope<2> hs(self);
204   Handle<mirror::ObjectArray<mirror::Class>> ptypes(hs.NewHandle(method_type->GetPTypes()));
205   int32_t ptypes_length = ptypes->GetLength();
206 
207   for (int32_t i = 0; i < ptypes_length; ++i) {
208     ObjPtr<mirror::Class> ptype(ptypes->GetWithoutChecks(i));
209     Primitive::Type primitive = ptype->GetPrimitiveType();
210     if (Primitive::Is64BitType(primitive)) {
211       setter->SetLong(getter->GetLong());
212     } else if (primitive == Primitive::kPrimNot) {
213       setter->SetReference(getter->GetReference());
214     } else {
215       setter->Set(getter->Get());
216     }
217   }
218   return true;
219 }
220 
221 }  // namespace art
222 
223 #endif  // ART_RUNTIME_METHOD_HANDLES_INL_H_
224