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