blob: 2a6e7d96cdc8d69abbb868c9cf68a41aa0c9a262 [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"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070022#include "thread.h"
Ian Rogers166db042013-07-26 12:05:57 -070023#include "utils/managed_register.h"
Ian Rogersb033c752011-07-20 12:22:35 -070024
25namespace art {
26
Ian Rogers790a6b72014-04-01 10:36:00 -070027// Top-level abstraction for different calling conventions.
Ian Rogersb033c752011-07-20 12:22:35 -070028class CallingConvention {
29 public:
Ian Rogers169c9a72011-11-13 20:13:17 -080030 bool IsReturnAReference() const { return shorty_[0] == 'L'; }
Ian Rogersb033c752011-07-20 12:22:35 -070031
jeffhao58136ca2012-05-24 13:40:11 -070032 Primitive::Type GetReturnType() const {
33 return Primitive::GetType(shorty_[0]);
34 }
35
Ian Rogers169c9a72011-11-13 20:13:17 -080036 size_t SizeOfReturnValue() const {
37 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
38 if (result >= 1 && result < 4) {
39 result = 4;
40 }
41 return result;
42 }
Ian Rogersdf20fe02011-07-20 20:34:16 -070043
Ian Rogers00f7d0e2012-07-19 15:28:27 -070044 // Register that holds result of this method invocation.
Ian Rogers2c8f6532011-09-02 17:16:34 -070045 virtual ManagedRegister ReturnRegister() = 0;
Ian Rogers00f7d0e2012-07-19 15:28:27 -070046 // Register reserved for scratch usage during procedure calls.
Ian Rogers2c8f6532011-09-02 17:16:34 -070047 virtual ManagedRegister InterproceduralScratchRegister() = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070048
Ian Rogers790a6b72014-04-01 10:36:00 -070049 // Offset of Method within the frame.
50 FrameOffset MethodStackOffset() {
51 return displacement_;
52 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070053
Ian Rogersb033c752011-07-20 12:22:35 -070054 // Iterator interface
55
56 // Place iterator at start of arguments. The displacement is applied to
57 // frame offset methods to account for frames which may be on the stack
58 // below the one being iterated over.
59 void ResetIterator(FrameOffset displacement) {
60 displacement_ = displacement;
Shih-wei Liao5381cf92011-07-27 00:28:04 -070061 itr_slots_ = 0;
62 itr_args_ = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070063 itr_refs_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070064 itr_longs_and_doubles_ = 0;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070065 itr_float_and_doubles_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070066 }
67
Ian Rogers2c8f6532011-09-02 17:16:34 -070068 virtual ~CallingConvention() {}
69
Ian Rogersb033c752011-07-20 12:22:35 -070070 protected:
Ian Rogers790a6b72014-04-01 10:36:00 -070071 CallingConvention(bool is_static, bool is_synchronized, const char* shorty,
72 size_t frame_pointer_size)
73 : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
74 itr_float_and_doubles_(0), displacement_(0),
75 frame_pointer_size_(frame_pointer_size),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070076 handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
Ian Rogers790a6b72014-04-01 10:36:00 -070077 is_static_(is_static), is_synchronized_(is_synchronized),
Ian Rogers169c9a72011-11-13 20:13:17 -080078 shorty_(shorty) {
79 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
80 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070081 num_float_or_double_args_ = 0;
Ian Rogers169c9a72011-11-13 20:13:17 -080082 num_long_or_double_args_ = 0;
83 for (size_t i = 1; i < strlen(shorty); i++) {
84 char ch = shorty_[i];
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070085 switch (ch) {
86 case 'L':
Ian Rogers169c9a72011-11-13 20:13:17 -080087 num_ref_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070088 break;
89 case 'J':
Ian Rogers169c9a72011-11-13 20:13:17 -080090 num_long_or_double_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070091 break;
92 case 'D':
93 num_long_or_double_args_++;
94 num_float_or_double_args_++;
95 break;
96 case 'F':
97 num_float_or_double_args_++;
98 break;
Ian Rogers169c9a72011-11-13 20:13:17 -080099 }
100 }
101 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700102
Ian Rogers169c9a72011-11-13 20:13:17 -0800103 bool IsStatic() const {
104 return is_static_;
105 }
106 bool IsSynchronized() const {
107 return is_synchronized_;
108 }
109 bool IsParamALongOrDouble(unsigned int param) const {
110 DCHECK_LT(param, NumArgs());
111 if (IsStatic()) {
112 param++; // 0th argument must skip return value at start of the shorty
113 } else if (param == 0) {
114 return false; // this argument
115 }
116 char ch = shorty_[param];
117 return (ch == 'J' || ch == 'D');
118 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700119 bool IsParamAFloatOrDouble(unsigned int param) const {
120 DCHECK_LT(param, NumArgs());
121 if (IsStatic()) {
122 param++; // 0th argument must skip return value at start of the shorty
123 } else if (param == 0) {
124 return false; // this argument
125 }
126 char ch = shorty_[param];
127 return (ch == 'F' || ch == 'D');
128 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100129 bool IsParamADouble(unsigned int param) const {
130 DCHECK_LT(param, NumArgs());
131 if (IsStatic()) {
132 param++; // 0th argument must skip return value at start of the shorty
133 } else if (param == 0) {
134 return false; // this argument
135 }
136 return shorty_[param] == 'D';
137 }
138 bool IsParamALong(unsigned int param) const {
139 DCHECK_LT(param, NumArgs());
140 if (IsStatic()) {
141 param++; // 0th argument must skip return value at start of the shorty
142 } else if (param == 0) {
143 return true; // this argument
144 }
145 return shorty_[param] == 'J';
146 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800147 bool IsParamAReference(unsigned int param) const {
148 DCHECK_LT(param, NumArgs());
149 if (IsStatic()) {
150 param++; // 0th argument must skip return value at start of the shorty
151 } else if (param == 0) {
152 return true; // this argument
153 }
154 return shorty_[param] == 'L';
Ian Rogers169c9a72011-11-13 20:13:17 -0800155 }
156 size_t NumArgs() const {
157 return num_args_;
158 }
159 size_t NumLongOrDoubleArgs() const {
160 return num_long_or_double_args_;
161 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700162 size_t NumFloatOrDoubleArgs() const {
163 return num_float_or_double_args_;
164 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800165 size_t NumReferenceArgs() const {
166 return num_ref_args_;
167 }
168 size_t ParamSize(unsigned int param) const {
169 DCHECK_LT(param, NumArgs());
170 if (IsStatic()) {
171 param++; // 0th argument must skip return value at start of the shorty
172 } else if (param == 0) {
Ian Rogers790a6b72014-04-01 10:36:00 -0700173 return frame_pointer_size_; // this argument
Ian Rogers169c9a72011-11-13 20:13:17 -0800174 }
175 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
176 if (result >= 1 && result < 4) {
177 result = 4;
178 }
179 return result;
180 }
181 const char* GetShorty() const {
182 return shorty_.c_str();
183 }
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700184 // The slot number for current calling_convention argument.
185 // Note that each slot is 32-bit. When the current argument is bigger
186 // than 32 bits, return the first slot number for this argument.
187 unsigned int itr_slots_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700188 // The number of references iterated past.
Ian Rogers7a99c112011-09-07 12:48:27 -0700189 unsigned int itr_refs_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700190 // The argument number along argument list for current argument.
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700191 unsigned int itr_args_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700192 // Number of longs and doubles seen along argument list.
Ian Rogersb033c752011-07-20 12:22:35 -0700193 unsigned int itr_longs_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700194 // Number of float and doubles seen along argument list.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700195 unsigned int itr_float_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700196 // Space for frames below this on the stack.
Ian Rogersb033c752011-07-20 12:22:35 -0700197 FrameOffset displacement_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700198 // The size of a reference.
199 const size_t frame_pointer_size_;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700200 // The size of a reference entry within the handle scope.
201 const size_t handle_scope_pointer_size_;
Ian Rogersb033c752011-07-20 12:22:35 -0700202
203 private:
Ian Rogers169c9a72011-11-13 20:13:17 -0800204 const bool is_static_;
205 const bool is_synchronized_;
206 std::string shorty_;
207 size_t num_args_;
208 size_t num_ref_args_;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700209 size_t num_float_or_double_args_;
Ian Rogers169c9a72011-11-13 20:13:17 -0800210 size_t num_long_or_double_args_;
Ian Rogersb033c752011-07-20 12:22:35 -0700211};
212
213// Abstraction for managed code's calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700214// | { Incoming stack args } |
215// | { Prior Method* } | <-- Prior SP
216// | { Return address } |
217// | { Callee saves } |
218// | { Spills ... } |
219// | { Outgoing stack args } |
220// | { Method* } | <-- SP
Ian Rogersb033c752011-07-20 12:22:35 -0700221class ManagedRuntimeCallingConvention : public CallingConvention {
222 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800223 static ManagedRuntimeCallingConvention* Create(bool is_static, bool is_synchronized,
224 const char* shorty,
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700225 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700226
Ian Rogers2c8f6532011-09-02 17:16:34 -0700227 // Register that holds the incoming method argument
228 virtual ManagedRegister MethodRegister() = 0;
229
Ian Rogersb033c752011-07-20 12:22:35 -0700230 // Iterator interface
231 bool HasNext();
232 void Next();
233 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700234 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100235 bool IsCurrentParamADouble();
236 bool IsCurrentParamALong();
Ian Rogers7a99c112011-09-07 12:48:27 -0700237 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
238 bool IsCurrentArgPossiblyNull();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700239 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700240 virtual bool IsCurrentParamInRegister() = 0;
241 virtual bool IsCurrentParamOnStack() = 0;
242 virtual ManagedRegister CurrentParamRegister() = 0;
243 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700244
Ian Rogers2c8f6532011-09-02 17:16:34 -0700245 virtual ~ManagedRuntimeCallingConvention() {}
246
Ian Rogersb5d09b22012-03-06 22:14:17 -0800247 // Registers to spill to caller's out registers on entry.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700248 virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800249
Ian Rogers2c8f6532011-09-02 17:16:34 -0700250 protected:
Ian Rogers790a6b72014-04-01 10:36:00 -0700251 ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
252 size_t frame_pointer_size)
253 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogersb033c752011-07-20 12:22:35 -0700254};
255
256// Abstraction for JNI calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700257// | { Incoming stack args } | <-- Prior SP
258// | { Return address } |
259// | { Callee saves } | ([1])
260// | { Return value spill } | (live on return slow paths)
Ian Rogersdc51b792011-09-22 20:41:37 -0700261// | { Local Ref. Table State } |
Ian Rogersbdb03912011-09-14 00:55:44 -0700262// | { Stack Indirect Ref. Table |
263// | num. refs./link } | (here to prior SP is frame size)
264// | { Method* } | <-- Anchor SP written to thread
265// | { Outgoing stack args } | <-- SP at point of call
266// | Native frame |
267//
268// [1] We must save all callee saves here to enable any exception throws to restore
269// callee saves for frames above this one.
Ian Rogersb033c752011-07-20 12:22:35 -0700270class JniCallingConvention : public CallingConvention {
271 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800272 static JniCallingConvention* Create(bool is_static, bool is_synchronized, const char* shorty,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700273 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700274
275 // Size of frame excluding space for outgoing args (its assumed Method* is
276 // always at the bottom of a frame, but this doesn't work for outgoing
277 // native args). Includes alignment.
Ian Rogers2c8f6532011-09-02 17:16:34 -0700278 virtual size_t FrameSize() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700279 // Size of outgoing arguments, including alignment
Ian Rogers2c8f6532011-09-02 17:16:34 -0700280 virtual size_t OutArgSize() = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700281 // Number of references in stack indirect reference table
Ian Rogersdc51b792011-09-22 20:41:37 -0700282 size_t ReferenceCount() const;
283 // Location where the segment state of the local indirect reference table is saved
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700284 FrameOffset SavedLocalReferenceCookieOffset() const;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700285 // Location where the return value of a call can be squirreled if another
286 // call is made following the native call
Ian Rogersdc51b792011-09-22 20:41:37 -0700287 FrameOffset ReturnValueSaveLocation() const;
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700288 // Register that holds result if it is integer.
289 virtual ManagedRegister IntReturnRegister() = 0;
Andreas Gamped1104322014-05-01 14:38:56 -0700290 // Whether the compiler needs to ensure zero-/sign-extension of a small result type
291 virtual bool RequiresSmallResultTypeExtension() const = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700292
Ian Rogersbdb03912011-09-14 00:55:44 -0700293 // Callee save registers to spill prior to native code (which may clobber)
294 virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0;
295
296 // Spill mask values
297 virtual uint32_t CoreSpillMask() const = 0;
298 virtual uint32_t FpSpillMask() const = 0;
Ian Rogers0d666d82011-08-14 16:03:46 -0700299
Ian Rogersdc51b792011-09-22 20:41:37 -0700300 // An extra scratch register live after the call
301 virtual ManagedRegister ReturnScratchRegister() const = 0;
302
Ian Rogersb033c752011-07-20 12:22:35 -0700303 // Iterator interface
304 bool HasNext();
Ian Rogers67375ac2011-09-14 00:55:44 -0700305 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700306 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700307 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100308 bool IsCurrentParamADouble();
309 bool IsCurrentParamALong();
310 bool IsCurrentParamJniEnv();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700311 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700312 virtual bool IsCurrentParamInRegister() = 0;
313 virtual bool IsCurrentParamOnStack() = 0;
314 virtual ManagedRegister CurrentParamRegister() = 0;
315 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700316
317 // Iterator interface extension for JNI
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700318 FrameOffset CurrentParamHandleScopeEntryOffset();
Ian Rogersb033c752011-07-20 12:22:35 -0700319
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700320 // Position of handle scope and interior fields
321 FrameOffset HandleScopeOffset() const {
Ian Rogers790a6b72014-04-01 10:36:00 -0700322 return FrameOffset(this->displacement_.Int32Value() + frame_pointer_size_); // above Method*
Ian Rogersb033c752011-07-20 12:22:35 -0700323 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700324
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700325 FrameOffset HandleScopeLinkOffset() const {
326 return FrameOffset(HandleScopeOffset().Int32Value() + HandleScope::LinkOffset(frame_pointer_size_));
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700327 }
328
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700329 FrameOffset HandleScopeNumRefsOffset() const {
330 return FrameOffset(HandleScopeOffset().Int32Value() +
331 HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700332 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700333
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700334 FrameOffset HandleerencesOffset() const {
335 return FrameOffset(HandleScopeOffset().Int32Value() +
336 HandleScope::ReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700337 }
338
Ian Rogers2c8f6532011-09-02 17:16:34 -0700339 virtual ~JniCallingConvention() {}
340
341 protected:
Ian Rogersb033c752011-07-20 12:22:35 -0700342 // Named iterator positions
343 enum IteratorPos {
344 kJniEnv = 0,
345 kObjectOrClass = 1
346 };
347
Ian Rogers790a6b72014-04-01 10:36:00 -0700348 explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
349 size_t frame_pointer_size)
350 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700351
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700352 // Number of stack slots for outgoing arguments, above which the handle scope is
Ian Rogersb033c752011-07-20 12:22:35 -0700353 // located
Ian Rogers2c8f6532011-09-02 17:16:34 -0700354 virtual size_t NumberOfOutgoingStackArgs() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700355
Ian Rogers2c8f6532011-09-02 17:16:34 -0700356 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800357 size_t NumberOfExtraArgumentsForJni();
Ian Rogersb033c752011-07-20 12:22:35 -0700358};
359
360} // namespace art
361
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700362#endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_