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