blob: e8f738d4d762a2115866b3e93d008422a6744a12 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 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 */
Ian Rogersb033c752011-07-20 12:22:35 -070016
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
18#define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
Ian Rogersb033c752011-07-20 12:22:35 -070019
Vladimir Markod1ee8092016-04-13 11:59:46 +010020#include "base/arena_object.h"
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070021#include "handle_scope.h"
Ian Rogerse63db272014-07-15 15:36:11 -070022#include "primitive.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070023#include "thread.h"
Vladimir Marko1cd1b032016-05-19 10:37:24 +010024#include "utils/array_ref.h"
Ian Rogers166db042013-07-26 12:05:57 -070025#include "utils/managed_register.h"
Ian Rogersb033c752011-07-20 12:22:35 -070026
27namespace art {
28
Ian Rogers790a6b72014-04-01 10:36:00 -070029// Top-level abstraction for different calling conventions.
Vladimir Markod1ee8092016-04-13 11:59:46 +010030class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConvention> {
Ian Rogersb033c752011-07-20 12:22:35 -070031 public:
Ian Rogers169c9a72011-11-13 20:13:17 -080032 bool IsReturnAReference() const { return shorty_[0] == 'L'; }
Ian Rogersb033c752011-07-20 12:22:35 -070033
jeffhao58136ca2012-05-24 13:40:11 -070034 Primitive::Type GetReturnType() const {
35 return Primitive::GetType(shorty_[0]);
36 }
37
Ian Rogers169c9a72011-11-13 20:13:17 -080038 size_t SizeOfReturnValue() const {
39 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
40 if (result >= 1 && result < 4) {
41 result = 4;
42 }
43 return result;
44 }
Ian Rogersdf20fe02011-07-20 20:34:16 -070045
Ian Rogers00f7d0e2012-07-19 15:28:27 -070046 // Register that holds result of this method invocation.
Ian Rogers2c8f6532011-09-02 17:16:34 -070047 virtual ManagedRegister ReturnRegister() = 0;
Ian Rogers00f7d0e2012-07-19 15:28:27 -070048 // Register reserved for scratch usage during procedure calls.
Ian Rogers2c8f6532011-09-02 17:16:34 -070049 virtual ManagedRegister InterproceduralScratchRegister() = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070050
Ian Rogers790a6b72014-04-01 10:36:00 -070051 // Offset of Method within the frame.
52 FrameOffset MethodStackOffset() {
53 return displacement_;
54 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070055
Ian Rogersb033c752011-07-20 12:22:35 -070056 // Iterator interface
57
58 // Place iterator at start of arguments. The displacement is applied to
59 // frame offset methods to account for frames which may be on the stack
60 // below the one being iterated over.
61 void ResetIterator(FrameOffset displacement) {
62 displacement_ = displacement;
Shih-wei Liao5381cf92011-07-27 00:28:04 -070063 itr_slots_ = 0;
64 itr_args_ = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070065 itr_refs_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070066 itr_longs_and_doubles_ = 0;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070067 itr_float_and_doubles_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070068 }
69
Ian Rogers2c8f6532011-09-02 17:16:34 -070070 virtual ~CallingConvention() {}
71
Ian Rogersb033c752011-07-20 12:22:35 -070072 protected:
Ian Rogers790a6b72014-04-01 10:36:00 -070073 CallingConvention(bool is_static, bool is_synchronized, const char* shorty,
74 size_t frame_pointer_size)
75 : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
76 itr_float_and_doubles_(0), displacement_(0),
77 frame_pointer_size_(frame_pointer_size),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070078 handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
Ian Rogers790a6b72014-04-01 10:36:00 -070079 is_static_(is_static), is_synchronized_(is_synchronized),
Ian Rogers169c9a72011-11-13 20:13:17 -080080 shorty_(shorty) {
81 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
82 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070083 num_float_or_double_args_ = 0;
Ian Rogers169c9a72011-11-13 20:13:17 -080084 num_long_or_double_args_ = 0;
85 for (size_t i = 1; i < strlen(shorty); i++) {
86 char ch = shorty_[i];
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070087 switch (ch) {
88 case 'L':
Ian Rogers169c9a72011-11-13 20:13:17 -080089 num_ref_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070090 break;
91 case 'J':
Ian Rogers169c9a72011-11-13 20:13:17 -080092 num_long_or_double_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070093 break;
94 case 'D':
95 num_long_or_double_args_++;
96 num_float_or_double_args_++;
97 break;
98 case 'F':
99 num_float_or_double_args_++;
100 break;
Ian Rogers169c9a72011-11-13 20:13:17 -0800101 }
102 }
103 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700104
Ian Rogers169c9a72011-11-13 20:13:17 -0800105 bool IsStatic() const {
106 return is_static_;
107 }
108 bool IsSynchronized() const {
109 return is_synchronized_;
110 }
111 bool IsParamALongOrDouble(unsigned int param) const {
112 DCHECK_LT(param, NumArgs());
113 if (IsStatic()) {
114 param++; // 0th argument must skip return value at start of the shorty
115 } else if (param == 0) {
116 return false; // this argument
117 }
118 char ch = shorty_[param];
119 return (ch == 'J' || ch == 'D');
120 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700121 bool IsParamAFloatOrDouble(unsigned int param) const {
122 DCHECK_LT(param, NumArgs());
123 if (IsStatic()) {
124 param++; // 0th argument must skip return value at start of the shorty
125 } else if (param == 0) {
126 return false; // this argument
127 }
128 char ch = shorty_[param];
129 return (ch == 'F' || ch == 'D');
130 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100131 bool IsParamADouble(unsigned int param) const {
132 DCHECK_LT(param, NumArgs());
133 if (IsStatic()) {
134 param++; // 0th argument must skip return value at start of the shorty
135 } else if (param == 0) {
136 return false; // this argument
137 }
138 return shorty_[param] == 'D';
139 }
140 bool IsParamALong(unsigned int param) const {
141 DCHECK_LT(param, NumArgs());
142 if (IsStatic()) {
143 param++; // 0th argument must skip return value at start of the shorty
144 } else if (param == 0) {
Mark Mendell3e6a3bf2015-01-19 14:09:22 -0500145 return false; // this argument
Serban Constantinescu75b91132014-04-09 18:39:10 +0100146 }
147 return shorty_[param] == 'J';
148 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800149 bool IsParamAReference(unsigned int param) const {
150 DCHECK_LT(param, NumArgs());
151 if (IsStatic()) {
152 param++; // 0th argument must skip return value at start of the shorty
153 } else if (param == 0) {
154 return true; // this argument
155 }
156 return shorty_[param] == 'L';
Ian Rogers169c9a72011-11-13 20:13:17 -0800157 }
158 size_t NumArgs() const {
159 return num_args_;
160 }
161 size_t NumLongOrDoubleArgs() const {
162 return num_long_or_double_args_;
163 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700164 size_t NumFloatOrDoubleArgs() const {
165 return num_float_or_double_args_;
166 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800167 size_t NumReferenceArgs() const {
168 return num_ref_args_;
169 }
170 size_t ParamSize(unsigned int param) const {
171 DCHECK_LT(param, NumArgs());
172 if (IsStatic()) {
173 param++; // 0th argument must skip return value at start of the shorty
174 } else if (param == 0) {
Mathieu Chartiere401d142015-04-22 13:56:20 -0700175 return sizeof(mirror::HeapReference<mirror::Object>); // this argument
Ian Rogers169c9a72011-11-13 20:13:17 -0800176 }
177 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
178 if (result >= 1 && result < 4) {
179 result = 4;
180 }
181 return result;
182 }
183 const char* GetShorty() const {
184 return shorty_.c_str();
185 }
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700186 // The slot number for current calling_convention argument.
187 // Note that each slot is 32-bit. When the current argument is bigger
188 // than 32 bits, return the first slot number for this argument.
189 unsigned int itr_slots_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700190 // The number of references iterated past.
Ian Rogers7a99c112011-09-07 12:48:27 -0700191 unsigned int itr_refs_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700192 // The argument number along argument list for current argument.
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700193 unsigned int itr_args_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700194 // Number of longs and doubles seen along argument list.
Ian Rogersb033c752011-07-20 12:22:35 -0700195 unsigned int itr_longs_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700196 // Number of float and doubles seen along argument list.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700197 unsigned int itr_float_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700198 // Space for frames below this on the stack.
Ian Rogersb033c752011-07-20 12:22:35 -0700199 FrameOffset displacement_;
Mathieu Chartiere401d142015-04-22 13:56:20 -0700200 // The size of a pointer.
Ian Rogers790a6b72014-04-01 10:36:00 -0700201 const size_t frame_pointer_size_;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700202 // The size of a reference entry within the handle scope.
203 const size_t handle_scope_pointer_size_;
Ian Rogersb033c752011-07-20 12:22:35 -0700204
205 private:
Ian Rogers169c9a72011-11-13 20:13:17 -0800206 const bool is_static_;
207 const bool is_synchronized_;
208 std::string shorty_;
209 size_t num_args_;
210 size_t num_ref_args_;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700211 size_t num_float_or_double_args_;
Ian Rogers169c9a72011-11-13 20:13:17 -0800212 size_t num_long_or_double_args_;
Ian Rogersb033c752011-07-20 12:22:35 -0700213};
214
215// Abstraction for managed code's calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700216// | { Incoming stack args } |
217// | { Prior Method* } | <-- Prior SP
218// | { Return address } |
219// | { Callee saves } |
220// | { Spills ... } |
221// | { Outgoing stack args } |
222// | { Method* } | <-- SP
Ian Rogersb033c752011-07-20 12:22:35 -0700223class ManagedRuntimeCallingConvention : public CallingConvention {
224 public:
Vladimir Markod1ee8092016-04-13 11:59:46 +0100225 static std::unique_ptr<ManagedRuntimeCallingConvention> Create(ArenaAllocator* arena,
226 bool is_static,
227 bool is_synchronized,
228 const char* shorty,
229 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700230
Ian Rogers2c8f6532011-09-02 17:16:34 -0700231 // Register that holds the incoming method argument
232 virtual ManagedRegister MethodRegister() = 0;
233
Ian Rogersb033c752011-07-20 12:22:35 -0700234 // Iterator interface
235 bool HasNext();
236 void Next();
237 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700238 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100239 bool IsCurrentParamADouble();
240 bool IsCurrentParamALong();
Ian Rogers7a99c112011-09-07 12:48:27 -0700241 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
242 bool IsCurrentArgPossiblyNull();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700243 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700244 virtual bool IsCurrentParamInRegister() = 0;
245 virtual bool IsCurrentParamOnStack() = 0;
246 virtual ManagedRegister CurrentParamRegister() = 0;
247 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700248
Ian Rogers2c8f6532011-09-02 17:16:34 -0700249 virtual ~ManagedRuntimeCallingConvention() {}
250
Ian Rogersb5d09b22012-03-06 22:14:17 -0800251 // Registers to spill to caller's out registers on entry.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700252 virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800253
Ian Rogers2c8f6532011-09-02 17:16:34 -0700254 protected:
Vladimir Markod1ee8092016-04-13 11:59:46 +0100255 ManagedRuntimeCallingConvention(bool is_static,
256 bool is_synchronized,
257 const char* shorty,
Ian Rogers790a6b72014-04-01 10:36:00 -0700258 size_t frame_pointer_size)
259 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogersb033c752011-07-20 12:22:35 -0700260};
261
262// Abstraction for JNI calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700263// | { Incoming stack args } | <-- Prior SP
264// | { Return address } |
265// | { Callee saves } | ([1])
266// | { Return value spill } | (live on return slow paths)
Ian Rogersdc51b792011-09-22 20:41:37 -0700267// | { Local Ref. Table State } |
Ian Rogersbdb03912011-09-14 00:55:44 -0700268// | { Stack Indirect Ref. Table |
269// | num. refs./link } | (here to prior SP is frame size)
270// | { Method* } | <-- Anchor SP written to thread
271// | { Outgoing stack args } | <-- SP at point of call
272// | Native frame |
273//
274// [1] We must save all callee saves here to enable any exception throws to restore
275// callee saves for frames above this one.
Ian Rogersb033c752011-07-20 12:22:35 -0700276class JniCallingConvention : public CallingConvention {
277 public:
Vladimir Markod1ee8092016-04-13 11:59:46 +0100278 static std::unique_ptr<JniCallingConvention> Create(ArenaAllocator* arena,
279 bool is_static,
280 bool is_synchronized,
281 const char* shorty,
282 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700283
284 // Size of frame excluding space for outgoing args (its assumed Method* is
285 // always at the bottom of a frame, but this doesn't work for outgoing
286 // native args). Includes alignment.
Ian Rogers2c8f6532011-09-02 17:16:34 -0700287 virtual size_t FrameSize() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700288 // Size of outgoing arguments, including alignment
Ian Rogers2c8f6532011-09-02 17:16:34 -0700289 virtual size_t OutArgSize() = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700290 // Number of references in stack indirect reference table
Ian Rogersdc51b792011-09-22 20:41:37 -0700291 size_t ReferenceCount() const;
292 // Location where the segment state of the local indirect reference table is saved
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700293 FrameOffset SavedLocalReferenceCookieOffset() const;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700294 // Location where the return value of a call can be squirreled if another
295 // call is made following the native call
Ian Rogersdc51b792011-09-22 20:41:37 -0700296 FrameOffset ReturnValueSaveLocation() const;
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700297 // Register that holds result if it is integer.
298 virtual ManagedRegister IntReturnRegister() = 0;
Andreas Gamped1104322014-05-01 14:38:56 -0700299 // Whether the compiler needs to ensure zero-/sign-extension of a small result type
300 virtual bool RequiresSmallResultTypeExtension() const = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700301
Ian Rogersbdb03912011-09-14 00:55:44 -0700302 // Callee save registers to spill prior to native code (which may clobber)
Vladimir Marko1cd1b032016-05-19 10:37:24 +0100303 virtual ArrayRef<const ManagedRegister> CalleeSaveRegisters() const = 0;
Ian Rogersbdb03912011-09-14 00:55:44 -0700304
305 // Spill mask values
306 virtual uint32_t CoreSpillMask() const = 0;
307 virtual uint32_t FpSpillMask() const = 0;
Ian Rogers0d666d82011-08-14 16:03:46 -0700308
Ian Rogersdc51b792011-09-22 20:41:37 -0700309 // An extra scratch register live after the call
310 virtual ManagedRegister ReturnScratchRegister() const = 0;
311
Ian Rogersb033c752011-07-20 12:22:35 -0700312 // Iterator interface
313 bool HasNext();
Ian Rogers67375ac2011-09-14 00:55:44 -0700314 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700315 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700316 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100317 bool IsCurrentParamADouble();
318 bool IsCurrentParamALong();
319 bool IsCurrentParamJniEnv();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700320 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700321 virtual bool IsCurrentParamInRegister() = 0;
322 virtual bool IsCurrentParamOnStack() = 0;
323 virtual ManagedRegister CurrentParamRegister() = 0;
324 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700325
326 // Iterator interface extension for JNI
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700327 FrameOffset CurrentParamHandleScopeEntryOffset();
Ian Rogersb033c752011-07-20 12:22:35 -0700328
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700329 // Position of handle scope and interior fields
330 FrameOffset HandleScopeOffset() const {
Mathieu Chartiere401d142015-04-22 13:56:20 -0700331 return FrameOffset(this->displacement_.Int32Value() + frame_pointer_size_);
Andreas Gampecf4035a2014-05-28 22:43:01 -0700332 // above Method reference
Ian Rogersb033c752011-07-20 12:22:35 -0700333 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700334
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700335 FrameOffset HandleScopeLinkOffset() const {
Mathieu Chartiere401d142015-04-22 13:56:20 -0700336 return FrameOffset(HandleScopeOffset().Int32Value() +
337 HandleScope::LinkOffset(frame_pointer_size_));
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700338 }
339
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700340 FrameOffset HandleScopeNumRefsOffset() const {
341 return FrameOffset(HandleScopeOffset().Int32Value() +
342 HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700343 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700344
Mathieu Chartiere401d142015-04-22 13:56:20 -0700345 FrameOffset HandleReferencesOffset() const {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700346 return FrameOffset(HandleScopeOffset().Int32Value() +
347 HandleScope::ReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700348 }
349
Ian Rogers2c8f6532011-09-02 17:16:34 -0700350 virtual ~JniCallingConvention() {}
351
352 protected:
Ian Rogersb033c752011-07-20 12:22:35 -0700353 // Named iterator positions
354 enum IteratorPos {
355 kJniEnv = 0,
356 kObjectOrClass = 1
357 };
358
Roland Levillain3887c462015-08-12 18:15:42 +0100359 JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
360 size_t frame_pointer_size)
Ian Rogers790a6b72014-04-01 10:36:00 -0700361 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700362
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700363 // Number of stack slots for outgoing arguments, above which the handle scope is
Ian Rogersb033c752011-07-20 12:22:35 -0700364 // located
Ian Rogers2c8f6532011-09-02 17:16:34 -0700365 virtual size_t NumberOfOutgoingStackArgs() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700366
Ian Rogers2c8f6532011-09-02 17:16:34 -0700367 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800368 size_t NumberOfExtraArgumentsForJni();
Ian Rogersb033c752011-07-20 12:22:35 -0700369};
370
371} // namespace art
372
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700373#endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_