blob: 995fa51d44023b86285d6a2f52f81d69ca2f1a29 [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 Marko93205e32016-04-13 11:59:46 +010020#include "base/arena_object.h"
Andreas Gampe542451c2016-07-26 09:02:02 -070021#include "base/enums.h"
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070022#include "handle_scope.h"
Ian Rogerse63db272014-07-15 15:36:11 -070023#include "primitive.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070024#include "thread.h"
Vladimir Marko32248382016-05-19 10:37:24 +010025#include "utils/array_ref.h"
Ian Rogers166db042013-07-26 12:05:57 -070026#include "utils/managed_register.h"
Ian Rogersb033c752011-07-20 12:22:35 -070027
28namespace art {
29
Ian Rogers790a6b72014-04-01 10:36:00 -070030// Top-level abstraction for different calling conventions.
Vladimir Marko93205e32016-04-13 11:59:46 +010031class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConvention> {
Ian Rogersb033c752011-07-20 12:22:35 -070032 public:
Ian Rogers169c9a72011-11-13 20:13:17 -080033 bool IsReturnAReference() const { return shorty_[0] == 'L'; }
Ian Rogersb033c752011-07-20 12:22:35 -070034
jeffhao58136ca2012-05-24 13:40:11 -070035 Primitive::Type GetReturnType() const {
36 return Primitive::GetType(shorty_[0]);
37 }
38
Ian Rogers169c9a72011-11-13 20:13:17 -080039 size_t SizeOfReturnValue() const {
40 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
41 if (result >= 1 && result < 4) {
42 result = 4;
43 }
44 return result;
45 }
Ian Rogersdf20fe02011-07-20 20:34:16 -070046
Ian Rogers00f7d0e2012-07-19 15:28:27 -070047 // Register that holds result of this method invocation.
Ian Rogers2c8f6532011-09-02 17:16:34 -070048 virtual ManagedRegister ReturnRegister() = 0;
Ian Rogers00f7d0e2012-07-19 15:28:27 -070049 // Register reserved for scratch usage during procedure calls.
Ian Rogers2c8f6532011-09-02 17:16:34 -070050 virtual ManagedRegister InterproceduralScratchRegister() = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070051
Ian Rogers790a6b72014-04-01 10:36:00 -070052 // Offset of Method within the frame.
53 FrameOffset MethodStackOffset() {
54 return displacement_;
55 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -070056
Ian Rogersb033c752011-07-20 12:22:35 -070057 // Iterator interface
58
59 // Place iterator at start of arguments. The displacement is applied to
60 // frame offset methods to account for frames which may be on the stack
61 // below the one being iterated over.
62 void ResetIterator(FrameOffset displacement) {
63 displacement_ = displacement;
Shih-wei Liao5381cf92011-07-27 00:28:04 -070064 itr_slots_ = 0;
65 itr_args_ = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070066 itr_refs_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070067 itr_longs_and_doubles_ = 0;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070068 itr_float_and_doubles_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070069 }
70
Ian Rogers2c8f6532011-09-02 17:16:34 -070071 virtual ~CallingConvention() {}
72
Ian Rogersb033c752011-07-20 12:22:35 -070073 protected:
Andreas Gampe542451c2016-07-26 09:02:02 -070074 CallingConvention(bool is_static,
75 bool is_synchronized,
76 const char* shorty,
77 PointerSize frame_pointer_size)
Ian Rogers790a6b72014-04-01 10:36:00 -070078 : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
79 itr_float_and_doubles_(0), displacement_(0),
80 frame_pointer_size_(frame_pointer_size),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070081 handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
Ian Rogers790a6b72014-04-01 10:36:00 -070082 is_static_(is_static), is_synchronized_(is_synchronized),
Ian Rogers169c9a72011-11-13 20:13:17 -080083 shorty_(shorty) {
84 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
85 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070086 num_float_or_double_args_ = 0;
Ian Rogers169c9a72011-11-13 20:13:17 -080087 num_long_or_double_args_ = 0;
88 for (size_t i = 1; i < strlen(shorty); i++) {
89 char ch = shorty_[i];
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070090 switch (ch) {
91 case 'L':
Ian Rogers169c9a72011-11-13 20:13:17 -080092 num_ref_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070093 break;
94 case 'J':
Ian Rogers169c9a72011-11-13 20:13:17 -080095 num_long_or_double_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070096 break;
97 case 'D':
98 num_long_or_double_args_++;
99 num_float_or_double_args_++;
100 break;
101 case 'F':
102 num_float_or_double_args_++;
103 break;
Ian Rogers169c9a72011-11-13 20:13:17 -0800104 }
105 }
106 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700107
Ian Rogers169c9a72011-11-13 20:13:17 -0800108 bool IsStatic() const {
109 return is_static_;
110 }
111 bool IsSynchronized() const {
112 return is_synchronized_;
113 }
114 bool IsParamALongOrDouble(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 false; // this argument
120 }
121 char ch = shorty_[param];
122 return (ch == 'J' || ch == 'D');
123 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700124 bool IsParamAFloatOrDouble(unsigned int param) const {
125 DCHECK_LT(param, NumArgs());
126 if (IsStatic()) {
127 param++; // 0th argument must skip return value at start of the shorty
128 } else if (param == 0) {
129 return false; // this argument
130 }
131 char ch = shorty_[param];
132 return (ch == 'F' || ch == 'D');
133 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100134 bool IsParamADouble(unsigned int param) const {
135 DCHECK_LT(param, NumArgs());
136 if (IsStatic()) {
137 param++; // 0th argument must skip return value at start of the shorty
138 } else if (param == 0) {
139 return false; // this argument
140 }
141 return shorty_[param] == 'D';
142 }
143 bool IsParamALong(unsigned int param) const {
144 DCHECK_LT(param, NumArgs());
145 if (IsStatic()) {
146 param++; // 0th argument must skip return value at start of the shorty
147 } else if (param == 0) {
Mark Mendell3e6a3bf2015-01-19 14:09:22 -0500148 return false; // this argument
Serban Constantinescu75b91132014-04-09 18:39:10 +0100149 }
150 return shorty_[param] == 'J';
151 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800152 bool IsParamAReference(unsigned int param) const {
153 DCHECK_LT(param, NumArgs());
154 if (IsStatic()) {
155 param++; // 0th argument must skip return value at start of the shorty
156 } else if (param == 0) {
157 return true; // this argument
158 }
159 return shorty_[param] == 'L';
Ian Rogers169c9a72011-11-13 20:13:17 -0800160 }
161 size_t NumArgs() const {
162 return num_args_;
163 }
164 size_t NumLongOrDoubleArgs() const {
165 return num_long_or_double_args_;
166 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700167 size_t NumFloatOrDoubleArgs() const {
168 return num_float_or_double_args_;
169 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800170 size_t NumReferenceArgs() const {
171 return num_ref_args_;
172 }
173 size_t ParamSize(unsigned int param) const {
174 DCHECK_LT(param, NumArgs());
175 if (IsStatic()) {
176 param++; // 0th argument must skip return value at start of the shorty
177 } else if (param == 0) {
Mathieu Chartiere401d142015-04-22 13:56:20 -0700178 return sizeof(mirror::HeapReference<mirror::Object>); // this argument
Ian Rogers169c9a72011-11-13 20:13:17 -0800179 }
180 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
181 if (result >= 1 && result < 4) {
182 result = 4;
183 }
184 return result;
185 }
186 const char* GetShorty() const {
187 return shorty_.c_str();
188 }
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700189 // The slot number for current calling_convention argument.
190 // Note that each slot is 32-bit. When the current argument is bigger
191 // than 32 bits, return the first slot number for this argument.
192 unsigned int itr_slots_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700193 // The number of references iterated past.
Ian Rogers7a99c112011-09-07 12:48:27 -0700194 unsigned int itr_refs_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700195 // The argument number along argument list for current argument.
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700196 unsigned int itr_args_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700197 // Number of longs and doubles seen along argument list.
Ian Rogersb033c752011-07-20 12:22:35 -0700198 unsigned int itr_longs_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700199 // Number of float and doubles seen along argument list.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700200 unsigned int itr_float_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700201 // Space for frames below this on the stack.
Ian Rogersb033c752011-07-20 12:22:35 -0700202 FrameOffset displacement_;
Mathieu Chartiere401d142015-04-22 13:56:20 -0700203 // The size of a pointer.
Andreas Gampe542451c2016-07-26 09:02:02 -0700204 const PointerSize frame_pointer_size_;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700205 // The size of a reference entry within the handle scope.
206 const size_t handle_scope_pointer_size_;
Ian Rogersb033c752011-07-20 12:22:35 -0700207
208 private:
Ian Rogers169c9a72011-11-13 20:13:17 -0800209 const bool is_static_;
210 const bool is_synchronized_;
211 std::string shorty_;
212 size_t num_args_;
213 size_t num_ref_args_;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700214 size_t num_float_or_double_args_;
Ian Rogers169c9a72011-11-13 20:13:17 -0800215 size_t num_long_or_double_args_;
Ian Rogersb033c752011-07-20 12:22:35 -0700216};
217
218// Abstraction for managed code's calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700219// | { Incoming stack args } |
220// | { Prior Method* } | <-- Prior SP
221// | { Return address } |
222// | { Callee saves } |
223// | { Spills ... } |
224// | { Outgoing stack args } |
225// | { Method* } | <-- SP
Ian Rogersb033c752011-07-20 12:22:35 -0700226class ManagedRuntimeCallingConvention : public CallingConvention {
227 public:
Vladimir Marko93205e32016-04-13 11:59:46 +0100228 static std::unique_ptr<ManagedRuntimeCallingConvention> Create(ArenaAllocator* arena,
229 bool is_static,
230 bool is_synchronized,
231 const char* shorty,
232 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700233
Ian Rogers2c8f6532011-09-02 17:16:34 -0700234 // Register that holds the incoming method argument
235 virtual ManagedRegister MethodRegister() = 0;
236
Ian Rogersb033c752011-07-20 12:22:35 -0700237 // Iterator interface
238 bool HasNext();
239 void Next();
240 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700241 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100242 bool IsCurrentParamADouble();
243 bool IsCurrentParamALong();
Ian Rogers7a99c112011-09-07 12:48:27 -0700244 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
245 bool IsCurrentArgPossiblyNull();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700246 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700247 virtual bool IsCurrentParamInRegister() = 0;
248 virtual bool IsCurrentParamOnStack() = 0;
249 virtual ManagedRegister CurrentParamRegister() = 0;
250 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700251
Ian Rogers2c8f6532011-09-02 17:16:34 -0700252 virtual ~ManagedRuntimeCallingConvention() {}
253
Ian Rogersb5d09b22012-03-06 22:14:17 -0800254 // Registers to spill to caller's out registers on entry.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700255 virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800256
Ian Rogers2c8f6532011-09-02 17:16:34 -0700257 protected:
Vladimir Marko93205e32016-04-13 11:59:46 +0100258 ManagedRuntimeCallingConvention(bool is_static,
259 bool is_synchronized,
260 const char* shorty,
Andreas Gampe542451c2016-07-26 09:02:02 -0700261 PointerSize frame_pointer_size)
Ian Rogers790a6b72014-04-01 10:36:00 -0700262 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogersb033c752011-07-20 12:22:35 -0700263};
264
265// Abstraction for JNI calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700266// | { Incoming stack args } | <-- Prior SP
267// | { Return address } |
268// | { Callee saves } | ([1])
269// | { Return value spill } | (live on return slow paths)
Ian Rogersdc51b792011-09-22 20:41:37 -0700270// | { Local Ref. Table State } |
Ian Rogersbdb03912011-09-14 00:55:44 -0700271// | { Stack Indirect Ref. Table |
272// | num. refs./link } | (here to prior SP is frame size)
273// | { Method* } | <-- Anchor SP written to thread
274// | { Outgoing stack args } | <-- SP at point of call
275// | Native frame |
276//
277// [1] We must save all callee saves here to enable any exception throws to restore
278// callee saves for frames above this one.
Ian Rogersb033c752011-07-20 12:22:35 -0700279class JniCallingConvention : public CallingConvention {
280 public:
Vladimir Marko93205e32016-04-13 11:59:46 +0100281 static std::unique_ptr<JniCallingConvention> Create(ArenaAllocator* arena,
282 bool is_static,
283 bool is_synchronized,
284 const char* shorty,
285 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700286
287 // Size of frame excluding space for outgoing args (its assumed Method* is
288 // always at the bottom of a frame, but this doesn't work for outgoing
289 // native args). Includes alignment.
Ian Rogers2c8f6532011-09-02 17:16:34 -0700290 virtual size_t FrameSize() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700291 // Size of outgoing arguments, including alignment
Ian Rogers2c8f6532011-09-02 17:16:34 -0700292 virtual size_t OutArgSize() = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700293 // Number of references in stack indirect reference table
Ian Rogersdc51b792011-09-22 20:41:37 -0700294 size_t ReferenceCount() const;
295 // Location where the segment state of the local indirect reference table is saved
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700296 FrameOffset SavedLocalReferenceCookieOffset() const;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700297 // Location where the return value of a call can be squirreled if another
298 // call is made following the native call
Ian Rogersdc51b792011-09-22 20:41:37 -0700299 FrameOffset ReturnValueSaveLocation() const;
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700300 // Register that holds result if it is integer.
301 virtual ManagedRegister IntReturnRegister() = 0;
Andreas Gamped1104322014-05-01 14:38:56 -0700302 // Whether the compiler needs to ensure zero-/sign-extension of a small result type
303 virtual bool RequiresSmallResultTypeExtension() const = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700304
Ian Rogersbdb03912011-09-14 00:55:44 -0700305 // Callee save registers to spill prior to native code (which may clobber)
Vladimir Marko32248382016-05-19 10:37:24 +0100306 virtual ArrayRef<const ManagedRegister> CalleeSaveRegisters() const = 0;
Ian Rogersbdb03912011-09-14 00:55:44 -0700307
308 // Spill mask values
309 virtual uint32_t CoreSpillMask() const = 0;
310 virtual uint32_t FpSpillMask() const = 0;
Ian Rogers0d666d82011-08-14 16:03:46 -0700311
Ian Rogersdc51b792011-09-22 20:41:37 -0700312 // An extra scratch register live after the call
313 virtual ManagedRegister ReturnScratchRegister() const = 0;
314
Ian Rogersb033c752011-07-20 12:22:35 -0700315 // Iterator interface
316 bool HasNext();
Ian Rogers67375ac2011-09-14 00:55:44 -0700317 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700318 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700319 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100320 bool IsCurrentParamADouble();
321 bool IsCurrentParamALong();
322 bool IsCurrentParamJniEnv();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700323 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700324 virtual bool IsCurrentParamInRegister() = 0;
325 virtual bool IsCurrentParamOnStack() = 0;
326 virtual ManagedRegister CurrentParamRegister() = 0;
327 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700328
329 // Iterator interface extension for JNI
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700330 FrameOffset CurrentParamHandleScopeEntryOffset();
Ian Rogersb033c752011-07-20 12:22:35 -0700331
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700332 // Position of handle scope and interior fields
333 FrameOffset HandleScopeOffset() const {
Andreas Gampe542451c2016-07-26 09:02:02 -0700334 return FrameOffset(this->displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
Andreas Gampecf4035a2014-05-28 22:43:01 -0700335 // above Method reference
Ian Rogersb033c752011-07-20 12:22:35 -0700336 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700337
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700338 FrameOffset HandleScopeLinkOffset() const {
Mathieu Chartiere401d142015-04-22 13:56:20 -0700339 return FrameOffset(HandleScopeOffset().Int32Value() +
340 HandleScope::LinkOffset(frame_pointer_size_));
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700341 }
342
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700343 FrameOffset HandleScopeNumRefsOffset() const {
344 return FrameOffset(HandleScopeOffset().Int32Value() +
345 HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700346 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700347
Mathieu Chartiere401d142015-04-22 13:56:20 -0700348 FrameOffset HandleReferencesOffset() const {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700349 return FrameOffset(HandleScopeOffset().Int32Value() +
350 HandleScope::ReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700351 }
352
Ian Rogers2c8f6532011-09-02 17:16:34 -0700353 virtual ~JniCallingConvention() {}
354
355 protected:
Ian Rogersb033c752011-07-20 12:22:35 -0700356 // Named iterator positions
357 enum IteratorPos {
358 kJniEnv = 0,
359 kObjectOrClass = 1
360 };
361
Andreas Gampe542451c2016-07-26 09:02:02 -0700362 JniCallingConvention(bool is_static,
363 bool is_synchronized,
364 const char* shorty,
365 PointerSize frame_pointer_size)
Ian Rogers790a6b72014-04-01 10:36:00 -0700366 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700367
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700368 // Number of stack slots for outgoing arguments, above which the handle scope is
Ian Rogersb033c752011-07-20 12:22:35 -0700369 // located
Ian Rogers2c8f6532011-09-02 17:16:34 -0700370 virtual size_t NumberOfOutgoingStackArgs() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700371
Ian Rogers2c8f6532011-09-02 17:16:34 -0700372 protected:
Ian Rogers169c9a72011-11-13 20:13:17 -0800373 size_t NumberOfExtraArgumentsForJni();
Ian Rogersb033c752011-07-20 12:22:35 -0700374};
375
376} // namespace art
377
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700378#endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_