blob: 5f9824c079cb301b0a7d7931eee177d54ff8188f [file] [log] [blame]
Narayan Kamath208f8572016-08-03 12:46:58 +01001/*
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_instruction.h"
24#include "interpreter/interpreter_common.h"
25#include "jvalue.h"
26#include "mirror/class.h"
27#include "mirror/method_type.h"
28#include "mirror/object.h"
29#include "reflection.h"
30#include "stack.h"
31
32namespace art {
33
34// Assigns |type| to the primitive type associated with |dst_class|. Returns
35// true iff. |dst_class| was a boxed type (Integer, Long etc.), false otherwise.
36REQUIRES_SHARED(Locks::mutator_lock_)
37static inline bool GetPrimitiveType(ObjPtr<mirror::Class> dst_class, Primitive::Type* type) {
38 if (dst_class->DescriptorEquals("Ljava/lang/Boolean;")) {
39 (*type) = Primitive::kPrimBoolean;
40 return true;
41 } else if (dst_class->DescriptorEquals("Ljava/lang/Byte;")) {
42 (*type) = Primitive::kPrimByte;
43 return true;
44 } else if (dst_class->DescriptorEquals("Ljava/lang/Character;")) {
45 (*type) = Primitive::kPrimChar;
46 return true;
47 } else if (dst_class->DescriptorEquals("Ljava/lang/Float;")) {
48 (*type) = Primitive::kPrimFloat;
49 return true;
50 } else if (dst_class->DescriptorEquals("Ljava/lang/Double;")) {
51 (*type) = Primitive::kPrimDouble;
52 return true;
53 } else if (dst_class->DescriptorEquals("Ljava/lang/Integer;")) {
54 (*type) = Primitive::kPrimInt;
55 return true;
56 } else if (dst_class->DescriptorEquals("Ljava/lang/Long;")) {
57 (*type) = Primitive::kPrimLong;
58 return true;
59 } else if (dst_class->DescriptorEquals("Ljava/lang/Short;")) {
60 (*type) = Primitive::kPrimShort;
61 return true;
62 } else {
63 return false;
64 }
65}
66
67// A convenience class that allows for iteration through a list of
68// input argument registers |arg| for non-range invokes or a list of
69// consecutive registers starting with a given based for range
70// invokes.
71template <bool is_range> class ArgIterator {
72 public:
73 ArgIterator(size_t first_src_reg,
74 const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) :
75 first_src_reg_(first_src_reg),
76 arg_(arg),
77 arg_index_(0) {
78 }
79
80 uint32_t Next() {
81 const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
82 ++arg_index_;
83
84 return next;
85 }
86
87 uint32_t NextPair() {
88 const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
89 arg_index_ += 2;
90
91 return next;
92 }
93
94 private:
95 const size_t first_src_reg_;
96 const uint32_t (&arg_)[Instruction::kMaxVarArgRegs];
97 size_t arg_index_;
98};
99
100template <bool is_range>
101bool PerformArgumentConversions(Thread* self,
102 Handle<mirror::MethodType> callsite_type,
103 Handle<mirror::MethodType> callee_type,
104 const ShadowFrame& caller_frame,
105 uint32_t first_src_reg,
106 uint32_t first_dest_reg,
107 const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
108 ShadowFrame* callee_frame,
109 JValue* result) {
110 StackHandleScope<4> hs(self);
111 Handle<mirror::ObjectArray<mirror::Class>> from_types(hs.NewHandle(callsite_type->GetPTypes()));
112 Handle<mirror::ObjectArray<mirror::Class>> to_types(hs.NewHandle(callee_type->GetPTypes()));
113
114 const int32_t num_method_params = from_types->GetLength();
115 if (to_types->GetLength() != num_method_params) {
116 ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
117 result->SetJ(0);
118 return false;
119 }
120
121 ArgIterator<is_range> input_args(first_src_reg, arg);
122 size_t to_arg_index = 0;
123 MutableHandle<mirror::Class> from(hs.NewHandle<mirror::Class>(nullptr));
124 MutableHandle<mirror::Class> to(hs.NewHandle<mirror::Class>(nullptr));
125 for (int32_t i = 0; i < num_method_params; ++i) {
126 from.Assign(from_types->GetWithoutChecks(i));
127 to.Assign(to_types->GetWithoutChecks(i));
128
129 const Primitive::Type from_type = from->GetPrimitiveType();
130 const Primitive::Type to_type = to->GetPrimitiveType();
131
132 // Easy case - the types are identical. Nothing left to do except to pass
133 // the arguments along verbatim.
134 if (from.Get() == to.Get()) {
135 interpreter::AssignRegister(callee_frame,
136 caller_frame,
137 first_dest_reg + to_arg_index,
138 input_args.Next());
139 ++to_arg_index;
140
141 // This is a wide argument, we must use the second half of the register
142 // pair as well.
143 if (Primitive::Is64BitType(from_type)) {
144 interpreter::AssignRegister(callee_frame,
145 caller_frame,
146 first_dest_reg + to_arg_index,
147 input_args.Next());
148 ++to_arg_index;
149 }
150
151 continue;
152 } else if ((from_type != Primitive::kPrimNot) && (to_type != Primitive::kPrimNot)) {
153 // They are both primitive types - we should perform any widening or
154 // narrowing conversions as applicable.
155 JValue from_value;
156 JValue to_value;
157
158 if (Primitive::Is64BitType(from_type)) {
159 from_value.SetJ(caller_frame.GetVRegLong(input_args.NextPair()));
160 } else {
161 from_value.SetI(caller_frame.GetVReg(input_args.Next()));
162 }
163
164 // Throws a ClassCastException if we're unable to convert a primitive value.
165 if (!ConvertPrimitiveValue(false, from_type, to_type, from_value, &to_value)) {
166 DCHECK(self->IsExceptionPending());
167 result->SetL(0);
168 return false;
169 }
170
171 if (Primitive::Is64BitType(to_type)) {
172 callee_frame->SetVRegLong(first_dest_reg + to_arg_index, to_value.GetJ());
173 to_arg_index += 2;
174 } else {
175 callee_frame->SetVReg(first_dest_reg + to_arg_index, to_value.GetI());
176 ++to_arg_index;
177 }
178 } else if ((from_type == Primitive::kPrimNot) && (to_type == Primitive::kPrimNot)) {
179 // They're both reference types. If "from" is null, we can pass it
180 // through unchanged. If not, we must generate a cast exception if
181 // |to| is not assignable from the dynamic type of |ref|.
182 const size_t next_arg_reg = input_args.Next();
183 mirror::Object* const ref = caller_frame.GetVRegReference(next_arg_reg);
184 if (ref == nullptr || to->IsAssignableFrom(ref->GetClass())) {
185 interpreter::AssignRegister(callee_frame,
186 caller_frame,
187 first_dest_reg + to_arg_index,
188 next_arg_reg);
189 ++to_arg_index;
190 } else {
191 ThrowClassCastException(to.Get(), ref->GetClass());
192 result->SetL(0);
193 return false;
194 }
195 } else {
196 // Precisely one of the source or the destination are reference types.
197 // We must box or unbox.
198 if (to_type == Primitive::kPrimNot) {
199 // The target type is a reference, we must box.
200 Primitive::Type type;
201 // TODO(narayan): This is a CHECK for now. There might be a few corner cases
202 // here that we might not have handled yet. For exmple, if |to| is java/lang/Number;,
203 // we will need to box this "naturally".
204 CHECK(GetPrimitiveType(to.Get(), &type));
205
206 JValue from_value;
207 JValue to_value;
208
209 if (Primitive::Is64BitType(from_type)) {
210 from_value.SetJ(caller_frame.GetVRegLong(input_args.NextPair()));
211 } else {
212 from_value.SetI(caller_frame.GetVReg(input_args.Next()));
213 }
214
215 // First perform a primitive conversion to the unboxed equivalent of the target,
216 // if necessary. This should be for the rarer cases like (int->Long) etc.
217 if (UNLIKELY(from_type != type)) {
218 if (!ConvertPrimitiveValue(false, from_type, type, from_value, &to_value)) {
219 DCHECK(self->IsExceptionPending());
220 result->SetL(0);
221 return false;
222 }
223 } else {
224 to_value = from_value;
225 }
226
227 // Then perform the actual boxing, and then set the reference.
228 ObjPtr<mirror::Object> boxed = BoxPrimitive(type, to_value);
229 callee_frame->SetVRegReference(first_dest_reg + to_arg_index, boxed.Ptr());
230 ++to_arg_index;
231 } else {
232 // The target type is a primitive, we must unbox.
233 ObjPtr<mirror::Object> ref(caller_frame.GetVRegReference(input_args.Next()));
234
235 // Note that UnboxPrimitiveForResult already performs all of the type
236 // conversions that we want, based on |to|.
237 JValue unboxed_value;
238 if (!UnboxPrimitiveForResult(ref, to.Get(), &unboxed_value)) {
239 DCHECK(self->IsExceptionPending());
240 result->SetL(0);
241 return false;
242 }
243
244 if (Primitive::Is64BitType(to_type)) {
245 callee_frame->SetVRegLong(first_dest_reg + to_arg_index, unboxed_value.GetJ());
246 to_arg_index += 2;
247 } else {
248 callee_frame->SetVReg(first_dest_reg + to_arg_index, unboxed_value.GetI());
249 ++to_arg_index;
250 }
251 }
252 }
253 }
254
255 return true;
256}
257
258} // namespace art
259
260#endif // ART_RUNTIME_METHOD_HANDLES_INL_H_