blob: 6db0c3b8b3abe11cef9ad87fa6d68bfaa6653cee [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
Ian Rogers0d666d82011-08-14 16:03:46 -070020#include <vector>
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"
Ian Rogers166db042013-07-26 12:05:57 -070024#include "utils/managed_register.h"
Ian Rogersb033c752011-07-20 12:22:35 -070025
26namespace art {
27
Ian Rogers790a6b72014-04-01 10:36:00 -070028// Top-level abstraction for different calling conventions.
Ian Rogersb033c752011-07-20 12:22:35 -070029class CallingConvention {
30 public:
Ian Rogers169c9a72011-11-13 20:13:17 -080031 bool IsReturnAReference() const { return shorty_[0] == 'L'; }
Ian Rogersb033c752011-07-20 12:22:35 -070032
jeffhao58136ca2012-05-24 13:40:11 -070033 Primitive::Type GetReturnType() const {
34 return Primitive::GetType(shorty_[0]);
35 }
36
Ian Rogers169c9a72011-11-13 20:13:17 -080037 size_t SizeOfReturnValue() const {
38 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
39 if (result >= 1 && result < 4) {
40 result = 4;
41 }
42 return result;
43 }
Ian Rogersdf20fe02011-07-20 20:34:16 -070044
Ian Rogers00f7d0e2012-07-19 15:28:27 -070045 // Register that holds result of this method invocation.
Ian Rogers2c8f6532011-09-02 17:16:34 -070046 virtual ManagedRegister ReturnRegister() = 0;
Ian Rogers00f7d0e2012-07-19 15:28:27 -070047 // Register reserved for scratch usage during procedure calls.
Ian Rogers2c8f6532011-09-02 17:16:34 -070048 virtual ManagedRegister InterproceduralScratchRegister() = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070049
Ian Rogers790a6b72014-04-01 10:36:00 -070050 // Offset of Method within the frame.
51 FrameOffset MethodStackOffset() {
52 return displacement_;
53 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070054
Ian Rogersb033c752011-07-20 12:22:35 -070055 // Iterator interface
56
57 // Place iterator at start of arguments. The displacement is applied to
58 // frame offset methods to account for frames which may be on the stack
59 // below the one being iterated over.
60 void ResetIterator(FrameOffset displacement) {
61 displacement_ = displacement;
Shih-wei Liao5381cf92011-07-27 00:28:04 -070062 itr_slots_ = 0;
63 itr_args_ = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070064 itr_refs_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070065 itr_longs_and_doubles_ = 0;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070066 itr_float_and_doubles_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070067 }
68
Ian Rogers2c8f6532011-09-02 17:16:34 -070069 virtual ~CallingConvention() {}
70
Ian Rogersb033c752011-07-20 12:22:35 -070071 protected:
Ian Rogers790a6b72014-04-01 10:36:00 -070072 CallingConvention(bool is_static, bool is_synchronized, const char* shorty,
73 size_t frame_pointer_size)
74 : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
75 itr_float_and_doubles_(0), displacement_(0),
76 frame_pointer_size_(frame_pointer_size),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070077 handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
Ian Rogers790a6b72014-04-01 10:36:00 -070078 is_static_(is_static), is_synchronized_(is_synchronized),
Ian Rogers169c9a72011-11-13 20:13:17 -080079 shorty_(shorty) {
80 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
81 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070082 num_float_or_double_args_ = 0;
Ian Rogers169c9a72011-11-13 20:13:17 -080083 num_long_or_double_args_ = 0;
84 for (size_t i = 1; i < strlen(shorty); i++) {
85 char ch = shorty_[i];
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070086 switch (ch) {
87 case 'L':
Ian Rogers169c9a72011-11-13 20:13:17 -080088 num_ref_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070089 break;
90 case 'J':
Ian Rogers169c9a72011-11-13 20:13:17 -080091 num_long_or_double_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070092 break;
93 case 'D':
94 num_long_or_double_args_++;
95 num_float_or_double_args_++;
96 break;
97 case 'F':
98 num_float_or_double_args_++;
99 break;
Ian Rogers169c9a72011-11-13 20:13:17 -0800100 }
101 }
102 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700103
Ian Rogers169c9a72011-11-13 20:13:17 -0800104 bool IsStatic() const {
105 return is_static_;
106 }
107 bool IsSynchronized() const {
108 return is_synchronized_;
109 }
110 bool IsParamALongOrDouble(unsigned int param) const {
111 DCHECK_LT(param, NumArgs());
112 if (IsStatic()) {
113 param++; // 0th argument must skip return value at start of the shorty
114 } else if (param == 0) {
115 return false; // this argument
116 }
117 char ch = shorty_[param];
118 return (ch == 'J' || ch == 'D');
119 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700120 bool IsParamAFloatOrDouble(unsigned int param) const {
121 DCHECK_LT(param, NumArgs());
122 if (IsStatic()) {
123 param++; // 0th argument must skip return value at start of the shorty
124 } else if (param == 0) {
125 return false; // this argument
126 }
127 char ch = shorty_[param];
128 return (ch == 'F' || ch == 'D');
129 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100130 bool IsParamADouble(unsigned int param) const {
131 DCHECK_LT(param, NumArgs());
132 if (IsStatic()) {
133 param++; // 0th argument must skip return value at start of the shorty
134 } else if (param == 0) {
135 return false; // this argument
136 }
137 return shorty_[param] == 'D';
138 }
139 bool IsParamALong(unsigned int param) const {
140 DCHECK_LT(param, NumArgs());
141 if (IsStatic()) {
142 param++; // 0th argument must skip return value at start of the shorty
143 } else if (param == 0) {
144 return true; // this argument
145 }
146 return shorty_[param] == 'J';
147 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800148 bool IsParamAReference(unsigned int param) const {
149 DCHECK_LT(param, NumArgs());
150 if (IsStatic()) {
151 param++; // 0th argument must skip return value at start of the shorty
152 } else if (param == 0) {
153 return true; // this argument
154 }
155 return shorty_[param] == 'L';
Ian Rogers169c9a72011-11-13 20:13:17 -0800156 }
157 size_t NumArgs() const {
158 return num_args_;
159 }
160 size_t NumLongOrDoubleArgs() const {
161 return num_long_or_double_args_;
162 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700163 size_t NumFloatOrDoubleArgs() const {
164 return num_float_or_double_args_;
165 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800166 size_t NumReferenceArgs() const {
167 return num_ref_args_;
168 }
169 size_t ParamSize(unsigned int param) const {
170 DCHECK_LT(param, NumArgs());
171 if (IsStatic()) {
172 param++; // 0th argument must skip return value at start of the shorty
173 } else if (param == 0) {
Ian Rogers790a6b72014-04-01 10:36:00 -0700174 return frame_pointer_size_; // this argument
Ian Rogers169c9a72011-11-13 20:13:17 -0800175 }
176 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
177 if (result >= 1 && result < 4) {
178 result = 4;
179 }
180 return result;
181 }
182 const char* GetShorty() const {
183 return shorty_.c_str();
184 }
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700185 // The slot number for current calling_convention argument.
186 // Note that each slot is 32-bit. When the current argument is bigger
187 // than 32 bits, return the first slot number for this argument.
188 unsigned int itr_slots_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700189 // The number of references iterated past.
Ian Rogers7a99c112011-09-07 12:48:27 -0700190 unsigned int itr_refs_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700191 // The argument number along argument list for current argument.
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700192 unsigned int itr_args_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700193 // Number of longs and doubles seen along argument list.
Ian Rogersb033c752011-07-20 12:22:35 -0700194 unsigned int itr_longs_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700195 // Number of float and doubles seen along argument list.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700196 unsigned int itr_float_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700197 // Space for frames below this on the stack.
Ian Rogersb033c752011-07-20 12:22:35 -0700198 FrameOffset displacement_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700199 // The size of a reference.
200 const size_t frame_pointer_size_;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700201 // The size of a reference entry within the handle scope.
202 const size_t handle_scope_pointer_size_;
Ian Rogersb033c752011-07-20 12:22:35 -0700203
204 private:
Ian Rogers169c9a72011-11-13 20:13:17 -0800205 const bool is_static_;
206 const bool is_synchronized_;
207 std::string shorty_;
208 size_t num_args_;
209 size_t num_ref_args_;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700210 size_t num_float_or_double_args_;
Ian Rogers169c9a72011-11-13 20:13:17 -0800211 size_t num_long_or_double_args_;
Ian Rogersb033c752011-07-20 12:22:35 -0700212};
213
214// Abstraction for managed code's calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700215// | { Incoming stack args } |
216// | { Prior Method* } | <-- Prior SP
217// | { Return address } |
218// | { Callee saves } |
219// | { Spills ... } |
220// | { Outgoing stack args } |
221// | { Method* } | <-- SP
Ian Rogersb033c752011-07-20 12:22:35 -0700222class ManagedRuntimeCallingConvention : public CallingConvention {
223 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800224 static ManagedRuntimeCallingConvention* Create(bool is_static, bool is_synchronized,
225 const char* shorty,
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700226 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700227
Ian Rogers2c8f6532011-09-02 17:16:34 -0700228 // Register that holds the incoming method argument
229 virtual ManagedRegister MethodRegister() = 0;
230
Ian Rogersb033c752011-07-20 12:22:35 -0700231 // Iterator interface
232 bool HasNext();
233 void Next();
234 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700235 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100236 bool IsCurrentParamADouble();
237 bool IsCurrentParamALong();
Ian Rogers7a99c112011-09-07 12:48:27 -0700238 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
239 bool IsCurrentArgPossiblyNull();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700240 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700241 virtual bool IsCurrentParamInRegister() = 0;
242 virtual bool IsCurrentParamOnStack() = 0;
243 virtual ManagedRegister CurrentParamRegister() = 0;
244 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700245
Ian Rogers2c8f6532011-09-02 17:16:34 -0700246 virtual ~ManagedRuntimeCallingConvention() {}
247
Ian Rogersb5d09b22012-03-06 22:14:17 -0800248 // Registers to spill to caller's out registers on entry.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700249 virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800250
Ian Rogers2c8f6532011-09-02 17:16:34 -0700251 protected:
Ian Rogers790a6b72014-04-01 10:36:00 -0700252 ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
253 size_t frame_pointer_size)
254 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogersb033c752011-07-20 12:22:35 -0700255};
256
257// Abstraction for JNI calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700258// | { Incoming stack args } | <-- Prior SP
259// | { Return address } |
260// | { Callee saves } | ([1])
261// | { Return value spill } | (live on return slow paths)
Ian Rogersdc51b792011-09-22 20:41:37 -0700262// | { Local Ref. Table State } |
Ian Rogersbdb03912011-09-14 00:55:44 -0700263// | { Stack Indirect Ref. Table |
264// | num. refs./link } | (here to prior SP is frame size)
265// | { Method* } | <-- Anchor SP written to thread
266// | { Outgoing stack args } | <-- SP at point of call
267// | Native frame |
268//
269// [1] We must save all callee saves here to enable any exception throws to restore
270// callee saves for frames above this one.
Ian Rogersb033c752011-07-20 12:22:35 -0700271class JniCallingConvention : public CallingConvention {
272 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800273 static JniCallingConvention* Create(bool is_static, bool is_synchronized, const char* shorty,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700274 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700275
276 // Size of frame excluding space for outgoing args (its assumed Method* is
277 // always at the bottom of a frame, but this doesn't work for outgoing
278 // native args). Includes alignment.
Ian Rogers2c8f6532011-09-02 17:16:34 -0700279 virtual size_t FrameSize() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700280 // Size of outgoing arguments, including alignment
Ian Rogers2c8f6532011-09-02 17:16:34 -0700281 virtual size_t OutArgSize() = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700282 // Number of references in stack indirect reference table
Ian Rogersdc51b792011-09-22 20:41:37 -0700283 size_t ReferenceCount() const;
284 // Location where the segment state of the local indirect reference table is saved
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700285 FrameOffset SavedLocalReferenceCookieOffset() const;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700286 // Location where the return value of a call can be squirreled if another
287 // call is made following the native call
Ian Rogersdc51b792011-09-22 20:41:37 -0700288 FrameOffset ReturnValueSaveLocation() const;
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700289 // Register that holds result if it is integer.
290 virtual ManagedRegister IntReturnRegister() = 0;
Andreas Gamped1104322014-05-01 14:38:56 -0700291 // Whether the compiler needs to ensure zero-/sign-extension of a small result type
292 virtual bool RequiresSmallResultTypeExtension() const = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700293
Ian Rogersbdb03912011-09-14 00:55:44 -0700294 // Callee save registers to spill prior to native code (which may clobber)
295 virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0;
296
297 // Spill mask values
298 virtual uint32_t CoreSpillMask() const = 0;
299 virtual uint32_t FpSpillMask() const = 0;
Ian Rogers0d666d82011-08-14 16:03:46 -0700300
Ian Rogersdc51b792011-09-22 20:41:37 -0700301 // An extra scratch register live after the call
302 virtual ManagedRegister ReturnScratchRegister() const = 0;
303
Ian Rogersb033c752011-07-20 12:22:35 -0700304 // Iterator interface
305 bool HasNext();
Ian Rogers67375ac2011-09-14 00:55:44 -0700306 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700307 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700308 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100309 bool IsCurrentParamADouble();
310 bool IsCurrentParamALong();
311 bool IsCurrentParamJniEnv();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700312 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700313 virtual bool IsCurrentParamInRegister() = 0;
314 virtual bool IsCurrentParamOnStack() = 0;
315 virtual ManagedRegister CurrentParamRegister() = 0;
316 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700317
318 // Iterator interface extension for JNI
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700319 FrameOffset CurrentParamHandleScopeEntryOffset();
Ian Rogersb033c752011-07-20 12:22:35 -0700320
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700321 // Position of handle scope and interior fields
322 FrameOffset HandleScopeOffset() const {
Andreas Gampecf4035a2014-05-28 22:43:01 -0700323 return FrameOffset(this->displacement_.Int32Value() + sizeof(StackReference<mirror::ArtMethod>));
324 // above Method reference
Ian Rogersb033c752011-07-20 12:22:35 -0700325 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700326
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700327 FrameOffset HandleScopeLinkOffset() const {
328 return FrameOffset(HandleScopeOffset().Int32Value() + HandleScope::LinkOffset(frame_pointer_size_));
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700329 }
330
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700331 FrameOffset HandleScopeNumRefsOffset() const {
332 return FrameOffset(HandleScopeOffset().Int32Value() +
333 HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700334 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700335
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700336 FrameOffset HandleerencesOffset() const {
337 return FrameOffset(HandleScopeOffset().Int32Value() +
338 HandleScope::ReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700339 }
340
Ian Rogers2c8f6532011-09-02 17:16:34 -0700341 virtual ~JniCallingConvention() {}
342
343 protected:
Ian Rogersb033c752011-07-20 12:22:35 -0700344 // Named iterator positions
345 enum IteratorPos {
346 kJniEnv = 0,
347 kObjectOrClass = 1
348 };
349
Ian Rogers790a6b72014-04-01 10:36:00 -0700350 explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
351 size_t frame_pointer_size)
352 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700353
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700354 // Number of stack slots for outgoing arguments, above which the handle scope is
Ian Rogersb033c752011-07-20 12:22:35 -0700355 // located
Ian Rogers2c8f6532011-09-02 17:16:34 -0700356 virtual size_t NumberOfOutgoingStackArgs() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700357
Ian Rogers2c8f6532011-09-02 17:16:34 -0700358 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800359 size_t NumberOfExtraArgumentsForJni();
Ian Rogersb033c752011-07-20 12:22:35 -0700360};
361
362} // namespace art
363
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700364#endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_