blob: bfd7d21ad3ecdd2eb2ce9b310bbd9111e22cb0e8 [file] [log] [blame]
Ian Rogersb033c752011-07-20 12:22:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Ian Rogersb033c752011-07-20 12:22:35 -07002
3#ifndef ART_SRC_CALLING_CONVENTION_H_
4#define ART_SRC_CALLING_CONVENTION_H_
5
Ian Rogers0d666d82011-08-14 16:03:46 -07006#include <vector>
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07007#include "managed_register.h"
Elliott Hughes68e76522011-10-05 13:22:16 -07008#include "stack_indirect_reference_table.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07009#include "thread.h"
Ian Rogersb033c752011-07-20 12:22:35 -070010
11namespace art {
12
13// Top-level abstraction for different calling conventions
14class CallingConvention {
15 public:
Ian Rogers169c9a72011-11-13 20:13:17 -080016 bool IsReturnAReference() const { return shorty_[0] == 'L'; }
Ian Rogersb033c752011-07-20 12:22:35 -070017
Ian Rogers169c9a72011-11-13 20:13:17 -080018 size_t SizeOfReturnValue() const {
19 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
20 if (result >= 1 && result < 4) {
21 result = 4;
22 }
23 return result;
24 }
Ian Rogersdf20fe02011-07-20 20:34:16 -070025
Ian Rogersb033c752011-07-20 12:22:35 -070026 // Register that holds result of this method
Ian Rogers2c8f6532011-09-02 17:16:34 -070027 virtual ManagedRegister ReturnRegister() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070028 // Register reserved for scratch usage during procedure calls
Ian Rogers2c8f6532011-09-02 17:16:34 -070029 virtual ManagedRegister InterproceduralScratchRegister() = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070030
Carl Shapiroe2d373e2011-07-25 15:20:06 -070031 // Offset of Method within the frame
32 FrameOffset MethodStackOffset();
33
Ian Rogersb033c752011-07-20 12:22:35 -070034 // Iterator interface
35
36 // Place iterator at start of arguments. The displacement is applied to
37 // frame offset methods to account for frames which may be on the stack
38 // below the one being iterated over.
39 void ResetIterator(FrameOffset displacement) {
40 displacement_ = displacement;
Shih-wei Liao5381cf92011-07-27 00:28:04 -070041 itr_slots_ = 0;
42 itr_args_ = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070043 itr_refs_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070044 itr_longs_and_doubles_ = 0;
45 }
46
Ian Rogers2c8f6532011-09-02 17:16:34 -070047 virtual ~CallingConvention() {}
48
Ian Rogersb033c752011-07-20 12:22:35 -070049 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -080050 CallingConvention(bool is_static, bool is_synchronized, const char* shorty)
51 : displacement_(0), is_static_(is_static), is_synchronized_(is_synchronized),
52 shorty_(shorty) {
53 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
54 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer.
55 num_long_or_double_args_ = 0;
56 for (size_t i = 1; i < strlen(shorty); i++) {
57 char ch = shorty_[i];
58 if (ch == 'L') {
59 num_ref_args_++;
60 } else if ((ch == 'D') || (ch == 'J')) {
61 num_long_or_double_args_++;
62 }
63 }
64 }
Ian Rogers2c8f6532011-09-02 17:16:34 -070065
Ian Rogers169c9a72011-11-13 20:13:17 -080066 bool IsStatic() const {
67 return is_static_;
68 }
69 bool IsSynchronized() const {
70 return is_synchronized_;
71 }
72 bool IsParamALongOrDouble(unsigned int param) const {
73 DCHECK_LT(param, NumArgs());
74 if (IsStatic()) {
75 param++; // 0th argument must skip return value at start of the shorty
76 } else if (param == 0) {
77 return false; // this argument
78 }
79 char ch = shorty_[param];
80 return (ch == 'J' || ch == 'D');
81 }
82 bool IsParamAReference(unsigned int param) const {
83 DCHECK_LT(param, NumArgs());
84 if (IsStatic()) {
85 param++; // 0th argument must skip return value at start of the shorty
86 } else if (param == 0) {
87 return true; // this argument
88 }
89 return shorty_[param] == 'L';
Ian Rogersb033c752011-07-20 12:22:35 -070090
Ian Rogers169c9a72011-11-13 20:13:17 -080091 }
92 size_t NumArgs() const {
93 return num_args_;
94 }
95 size_t NumLongOrDoubleArgs() const {
96 return num_long_or_double_args_;
97 }
98 size_t NumReferenceArgs() const {
99 return num_ref_args_;
100 }
101 size_t ParamSize(unsigned int param) const {
102 DCHECK_LT(param, NumArgs());
103 if (IsStatic()) {
104 param++; // 0th argument must skip return value at start of the shorty
105 } else if (param == 0) {
106 return kPointerSize; // this argument
107 }
108 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
109 if (result >= 1 && result < 4) {
110 result = 4;
111 }
112 return result;
113 }
114 const char* GetShorty() const {
115 return shorty_.c_str();
116 }
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700117 // The slot number for current calling_convention argument.
118 // Note that each slot is 32-bit. When the current argument is bigger
119 // than 32 bits, return the first slot number for this argument.
120 unsigned int itr_slots_;
Ian Rogers7a99c112011-09-07 12:48:27 -0700121 // The number of references iterated past
122 unsigned int itr_refs_;
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700123 // The argument number along argument list for current argument
124 unsigned int itr_args_;
125 // Number of longs and doubles seen along argument list
Ian Rogersb033c752011-07-20 12:22:35 -0700126 unsigned int itr_longs_and_doubles_;
127 // Space for frames below this on the stack
128 FrameOffset displacement_;
129
130 private:
Ian Rogers169c9a72011-11-13 20:13:17 -0800131 const bool is_static_;
132 const bool is_synchronized_;
133 std::string shorty_;
134 size_t num_args_;
135 size_t num_ref_args_;
136 size_t num_long_or_double_args_;
Ian Rogersb033c752011-07-20 12:22:35 -0700137};
138
139// Abstraction for managed code's calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700140// | { Incoming stack args } |
141// | { Prior Method* } | <-- Prior SP
142// | { Return address } |
143// | { Callee saves } |
144// | { Spills ... } |
145// | { Outgoing stack args } |
146// | { Method* } | <-- SP
Ian Rogersb033c752011-07-20 12:22:35 -0700147class ManagedRuntimeCallingConvention : public CallingConvention {
148 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800149 static ManagedRuntimeCallingConvention* Create(bool is_static, bool is_synchronized,
150 const char* shorty,
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700151 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700152
Ian Rogers2c8f6532011-09-02 17:16:34 -0700153 // Register that holds the incoming method argument
154 virtual ManagedRegister MethodRegister() = 0;
155
Ian Rogersb033c752011-07-20 12:22:35 -0700156 // Iterator interface
157 bool HasNext();
158 void Next();
159 bool IsCurrentParamAReference();
Ian Rogers7a99c112011-09-07 12:48:27 -0700160 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
161 bool IsCurrentArgPossiblyNull();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700162 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700163 virtual bool IsCurrentParamInRegister() = 0;
164 virtual bool IsCurrentParamOnStack() = 0;
165 virtual ManagedRegister CurrentParamRegister() = 0;
166 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700167
Ian Rogers2c8f6532011-09-02 17:16:34 -0700168 virtual ~ManagedRuntimeCallingConvention() {}
169
170 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800171 ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty) :
172 CallingConvention(is_static, is_synchronized, shorty) {}
Ian Rogersb033c752011-07-20 12:22:35 -0700173};
174
175// Abstraction for JNI calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700176// | { Incoming stack args } | <-- Prior SP
177// | { Return address } |
178// | { Callee saves } | ([1])
179// | { Return value spill } | (live on return slow paths)
Ian Rogersdc51b792011-09-22 20:41:37 -0700180// | { Local Ref. Table State } |
Ian Rogersbdb03912011-09-14 00:55:44 -0700181// | { Stack Indirect Ref. Table |
182// | num. refs./link } | (here to prior SP is frame size)
183// | { Method* } | <-- Anchor SP written to thread
184// | { Outgoing stack args } | <-- SP at point of call
185// | Native frame |
186//
187// [1] We must save all callee saves here to enable any exception throws to restore
188// callee saves for frames above this one.
Ian Rogersb033c752011-07-20 12:22:35 -0700189class JniCallingConvention : public CallingConvention {
190 public:
Ian Rogers169c9a72011-11-13 20:13:17 -0800191 static JniCallingConvention* Create(bool is_static, bool is_synchronized, const char* shorty,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700192 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700193
194 // Size of frame excluding space for outgoing args (its assumed Method* is
195 // always at the bottom of a frame, but this doesn't work for outgoing
196 // native args). Includes alignment.
Ian Rogers2c8f6532011-09-02 17:16:34 -0700197 virtual size_t FrameSize() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700198 // Size of outgoing arguments, including alignment
Ian Rogers2c8f6532011-09-02 17:16:34 -0700199 virtual size_t OutArgSize() = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700200 // Number of references in stack indirect reference table
Ian Rogersdc51b792011-09-22 20:41:37 -0700201 size_t ReferenceCount() const;
202 // Location where the segment state of the local indirect reference table is saved
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700203 FrameOffset SavedLocalReferenceCookieOffset() const;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700204 // Location where the return value of a call can be squirreled if another
205 // call is made following the native call
Ian Rogersdc51b792011-09-22 20:41:37 -0700206 FrameOffset ReturnValueSaveLocation() const;
Ian Rogersb033c752011-07-20 12:22:35 -0700207
Ian Rogersbdb03912011-09-14 00:55:44 -0700208 // Callee save registers to spill prior to native code (which may clobber)
209 virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0;
210
211 // Spill mask values
212 virtual uint32_t CoreSpillMask() const = 0;
213 virtual uint32_t FpSpillMask() const = 0;
Ian Rogers0d666d82011-08-14 16:03:46 -0700214
Ian Rogers67375ac2011-09-14 00:55:44 -0700215 // Returns true if the method register will have been clobbered during argument
216 // set up
Ian Rogersad42e132011-09-17 20:23:33 -0700217 virtual bool IsMethodRegisterClobberedPreCall() = 0;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700218
Ian Rogersdc51b792011-09-22 20:41:37 -0700219 // An extra scratch register live after the call
220 virtual ManagedRegister ReturnScratchRegister() const = 0;
221
Ian Rogersb033c752011-07-20 12:22:35 -0700222 // Iterator interface
223 bool HasNext();
Ian Rogers67375ac2011-09-14 00:55:44 -0700224 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700225 bool IsCurrentParamAReference();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700226 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700227 virtual bool IsCurrentParamInRegister() = 0;
228 virtual bool IsCurrentParamOnStack() = 0;
229 virtual ManagedRegister CurrentParamRegister() = 0;
230 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700231
232 // Iterator interface extension for JNI
Ian Rogers408f79a2011-08-23 18:22:33 -0700233 FrameOffset CurrentParamSirtEntryOffset();
Ian Rogersb033c752011-07-20 12:22:35 -0700234
Ian Rogers408f79a2011-08-23 18:22:33 -0700235 // Position of SIRT and interior fields
Ian Rogersdc51b792011-09-22 20:41:37 -0700236 FrameOffset SirtOffset() const {
Ian Rogersb033c752011-07-20 12:22:35 -0700237 return FrameOffset(displacement_.Int32Value() +
238 kPointerSize); // above Method*
239 }
Ian Rogersdc51b792011-09-22 20:41:37 -0700240 FrameOffset SirtNumRefsOffset() const {
Ian Rogers408f79a2011-08-23 18:22:33 -0700241 return FrameOffset(SirtOffset().Int32Value() +
242 StackIndirectReferenceTable::NumberOfReferencesOffset());
Ian Rogersb033c752011-07-20 12:22:35 -0700243 }
Ian Rogersdc51b792011-09-22 20:41:37 -0700244 FrameOffset SirtLinkOffset() const {
Ian Rogers408f79a2011-08-23 18:22:33 -0700245 return FrameOffset(SirtOffset().Int32Value() +
246 StackIndirectReferenceTable::LinkOffset());
Ian Rogersb033c752011-07-20 12:22:35 -0700247 }
248
Ian Rogers2c8f6532011-09-02 17:16:34 -0700249 virtual ~JniCallingConvention() {}
250
251 protected:
Ian Rogersb033c752011-07-20 12:22:35 -0700252 // Named iterator positions
253 enum IteratorPos {
254 kJniEnv = 0,
255 kObjectOrClass = 1
256 };
257
Ian Rogers169c9a72011-11-13 20:13:17 -0800258 explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty) :
259 CallingConvention(is_static, is_synchronized, shorty) {}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700260
Ian Rogers408f79a2011-08-23 18:22:33 -0700261 // Number of stack slots for outgoing arguments, above which the SIRT is
Ian Rogersb033c752011-07-20 12:22:35 -0700262 // located
Ian Rogers2c8f6532011-09-02 17:16:34 -0700263 virtual size_t NumberOfOutgoingStackArgs() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700264
Ian Rogers2c8f6532011-09-02 17:16:34 -0700265 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800266 size_t NumberOfExtraArgumentsForJni();
Ian Rogersb033c752011-07-20 12:22:35 -0700267};
268
269} // namespace art
270
271#endif // ART_SRC_CALLING_CONVENTION_H_