blob: ff5d2a1782b5d986897d839bdaf005287d44ce11 [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
Narayan Kamathda246502016-10-20 18:39:22 +010067REQUIRES_SHARED(Locks::mutator_lock_)
Narayan Kamath000e1882016-10-24 17:14:25 +010068inline bool ConvertJValue(Handle<mirror::Class> from,
69 Handle<mirror::Class> to,
70 const JValue& from_value,
71 JValue* to_value) {
Narayan Kamathda246502016-10-20 18:39:22 +010072 const Primitive::Type from_type = from->GetPrimitiveType();
73 const Primitive::Type to_type = to->GetPrimitiveType();
74
75 // This method must be called only when the types don't match.
76 DCHECK(from.Get() != to.Get());
77
78 if ((from_type != Primitive::kPrimNot) && (to_type != Primitive::kPrimNot)) {
79 // Throws a ClassCastException if we're unable to convert a primitive value.
80 return ConvertPrimitiveValue(false, from_type, to_type, from_value, to_value);
81 } else if ((from_type == Primitive::kPrimNot) && (to_type == Primitive::kPrimNot)) {
82 // They're both reference types. If "from" is null, we can pass it
83 // through unchanged. If not, we must generate a cast exception if
84 // |to| is not assignable from the dynamic type of |ref|.
85 mirror::Object* const ref = from_value.GetL();
86 if (ref == nullptr || to->IsAssignableFrom(ref->GetClass())) {
87 to_value->SetL(ref);
88 return true;
89 } else {
90 ThrowClassCastException(to.Get(), ref->GetClass());
91 return false;
92 }
93 } else {
94 // Precisely one of the source or the destination are reference types.
95 // We must box or unbox.
96 if (to_type == Primitive::kPrimNot) {
97 // The target type is a reference, we must box.
98 Primitive::Type type;
99 // TODO(narayan): This is a CHECK for now. There might be a few corner cases
100 // here that we might not have handled yet. For exmple, if |to| is java/lang/Number;,
101 // we will need to box this "naturally".
102 CHECK(GetPrimitiveType(to.Get(), &type));
103 // First perform a primitive conversion to the unboxed equivalent of the target,
104 // if necessary. This should be for the rarer cases like (int->Long) etc.
105 if (UNLIKELY(from_type != type)) {
106 if (!ConvertPrimitiveValue(false, from_type, type, from_value, to_value)) {
107 return false;
108 }
109 } else {
110 *to_value = from_value;
111 }
112
113 // Then perform the actual boxing, and then set the reference.
114 ObjPtr<mirror::Object> boxed = BoxPrimitive(type, from_value);
115 to_value->SetL(boxed.Ptr());
116 return true;
117 } else {
118 // The target type is a primitive, we must unbox.
119 ObjPtr<mirror::Object> ref(from_value.GetL());
120
121 // Note that UnboxPrimitiveForResult already performs all of the type
122 // conversions that we want, based on |to|.
123 JValue unboxed_value;
124 return UnboxPrimitiveForResult(ref, to.Get(), to_value);
125 }
126 }
127
128 return true;
129}
130
Narayan Kamath000e1882016-10-24 17:14:25 +0100131template <typename G, typename S>
132bool PerformConversions(Thread* self,
133 Handle<mirror::ObjectArray<mirror::Class>> from_types,
134 Handle<mirror::ObjectArray<mirror::Class>> to_types,
135 G* getter,
136 S* setter,
137 int32_t num_conversions) {
138 StackHandleScope<2> hs(self);
139 MutableHandle<mirror::Class> from(hs.NewHandle<mirror::Class>(nullptr));
140 MutableHandle<mirror::Class> to(hs.NewHandle<mirror::Class>(nullptr));
141
142 for (int32_t i = 0; i < num_conversions; ++i) {
143 from.Assign(from_types->GetWithoutChecks(i));
144 to.Assign(to_types->GetWithoutChecks(i));
145
146 const Primitive::Type from_type = from->GetPrimitiveType();
147 const Primitive::Type to_type = to->GetPrimitiveType();
148
149 if (from.Get() == to.Get()) {
150 // Easy case - the types are identical. Nothing left to do except to pass
151 // the arguments along verbatim.
152 if (Primitive::Is64BitType(from_type)) {
153 setter->SetLong(getter->GetLong());
154 } else if (from_type == Primitive::kPrimNot) {
155 setter->SetReference(getter->GetReference());
156 } else {
157 setter->Set(getter->Get());
158 }
159
160 continue;
161 } else {
162 JValue from_value;
163 JValue to_value;
164
165 if (Primitive::Is64BitType(from_type)) {
166 from_value.SetJ(getter->GetLong());
167 } else if (from_type == Primitive::kPrimNot) {
168 from_value.SetL(getter->GetReference());
169 } else {
170 from_value.SetI(getter->Get());
171 }
172
173 if (!ConvertJValue(from, to, from_value, &to_value)) {
174 DCHECK(self->IsExceptionPending());
175 return false;
176 }
177
178 if (Primitive::Is64BitType(to_type)) {
179 setter->SetLong(to_value.GetJ());
180 } else if (to_type == Primitive::kPrimNot) {
181 setter->SetReference(to_value.GetL());
182 } else {
183 setter->Set(to_value.GetI());
184 }
185 }
186 }
187
188 return true;
189}
190
Narayan Kamath208f8572016-08-03 12:46:58 +0100191template <bool is_range>
Narayan Kamathc3b7f1a2016-10-19 11:05:04 +0100192bool ConvertAndCopyArgumentsFromCallerFrame(Thread* self,
193 Handle<mirror::MethodType> callsite_type,
194 Handle<mirror::MethodType> callee_type,
195 const ShadowFrame& caller_frame,
196 uint32_t first_src_reg,
197 uint32_t first_dest_reg,
198 const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
199 ShadowFrame* callee_frame) {
Narayan Kamath208f8572016-08-03 12:46:58 +0100200 StackHandleScope<4> hs(self);
201 Handle<mirror::ObjectArray<mirror::Class>> from_types(hs.NewHandle(callsite_type->GetPTypes()));
202 Handle<mirror::ObjectArray<mirror::Class>> to_types(hs.NewHandle(callee_type->GetPTypes()));
203
204 const int32_t num_method_params = from_types->GetLength();
205 if (to_types->GetLength() != num_method_params) {
206 ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
Narayan Kamath208f8572016-08-03 12:46:58 +0100207 return false;
208 }
209
Narayan Kamath000e1882016-10-24 17:14:25 +0100210 ShadowFrameGetter<is_range> getter(first_src_reg, arg, caller_frame);
211 ShadowFrameSetter setter(callee_frame, first_dest_reg);
Narayan Kamath208f8572016-08-03 12:46:58 +0100212
Narayan Kamath000e1882016-10-24 17:14:25 +0100213 return PerformConversions<ShadowFrameGetter<is_range>, ShadowFrameSetter>(self,
214 from_types,
215 to_types,
216 &getter,
217 &setter,
218 num_method_params);
Narayan Kamath208f8572016-08-03 12:46:58 +0100219}
220
Narayan Kamath208f8572016-08-03 12:46:58 +0100221} // namespace art
222
223#endif // ART_RUNTIME_METHOD_HANDLES_INL_H_