blob: ce39049e11723a01a573f3bcb04540f08cfe0a6b [file] [log] [blame]
Narayan Kamath000e1882016-10-24 17:14:25 +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#include "emulated_stack_frame.h"
18
19#include "class-inl.h"
Vladimir Markob4eb1b12018-05-24 11:09:38 +010020#include "class_root.h"
Narayan Kamath000e1882016-10-24 17:14:25 +010021#include "jvalue-inl.h"
Narayan Kamath000e1882016-10-24 17:14:25 +010022#include "method_handles-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070023#include "method_handles.h"
Narayan Kamath000e1882016-10-24 17:14:25 +010024#include "reflection-inl.h"
25
26namespace art {
27namespace mirror {
28
Narayan Kamath000e1882016-10-24 17:14:25 +010029// Calculates the size of a stack frame based on the size of its argument
30// types and return types.
31static void CalculateFrameAndReferencesSize(ObjPtr<mirror::ObjectArray<mirror::Class>> p_types,
32 ObjPtr<mirror::Class> r_type,
33 size_t* frame_size_out,
34 size_t* references_size_out)
35 REQUIRES_SHARED(Locks::mutator_lock_) {
36 const size_t length = p_types->GetLength();
37 size_t frame_size = 0;
38 size_t references_size = 0;
39 for (size_t i = 0; i < length; ++i) {
40 ObjPtr<mirror::Class> type = p_types->GetWithoutChecks(i);
41 const Primitive::Type primitive_type = type->GetPrimitiveType();
42 if (primitive_type == Primitive::kPrimNot) {
43 references_size++;
44 } else if (Primitive::Is64BitType(primitive_type)) {
45 frame_size += 8;
46 } else {
47 frame_size += 4;
48 }
49 }
50
51 const Primitive::Type return_type = r_type->GetPrimitiveType();
52 if (return_type == Primitive::kPrimNot) {
53 references_size++;
54 } else if (Primitive::Is64BitType(return_type)) {
55 frame_size += 8;
56 } else {
57 frame_size += 4;
58 }
59
60 (*frame_size_out) = frame_size;
61 (*references_size_out) = references_size;
62}
63
64// Allows for read or write access to an emulated stack frame. Each
65// accessor index has an associated index into the references / stack frame
66// arrays which is incremented on every read or write to the frame.
67//
68// This class is used in conjunction with PerformConversions, either as a setter
69// or as a getter.
70class EmulatedStackFrameAccessor {
71 public:
72 EmulatedStackFrameAccessor(Handle<mirror::ObjectArray<mirror::Object>> references,
73 Handle<mirror::ByteArray> stack_frame,
74 size_t stack_frame_size) :
75 references_(references),
76 stack_frame_(stack_frame),
77 stack_frame_size_(stack_frame_size),
78 reference_idx_(0u),
79 stack_frame_idx_(0u) {
80 }
81
82 ALWAYS_INLINE void SetReference(ObjPtr<mirror::Object> reference)
83 REQUIRES_SHARED(Locks::mutator_lock_) {
84 references_->Set(reference_idx_++, reference);
85 }
86
87 ALWAYS_INLINE void Set(const uint32_t value) REQUIRES_SHARED(Locks::mutator_lock_) {
88 int8_t* array = stack_frame_->GetData();
89
90 CHECK_LE((stack_frame_idx_ + 4u), stack_frame_size_);
91 memcpy(array + stack_frame_idx_, &value, sizeof(uint32_t));
92 stack_frame_idx_ += 4u;
93 }
94
95 ALWAYS_INLINE void SetLong(const int64_t value) REQUIRES_SHARED(Locks::mutator_lock_) {
96 int8_t* array = stack_frame_->GetData();
97
98 CHECK_LE((stack_frame_idx_ + 8u), stack_frame_size_);
99 memcpy(array + stack_frame_idx_, &value, sizeof(int64_t));
100 stack_frame_idx_ += 8u;
101 }
102
103 ALWAYS_INLINE ObjPtr<mirror::Object> GetReference() REQUIRES_SHARED(Locks::mutator_lock_) {
104 return ObjPtr<mirror::Object>(references_->Get(reference_idx_++));
105 }
106
107 ALWAYS_INLINE uint32_t Get() REQUIRES_SHARED(Locks::mutator_lock_) {
108 const int8_t* array = stack_frame_->GetData();
109
110 CHECK_LE((stack_frame_idx_ + 4u), stack_frame_size_);
111 uint32_t val = 0;
112
113 memcpy(&val, array + stack_frame_idx_, sizeof(uint32_t));
114 stack_frame_idx_ += 4u;
115 return val;
116 }
117
118 ALWAYS_INLINE int64_t GetLong() REQUIRES_SHARED(Locks::mutator_lock_) {
119 const int8_t* array = stack_frame_->GetData();
120
121 CHECK_LE((stack_frame_idx_ + 8u), stack_frame_size_);
122 int64_t val = 0;
123
124 memcpy(&val, array + stack_frame_idx_, sizeof(int64_t));
125 stack_frame_idx_ += 8u;
126 return val;
127 }
128
129 private:
130 Handle<mirror::ObjectArray<mirror::Object>> references_;
131 Handle<mirror::ByteArray> stack_frame_;
132 const size_t stack_frame_size_;
133
134 size_t reference_idx_;
135 size_t stack_frame_idx_;
136
137 DISALLOW_COPY_AND_ASSIGN(EmulatedStackFrameAccessor);
138};
139
Narayan Kamath000e1882016-10-24 17:14:25 +0100140mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs(
141 Thread* self,
142 Handle<mirror::MethodType> caller_type,
143 Handle<mirror::MethodType> callee_type,
144 const ShadowFrame& caller_frame,
Orion Hodson960d4f72017-11-10 15:32:38 +0000145 const InstructionOperands* const operands) {
Narayan Kamath000e1882016-10-24 17:14:25 +0100146 StackHandleScope<6> hs(self);
147
148 // Step 1: We must throw a WrongMethodTypeException if there's a mismatch in the
149 // number of arguments between the caller and the callsite.
150 Handle<mirror::ObjectArray<mirror::Class>> from_types(hs.NewHandle(caller_type->GetPTypes()));
151 Handle<mirror::ObjectArray<mirror::Class>> to_types(hs.NewHandle(callee_type->GetPTypes()));
152
153 const int32_t num_method_params = from_types->GetLength();
154 if (to_types->GetLength() != num_method_params) {
155 ThrowWrongMethodTypeException(callee_type.Get(), caller_type.Get());
156 return nullptr;
157 }
158
159 // Step 2: Calculate the size of the reference / byte arrays in the emulated
160 // stack frame.
161 size_t frame_size = 0;
162 size_t refs_size = 0;
163 Handle<mirror::Class> r_type(hs.NewHandle(callee_type->GetRType()));
164 CalculateFrameAndReferencesSize(to_types.Get(), r_type.Get(), &frame_size, &refs_size);
165
166 // Step 3 : Allocate the arrays.
Vladimir Markob4eb1b12018-05-24 11:09:38 +0100167 ObjPtr<mirror::Class> array_class(GetClassRoot<mirror::ObjectArray<mirror::Object>>());
Narayan Kamath000e1882016-10-24 17:14:25 +0100168
169 Handle<mirror::ObjectArray<mirror::Object>> references(hs.NewHandle(
170 mirror::ObjectArray<mirror::Object>::Alloc(self, array_class, refs_size)));
Andreas Gampefa4333d2017-02-14 11:10:34 -0800171 if (references == nullptr) {
Narayan Kamath2cb856c2016-11-02 12:01:26 +0000172 DCHECK(self->IsExceptionPending());
173 return nullptr;
174 }
175
Narayan Kamath000e1882016-10-24 17:14:25 +0100176 Handle<ByteArray> stack_frame(hs.NewHandle(ByteArray::Alloc(self, frame_size)));
Andreas Gampefa4333d2017-02-14 11:10:34 -0800177 if (stack_frame == nullptr) {
Narayan Kamath2cb856c2016-11-02 12:01:26 +0000178 DCHECK(self->IsExceptionPending());
179 return nullptr;
180 }
Narayan Kamath000e1882016-10-24 17:14:25 +0100181
182 // Step 4 : Perform argument conversions (if required).
Orion Hodson928033d2018-02-07 05:30:54 +0000183 ShadowFrameGetter getter(caller_frame, operands);
Narayan Kamath000e1882016-10-24 17:14:25 +0100184 EmulatedStackFrameAccessor setter(references, stack_frame, stack_frame->GetLength());
Orion Hodson960d4f72017-11-10 15:32:38 +0000185 if (!PerformConversions<ShadowFrameGetter, EmulatedStackFrameAccessor>(
Orion Hodsonba28f9f2016-10-26 10:56:25 +0100186 self, caller_type, callee_type, &getter, &setter, num_method_params)) {
Narayan Kamath000e1882016-10-24 17:14:25 +0100187 return nullptr;
188 }
189
190 // Step 5: Construct the EmulatedStackFrame object.
191 Handle<EmulatedStackFrame> sf(hs.NewHandle(
Vladimir Markoadbceb72018-05-29 14:34:14 +0100192 ObjPtr<EmulatedStackFrame>::DownCast(GetClassRoot<EmulatedStackFrame>()->AllocObject(self))));
Narayan Kamathb79bbd82017-01-16 17:48:28 +0000193 sf->SetFieldObject<false>(CallsiteTypeOffset(), caller_type.Get());
Narayan Kamath000e1882016-10-24 17:14:25 +0100194 sf->SetFieldObject<false>(TypeOffset(), callee_type.Get());
195 sf->SetFieldObject<false>(ReferencesOffset(), references.Get());
196 sf->SetFieldObject<false>(StackFrameOffset(), stack_frame.Get());
197
198 return sf.Get();
199}
200
201bool EmulatedStackFrame::WriteToShadowFrame(Thread* self,
202 Handle<mirror::MethodType> callee_type,
203 const uint32_t first_dest_reg,
204 ShadowFrame* callee_frame) {
Orion Hodsonba28f9f2016-10-26 10:56:25 +0100205 ObjPtr<mirror::ObjectArray<mirror::Class>> from_types(GetType()->GetPTypes());
206 ObjPtr<mirror::ObjectArray<mirror::Class>> to_types(callee_type->GetPTypes());
Narayan Kamath000e1882016-10-24 17:14:25 +0100207
208 const int32_t num_method_params = from_types->GetLength();
209 if (to_types->GetLength() != num_method_params) {
210 ThrowWrongMethodTypeException(callee_type.Get(), GetType());
211 return false;
212 }
213
Orion Hodsonba28f9f2016-10-26 10:56:25 +0100214 StackHandleScope<3> hs(self);
215 Handle<mirror::MethodType> frame_callsite_type(hs.NewHandle(GetType()));
Narayan Kamath000e1882016-10-24 17:14:25 +0100216 Handle<mirror::ObjectArray<mirror::Object>> references(hs.NewHandle(GetReferences()));
217 Handle<ByteArray> stack_frame(hs.NewHandle(GetStackFrame()));
218
219 EmulatedStackFrameAccessor getter(references, stack_frame, stack_frame->GetLength());
220 ShadowFrameSetter setter(callee_frame, first_dest_reg);
221
222 return PerformConversions<EmulatedStackFrameAccessor, ShadowFrameSetter>(
Orion Hodsonba28f9f2016-10-26 10:56:25 +0100223 self, frame_callsite_type, callee_type, &getter, &setter, num_method_params);
Narayan Kamath000e1882016-10-24 17:14:25 +0100224}
225
226void EmulatedStackFrame::GetReturnValue(Thread* self, JValue* value) {
227 StackHandleScope<2> hs(self);
228 Handle<mirror::Class> r_type(hs.NewHandle(GetType()->GetRType()));
229
230 const Primitive::Type type = r_type->GetPrimitiveType();
231 if (type == Primitive::kPrimNot) {
232 Handle<mirror::ObjectArray<mirror::Object>> references(hs.NewHandle(GetReferences()));
233 value->SetL(references->GetWithoutChecks(references->GetLength() - 1));
234 } else {
235 Handle<ByteArray> stack_frame(hs.NewHandle(GetStackFrame()));
236 const int8_t* array = stack_frame->GetData();
237 const size_t length = stack_frame->GetLength();
238 if (Primitive::Is64BitType(type)) {
239 int64_t primitive = 0;
240 memcpy(&primitive, array + length - sizeof(int64_t), sizeof(int64_t));
241 value->SetJ(primitive);
242 } else {
243 uint32_t primitive = 0;
244 memcpy(&primitive, array + length - sizeof(uint32_t), sizeof(uint32_t));
245 value->SetI(primitive);
246 }
247 }
248}
249
250void EmulatedStackFrame::SetReturnValue(Thread* self, const JValue& value) {
251 StackHandleScope<2> hs(self);
252 Handle<mirror::Class> r_type(hs.NewHandle(GetType()->GetRType()));
253
254 const Primitive::Type type = r_type->GetPrimitiveType();
255 if (type == Primitive::kPrimNot) {
256 Handle<mirror::ObjectArray<mirror::Object>> references(hs.NewHandle(GetReferences()));
257 references->SetWithoutChecks<false>(references->GetLength() - 1, value.GetL());
258 } else {
259 Handle<ByteArray> stack_frame(hs.NewHandle(GetStackFrame()));
260 int8_t* array = stack_frame->GetData();
261 const size_t length = stack_frame->GetLength();
262 if (Primitive::Is64BitType(type)) {
263 const int64_t primitive = value.GetJ();
264 memcpy(array + length - sizeof(int64_t), &primitive, sizeof(int64_t));
265 } else {
266 const uint32_t primitive = value.GetI();
267 memcpy(array + length - sizeof(uint32_t), &primitive, sizeof(uint32_t));
268 }
269 }
270}
271
Narayan Kamath000e1882016-10-24 17:14:25 +0100272} // namespace mirror
273} // namespace art