blob: 3a0eb5a4b443ce5e86fddf85d255a72635226527 [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
17#ifndef ART_SRC_CALLING_CONVENTION_H_
18#define ART_SRC_CALLING_CONVENTION_H_
19
Ian Rogers0d666d82011-08-14 16:03:46 -070020#include <vector>
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070021#include "managed_register.h"
Elliott Hughes68e76522011-10-05 13:22:16 -070022#include "stack_indirect_reference_table.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070023#include "thread.h"
Ian Rogersb033c752011-07-20 12:22:35 -070024
25namespace art {
26
27// Top-level abstraction for different calling conventions
28class 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
Ian Rogers169c9a72011-11-13 20:13:17 -080032 size_t SizeOfReturnValue() const {
33 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
34 if (result >= 1 && result < 4) {
35 result = 4;
36 }
37 return result;
38 }
Ian Rogersdf20fe02011-07-20 20:34:16 -070039
Ian Rogersb033c752011-07-20 12:22:35 -070040 // Register that holds result of this method
Ian Rogers2c8f6532011-09-02 17:16:34 -070041 virtual ManagedRegister ReturnRegister() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070042 // Register reserved for scratch usage during procedure calls
Ian Rogers2c8f6532011-09-02 17:16:34 -070043 virtual ManagedRegister InterproceduralScratchRegister() = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070044
Carl Shapiroe2d373e2011-07-25 15:20:06 -070045 // Offset of Method within the frame
46 FrameOffset MethodStackOffset();
47
Ian Rogersb033c752011-07-20 12:22:35 -070048 // Iterator interface
49
50 // Place iterator at start of arguments. The displacement is applied to
51 // frame offset methods to account for frames which may be on the stack
52 // below the one being iterated over.
53 void ResetIterator(FrameOffset displacement) {
54 displacement_ = displacement;
Shih-wei Liao5381cf92011-07-27 00:28:04 -070055 itr_slots_ = 0;
56 itr_args_ = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070057 itr_refs_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070058 itr_longs_and_doubles_ = 0;
59 }
60
Ian Rogers2c8f6532011-09-02 17:16:34 -070061 virtual ~CallingConvention() {}
62
Ian Rogersb033c752011-07-20 12:22:35 -070063 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -080064 CallingConvention(bool is_static, bool is_synchronized, const char* shorty)
65 : displacement_(0), is_static_(is_static), is_synchronized_(is_synchronized),
66 shorty_(shorty) {
67 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
68 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer.
69 num_long_or_double_args_ = 0;
70 for (size_t i = 1; i < strlen(shorty); i++) {
71 char ch = shorty_[i];
72 if (ch == 'L') {
73 num_ref_args_++;
74 } else if ((ch == 'D') || (ch == 'J')) {
75 num_long_or_double_args_++;
76 }
77 }
78 }
Ian Rogers2c8f6532011-09-02 17:16:34 -070079
Ian Rogers169c9a72011-11-13 20:13:17 -080080 bool IsStatic() const {
81 return is_static_;
82 }
83 bool IsSynchronized() const {
84 return is_synchronized_;
85 }
86 bool IsParamALongOrDouble(unsigned int param) const {
87 DCHECK_LT(param, NumArgs());
88 if (IsStatic()) {
89 param++; // 0th argument must skip return value at start of the shorty
90 } else if (param == 0) {
91 return false; // this argument
92 }
93 char ch = shorty_[param];
94 return (ch == 'J' || ch == 'D');
95 }
96 bool IsParamAReference(unsigned int param) const {
97 DCHECK_LT(param, NumArgs());
98 if (IsStatic()) {
99 param++; // 0th argument must skip return value at start of the shorty
100 } else if (param == 0) {
101 return true; // this argument
102 }
103 return shorty_[param] == 'L';
Ian Rogers169c9a72011-11-13 20:13:17 -0800104 }
105 size_t NumArgs() const {
106 return num_args_;
107 }
108 size_t NumLongOrDoubleArgs() const {
109 return num_long_or_double_args_;
110 }
111 size_t NumReferenceArgs() const {
112 return num_ref_args_;
113 }
114 size_t ParamSize(unsigned int param) const {
115 DCHECK_LT(param, NumArgs());
116 if (IsStatic()) {
117 param++; // 0th argument must skip return value at start of the shorty
118 } else if (param == 0) {
119 return kPointerSize; // this argument
120 }
121 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
122 if (result >= 1 && result < 4) {
123 result = 4;
124 }
125 return result;
126 }
127 const char* GetShorty() const {
128 return shorty_.c_str();
129 }
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700130 // The slot number for current calling_convention argument.
131 // Note that each slot is 32-bit. When the current argument is bigger
132 // than 32 bits, return the first slot number for this argument.
133 unsigned int itr_slots_;
Ian Rogers7a99c112011-09-07 12:48:27 -0700134 // The number of references iterated past
135 unsigned int itr_refs_;
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700136 // The argument number along argument list for current argument
137 unsigned int itr_args_;
138 // Number of longs and doubles seen along argument list
Ian Rogersb033c752011-07-20 12:22:35 -0700139 unsigned int itr_longs_and_doubles_;
140 // Space for frames below this on the stack
141 FrameOffset displacement_;
142
143 private:
Ian Rogers169c9a72011-11-13 20:13:17 -0800144 const bool is_static_;
145 const bool is_synchronized_;
146 std::string shorty_;
147 size_t num_args_;
148 size_t num_ref_args_;
149 size_t num_long_or_double_args_;
Ian Rogersb033c752011-07-20 12:22:35 -0700150};
151
152// Abstraction for managed code's calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700153// | { Incoming stack args } |
154// | { Prior Method* } | <-- Prior SP
155// | { Return address } |
156// | { Callee saves } |
157// | { Spills ... } |
158// | { Outgoing stack args } |
159// | { Method* } | <-- SP
Ian Rogersb033c752011-07-20 12:22:35 -0700160class ManagedRuntimeCallingConvention : public CallingConvention {
161 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800162 static ManagedRuntimeCallingConvention* Create(bool is_static, bool is_synchronized,
163 const char* shorty,
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700164 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700165
Ian Rogers2c8f6532011-09-02 17:16:34 -0700166 // Register that holds the incoming method argument
167 virtual ManagedRegister MethodRegister() = 0;
168
Ian Rogersb033c752011-07-20 12:22:35 -0700169 // Iterator interface
170 bool HasNext();
171 void Next();
172 bool IsCurrentParamAReference();
Ian Rogers7a99c112011-09-07 12:48:27 -0700173 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
174 bool IsCurrentArgPossiblyNull();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700175 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700176 virtual bool IsCurrentParamInRegister() = 0;
177 virtual bool IsCurrentParamOnStack() = 0;
178 virtual ManagedRegister CurrentParamRegister() = 0;
179 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700180
Ian Rogers2c8f6532011-09-02 17:16:34 -0700181 virtual ~ManagedRuntimeCallingConvention() {}
182
Ian Rogersb5d09b22012-03-06 22:14:17 -0800183 // Registers to spill to caller's out registers on entry.
184 virtual const std::vector<ManagedRegister>& EntrySpills() = 0;
185
Ian Rogers2c8f6532011-09-02 17:16:34 -0700186 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800187 ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty) :
188 CallingConvention(is_static, is_synchronized, shorty) {}
Ian Rogersb033c752011-07-20 12:22:35 -0700189};
190
191// Abstraction for JNI calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700192// | { Incoming stack args } | <-- Prior SP
193// | { Return address } |
194// | { Callee saves } | ([1])
195// | { Return value spill } | (live on return slow paths)
Ian Rogersdc51b792011-09-22 20:41:37 -0700196// | { Local Ref. Table State } |
Ian Rogersbdb03912011-09-14 00:55:44 -0700197// | { Stack Indirect Ref. Table |
198// | num. refs./link } | (here to prior SP is frame size)
199// | { Method* } | <-- Anchor SP written to thread
200// | { Outgoing stack args } | <-- SP at point of call
201// | Native frame |
202//
203// [1] We must save all callee saves here to enable any exception throws to restore
204// callee saves for frames above this one.
Ian Rogersb033c752011-07-20 12:22:35 -0700205class JniCallingConvention : public CallingConvention {
206 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800207 static JniCallingConvention* Create(bool is_static, bool is_synchronized, const char* shorty,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700208 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700209
210 // Size of frame excluding space for outgoing args (its assumed Method* is
211 // always at the bottom of a frame, but this doesn't work for outgoing
212 // native args). Includes alignment.
Ian Rogers2c8f6532011-09-02 17:16:34 -0700213 virtual size_t FrameSize() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700214 // Size of outgoing arguments, including alignment
Ian Rogers2c8f6532011-09-02 17:16:34 -0700215 virtual size_t OutArgSize() = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700216 // Number of references in stack indirect reference table
Ian Rogersdc51b792011-09-22 20:41:37 -0700217 size_t ReferenceCount() const;
218 // Location where the segment state of the local indirect reference table is saved
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700219 FrameOffset SavedLocalReferenceCookieOffset() const;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700220 // Location where the return value of a call can be squirreled if another
221 // call is made following the native call
Ian Rogersdc51b792011-09-22 20:41:37 -0700222 FrameOffset ReturnValueSaveLocation() const;
Ian Rogersb033c752011-07-20 12:22:35 -0700223
Ian Rogersbdb03912011-09-14 00:55:44 -0700224 // Callee save registers to spill prior to native code (which may clobber)
225 virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0;
226
227 // Spill mask values
228 virtual uint32_t CoreSpillMask() const = 0;
229 virtual uint32_t FpSpillMask() const = 0;
Ian Rogers0d666d82011-08-14 16:03:46 -0700230
Ian Rogers67375ac2011-09-14 00:55:44 -0700231 // Returns true if the method register will have been clobbered during argument
232 // set up
Ian Rogersad42e132011-09-17 20:23:33 -0700233 virtual bool IsMethodRegisterClobberedPreCall() = 0;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700234
Ian Rogersdc51b792011-09-22 20:41:37 -0700235 // An extra scratch register live after the call
236 virtual ManagedRegister ReturnScratchRegister() const = 0;
237
Ian Rogersb033c752011-07-20 12:22:35 -0700238 // Iterator interface
239 bool HasNext();
Ian Rogers67375ac2011-09-14 00:55:44 -0700240 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700241 bool IsCurrentParamAReference();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700242 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700243 virtual bool IsCurrentParamInRegister() = 0;
244 virtual bool IsCurrentParamOnStack() = 0;
245 virtual ManagedRegister CurrentParamRegister() = 0;
246 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700247
248 // Iterator interface extension for JNI
Ian Rogers408f79a2011-08-23 18:22:33 -0700249 FrameOffset CurrentParamSirtEntryOffset();
Ian Rogersb033c752011-07-20 12:22:35 -0700250
Ian Rogers408f79a2011-08-23 18:22:33 -0700251 // Position of SIRT and interior fields
Ian Rogersdc51b792011-09-22 20:41:37 -0700252 FrameOffset SirtOffset() const {
Ian Rogersb033c752011-07-20 12:22:35 -0700253 return FrameOffset(displacement_.Int32Value() +
254 kPointerSize); // above Method*
255 }
Ian Rogersdc51b792011-09-22 20:41:37 -0700256 FrameOffset SirtNumRefsOffset() const {
Ian Rogers408f79a2011-08-23 18:22:33 -0700257 return FrameOffset(SirtOffset().Int32Value() +
258 StackIndirectReferenceTable::NumberOfReferencesOffset());
Ian Rogersb033c752011-07-20 12:22:35 -0700259 }
Ian Rogersdc51b792011-09-22 20:41:37 -0700260 FrameOffset SirtLinkOffset() const {
Ian Rogers408f79a2011-08-23 18:22:33 -0700261 return FrameOffset(SirtOffset().Int32Value() +
262 StackIndirectReferenceTable::LinkOffset());
Ian Rogersb033c752011-07-20 12:22:35 -0700263 }
264
Ian Rogers2c8f6532011-09-02 17:16:34 -0700265 virtual ~JniCallingConvention() {}
266
267 protected:
Ian Rogersb033c752011-07-20 12:22:35 -0700268 // Named iterator positions
269 enum IteratorPos {
270 kJniEnv = 0,
271 kObjectOrClass = 1
272 };
273
Ian Rogers169c9a72011-11-13 20:13:17 -0800274 explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty) :
275 CallingConvention(is_static, is_synchronized, shorty) {}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700276
Ian Rogers408f79a2011-08-23 18:22:33 -0700277 // Number of stack slots for outgoing arguments, above which the SIRT is
Ian Rogersb033c752011-07-20 12:22:35 -0700278 // located
Ian Rogers2c8f6532011-09-02 17:16:34 -0700279 virtual size_t NumberOfOutgoingStackArgs() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700280
Ian Rogers2c8f6532011-09-02 17:16:34 -0700281 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800282 size_t NumberOfExtraArgumentsForJni();
Ian Rogersb033c752011-07-20 12:22:35 -0700283};
284
285} // namespace art
286
287#endif // ART_SRC_CALLING_CONVENTION_H_