blob: 005ae910d1517c67e92d01e8aa099bb7968d5ece [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"
David Brazdild9c90372016-09-14 16:53:55 +010021#include "base/array_ref.h"
Andreas Gampe542451c2016-07-26 09:02:02 -070022#include "base/enums.h"
David Sehr67bf42e2018-02-26 16:43:04 -080023#include "dex/primitive.h"
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070024#include "handle_scope.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070025#include "thread.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
Andreas Gampe639b2b12019-01-08 10:32:50 -080030enum class InstructionSet;
31
Ian Rogers790a6b72014-04-01 10:36:00 -070032// Top-level abstraction for different calling conventions.
Vladimir Marko93205e32016-04-13 11:59:46 +010033class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConvention> {
Ian Rogersb033c752011-07-20 12:22:35 -070034 public:
Ian Rogers169c9a72011-11-13 20:13:17 -080035 bool IsReturnAReference() const { return shorty_[0] == 'L'; }
Ian Rogersb033c752011-07-20 12:22:35 -070036
jeffhao58136ca2012-05-24 13:40:11 -070037 Primitive::Type GetReturnType() const {
38 return Primitive::GetType(shorty_[0]);
39 }
40
Ian Rogers169c9a72011-11-13 20:13:17 -080041 size_t SizeOfReturnValue() const {
42 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
43 if (result >= 1 && result < 4) {
44 result = 4;
45 }
46 return result;
47 }
Ian Rogersdf20fe02011-07-20 20:34:16 -070048
Ian Rogers00f7d0e2012-07-19 15:28:27 -070049 // Register that holds result of this method invocation.
Ian Rogers2c8f6532011-09-02 17:16:34 -070050 virtual ManagedRegister ReturnRegister() = 0;
Carl Shapiroe2d373e2011-07-25 15:20:06 -070051
Ian Rogersb033c752011-07-20 12:22:35 -070052 // Iterator interface
53
54 // Place iterator at start of arguments. The displacement is applied to
55 // frame offset methods to account for frames which may be on the stack
56 // below the one being iterated over.
Vladimir Marko662f12e2020-02-26 12:46:09 +000057 virtual void ResetIterator(FrameOffset displacement) {
Ian Rogersb033c752011-07-20 12:22:35 -070058 displacement_ = displacement;
Shih-wei Liao5381cf92011-07-27 00:28:04 -070059 itr_slots_ = 0;
60 itr_args_ = 0;
Shih-wei Liao668512a2011-09-01 14:18:34 -070061 itr_refs_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070062 itr_longs_and_doubles_ = 0;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070063 itr_float_and_doubles_ = 0;
Ian Rogersb033c752011-07-20 12:22:35 -070064 }
65
Vladimir Marko1c3c1062019-12-03 11:18:44 +000066 FrameOffset GetDisplacement() const {
67 return displacement_;
68 }
69
70 PointerSize GetFramePointerSize() const {
71 return frame_pointer_size_;
72 }
73
Ian Rogers2c8f6532011-09-02 17:16:34 -070074 virtual ~CallingConvention() {}
75
Ian Rogersb033c752011-07-20 12:22:35 -070076 protected:
Andreas Gampe542451c2016-07-26 09:02:02 -070077 CallingConvention(bool is_static,
78 bool is_synchronized,
79 const char* shorty,
80 PointerSize frame_pointer_size)
Ian Rogers790a6b72014-04-01 10:36:00 -070081 : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
82 itr_float_and_doubles_(0), displacement_(0),
83 frame_pointer_size_(frame_pointer_size),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -070084 handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
Ian Rogers790a6b72014-04-01 10:36:00 -070085 is_static_(is_static), is_synchronized_(is_synchronized),
Ian Rogers169c9a72011-11-13 20:13:17 -080086 shorty_(shorty) {
87 num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
88 num_ref_args_ = is_static ? 0 : 1; // The implicit this pointer.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070089 num_float_or_double_args_ = 0;
Ian Rogers169c9a72011-11-13 20:13:17 -080090 num_long_or_double_args_ = 0;
91 for (size_t i = 1; i < strlen(shorty); i++) {
92 char ch = shorty_[i];
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070093 switch (ch) {
94 case 'L':
Ian Rogers169c9a72011-11-13 20:13:17 -080095 num_ref_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070096 break;
97 case 'J':
Ian Rogers169c9a72011-11-13 20:13:17 -080098 num_long_or_double_args_++;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +070099 break;
100 case 'D':
101 num_long_or_double_args_++;
102 num_float_or_double_args_++;
103 break;
104 case 'F':
105 num_float_or_double_args_++;
106 break;
Ian Rogers169c9a72011-11-13 20:13:17 -0800107 }
108 }
109 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700110
Ian Rogers169c9a72011-11-13 20:13:17 -0800111 bool IsStatic() const {
112 return is_static_;
113 }
114 bool IsSynchronized() const {
115 return is_synchronized_;
116 }
117 bool IsParamALongOrDouble(unsigned int param) const {
118 DCHECK_LT(param, NumArgs());
119 if (IsStatic()) {
120 param++; // 0th argument must skip return value at start of the shorty
121 } else if (param == 0) {
122 return false; // this argument
123 }
124 char ch = shorty_[param];
125 return (ch == 'J' || ch == 'D');
126 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700127 bool IsParamAFloatOrDouble(unsigned int param) const {
128 DCHECK_LT(param, NumArgs());
129 if (IsStatic()) {
130 param++; // 0th argument must skip return value at start of the shorty
131 } else if (param == 0) {
132 return false; // this argument
133 }
134 char ch = shorty_[param];
135 return (ch == 'F' || ch == 'D');
136 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100137 bool IsParamADouble(unsigned int param) const {
138 DCHECK_LT(param, NumArgs());
139 if (IsStatic()) {
140 param++; // 0th argument must skip return value at start of the shorty
141 } else if (param == 0) {
142 return false; // this argument
143 }
144 return shorty_[param] == 'D';
145 }
146 bool IsParamALong(unsigned int param) const {
147 DCHECK_LT(param, NumArgs());
148 if (IsStatic()) {
149 param++; // 0th argument must skip return value at start of the shorty
150 } else if (param == 0) {
Mark Mendell3e6a3bf2015-01-19 14:09:22 -0500151 return false; // this argument
Serban Constantinescu75b91132014-04-09 18:39:10 +0100152 }
153 return shorty_[param] == 'J';
154 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800155 bool IsParamAReference(unsigned int param) const {
156 DCHECK_LT(param, NumArgs());
157 if (IsStatic()) {
158 param++; // 0th argument must skip return value at start of the shorty
159 } else if (param == 0) {
160 return true; // this argument
161 }
162 return shorty_[param] == 'L';
Ian Rogers169c9a72011-11-13 20:13:17 -0800163 }
164 size_t NumArgs() const {
165 return num_args_;
166 }
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700167 // Implicit argument count: 1 for instance functions, 0 for static functions.
168 // (The implicit argument is only relevant to the shorty, i.e.
169 // the 0th arg is not in the shorty if it's implicit).
170 size_t NumImplicitArgs() const {
171 return IsStatic() ? 0 : 1;
172 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800173 size_t NumLongOrDoubleArgs() const {
174 return num_long_or_double_args_;
175 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700176 size_t NumFloatOrDoubleArgs() const {
177 return num_float_or_double_args_;
178 }
Ian Rogers169c9a72011-11-13 20:13:17 -0800179 size_t NumReferenceArgs() const {
180 return num_ref_args_;
181 }
182 size_t ParamSize(unsigned int param) const {
183 DCHECK_LT(param, NumArgs());
184 if (IsStatic()) {
185 param++; // 0th argument must skip return value at start of the shorty
186 } else if (param == 0) {
Mathieu Chartiere401d142015-04-22 13:56:20 -0700187 return sizeof(mirror::HeapReference<mirror::Object>); // this argument
Ian Rogers169c9a72011-11-13 20:13:17 -0800188 }
189 size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
190 if (result >= 1 && result < 4) {
191 result = 4;
192 }
193 return result;
194 }
195 const char* GetShorty() const {
196 return shorty_.c_str();
197 }
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700198 // The slot number for current calling_convention argument.
199 // Note that each slot is 32-bit. When the current argument is bigger
200 // than 32 bits, return the first slot number for this argument.
201 unsigned int itr_slots_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700202 // The number of references iterated past.
Ian Rogers7a99c112011-09-07 12:48:27 -0700203 unsigned int itr_refs_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700204 // The argument number along argument list for current argument.
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700205 unsigned int itr_args_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700206 // Number of longs and doubles seen along argument list.
Ian Rogersb033c752011-07-20 12:22:35 -0700207 unsigned int itr_longs_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700208 // Number of float and doubles seen along argument list.
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700209 unsigned int itr_float_and_doubles_;
Ian Rogers790a6b72014-04-01 10:36:00 -0700210 // Space for frames below this on the stack.
Ian Rogersb033c752011-07-20 12:22:35 -0700211 FrameOffset displacement_;
Mathieu Chartiere401d142015-04-22 13:56:20 -0700212 // The size of a pointer.
Andreas Gampe542451c2016-07-26 09:02:02 -0700213 const PointerSize frame_pointer_size_;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700214 // The size of a reference entry within the handle scope.
215 const size_t handle_scope_pointer_size_;
Ian Rogersb033c752011-07-20 12:22:35 -0700216
217 private:
Ian Rogers169c9a72011-11-13 20:13:17 -0800218 const bool is_static_;
219 const bool is_synchronized_;
220 std::string shorty_;
221 size_t num_args_;
222 size_t num_ref_args_;
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700223 size_t num_float_or_double_args_;
Ian Rogers169c9a72011-11-13 20:13:17 -0800224 size_t num_long_or_double_args_;
Ian Rogersb033c752011-07-20 12:22:35 -0700225};
226
227// Abstraction for managed code's calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700228// | { Incoming stack args } |
229// | { Prior Method* } | <-- Prior SP
230// | { Return address } |
231// | { Callee saves } |
232// | { Spills ... } |
233// | { Outgoing stack args } |
234// | { Method* } | <-- SP
Ian Rogersb033c752011-07-20 12:22:35 -0700235class ManagedRuntimeCallingConvention : public CallingConvention {
236 public:
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100237 static std::unique_ptr<ManagedRuntimeCallingConvention> Create(ArenaAllocator* allocator,
Vladimir Marko93205e32016-04-13 11:59:46 +0100238 bool is_static,
239 bool is_synchronized,
240 const char* shorty,
241 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700242
Vladimir Marko1c3c1062019-12-03 11:18:44 +0000243 // Offset of Method within the managed frame.
244 FrameOffset MethodStackOffset() {
245 return FrameOffset(0u);
246 }
247
Ian Rogers2c8f6532011-09-02 17:16:34 -0700248 // Register that holds the incoming method argument
249 virtual ManagedRegister MethodRegister() = 0;
250
Ian Rogersb033c752011-07-20 12:22:35 -0700251 // Iterator interface
252 bool HasNext();
Vladimir Marko662f12e2020-02-26 12:46:09 +0000253 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700254 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700255 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100256 bool IsCurrentParamADouble();
257 bool IsCurrentParamALong();
Vladimir Marko662f12e2020-02-26 12:46:09 +0000258 bool IsCurrentParamALongOrDouble() {
259 return IsCurrentParamALong() || IsCurrentParamADouble();
260 }
Ian Rogers7a99c112011-09-07 12:48:27 -0700261 bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
262 bool IsCurrentArgPossiblyNull();
Ian Rogersdf20fe02011-07-20 20:34:16 -0700263 size_t CurrentParamSize();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700264 virtual bool IsCurrentParamInRegister() = 0;
265 virtual bool IsCurrentParamOnStack() = 0;
266 virtual ManagedRegister CurrentParamRegister() = 0;
267 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700268
Ian Rogers2c8f6532011-09-02 17:16:34 -0700269 virtual ~ManagedRuntimeCallingConvention() {}
270
271 protected:
Vladimir Marko93205e32016-04-13 11:59:46 +0100272 ManagedRuntimeCallingConvention(bool is_static,
273 bool is_synchronized,
274 const char* shorty,
Andreas Gampe542451c2016-07-26 09:02:02 -0700275 PointerSize frame_pointer_size)
Ian Rogers790a6b72014-04-01 10:36:00 -0700276 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
Ian Rogersb033c752011-07-20 12:22:35 -0700277};
278
279// Abstraction for JNI calling conventions
Ian Rogersbdb03912011-09-14 00:55:44 -0700280// | { Incoming stack args } | <-- Prior SP
281// | { Return address } |
282// | { Callee saves } | ([1])
283// | { Return value spill } | (live on return slow paths)
Ian Rogersdc51b792011-09-22 20:41:37 -0700284// | { Local Ref. Table State } |
Ian Rogersbdb03912011-09-14 00:55:44 -0700285// | { Stack Indirect Ref. Table |
286// | num. refs./link } | (here to prior SP is frame size)
287// | { Method* } | <-- Anchor SP written to thread
288// | { Outgoing stack args } | <-- SP at point of call
289// | Native frame |
290//
291// [1] We must save all callee saves here to enable any exception throws to restore
292// callee saves for frames above this one.
Ian Rogersb033c752011-07-20 12:22:35 -0700293class JniCallingConvention : public CallingConvention {
294 public:
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100295 static std::unique_ptr<JniCallingConvention> Create(ArenaAllocator* allocator,
Vladimir Marko93205e32016-04-13 11:59:46 +0100296 bool is_static,
297 bool is_synchronized,
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700298 bool is_critical_native,
Vladimir Marko93205e32016-04-13 11:59:46 +0100299 const char* shorty,
300 InstructionSet instruction_set);
Ian Rogersb033c752011-07-20 12:22:35 -0700301
302 // Size of frame excluding space for outgoing args (its assumed Method* is
303 // always at the bottom of a frame, but this doesn't work for outgoing
304 // native args). Includes alignment.
Vladimir Marko1c3c1062019-12-03 11:18:44 +0000305 virtual size_t FrameSize() const = 0;
Vladimir Marko86c87522020-05-11 16:55:55 +0100306 // Size of outgoing frame, i.e. stack arguments, @CriticalNative return PC if needed, alignment.
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700307 // -- Arguments that are passed via registers are excluded from this size.
Vladimir Marko86c87522020-05-11 16:55:55 +0100308 virtual size_t OutFrameSize() const = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700309 // Number of references in stack indirect reference table
Ian Rogersdc51b792011-09-22 20:41:37 -0700310 size_t ReferenceCount() const;
311 // Location where the segment state of the local indirect reference table is saved
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700312 FrameOffset SavedLocalReferenceCookieOffset() const;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700313 // Location where the return value of a call can be squirreled if another
314 // call is made following the native call
Ian Rogersdc51b792011-09-22 20:41:37 -0700315 FrameOffset ReturnValueSaveLocation() const;
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700316 // Register that holds result if it is integer.
317 virtual ManagedRegister IntReturnRegister() = 0;
Andreas Gamped1104322014-05-01 14:38:56 -0700318 // Whether the compiler needs to ensure zero-/sign-extension of a small result type
319 virtual bool RequiresSmallResultTypeExtension() const = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700320
Ian Rogersbdb03912011-09-14 00:55:44 -0700321 // Callee save registers to spill prior to native code (which may clobber)
Vladimir Marko32248382016-05-19 10:37:24 +0100322 virtual ArrayRef<const ManagedRegister> CalleeSaveRegisters() const = 0;
Ian Rogersbdb03912011-09-14 00:55:44 -0700323
324 // Spill mask values
325 virtual uint32_t CoreSpillMask() const = 0;
326 virtual uint32_t FpSpillMask() const = 0;
Ian Rogers0d666d82011-08-14 16:03:46 -0700327
Ian Rogersdc51b792011-09-22 20:41:37 -0700328 // An extra scratch register live after the call
329 virtual ManagedRegister ReturnScratchRegister() const = 0;
330
Ian Rogersb033c752011-07-20 12:22:35 -0700331 // Iterator interface
332 bool HasNext();
Ian Rogers67375ac2011-09-14 00:55:44 -0700333 virtual void Next();
Ian Rogersb033c752011-07-20 12:22:35 -0700334 bool IsCurrentParamAReference();
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700335 bool IsCurrentParamAFloatOrDouble();
Serban Constantinescu75b91132014-04-09 18:39:10 +0100336 bool IsCurrentParamADouble();
337 bool IsCurrentParamALong();
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700338 bool IsCurrentParamALongOrDouble() {
339 return IsCurrentParamALong() || IsCurrentParamADouble();
340 }
Serban Constantinescu75b91132014-04-09 18:39:10 +0100341 bool IsCurrentParamJniEnv();
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700342 size_t CurrentParamSize() const;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700343 virtual bool IsCurrentParamInRegister() = 0;
344 virtual bool IsCurrentParamOnStack() = 0;
345 virtual ManagedRegister CurrentParamRegister() = 0;
346 virtual FrameOffset CurrentParamStackOffset() = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700347
348 // Iterator interface extension for JNI
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700349 FrameOffset CurrentParamHandleScopeEntryOffset();
Ian Rogersb033c752011-07-20 12:22:35 -0700350
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700351 // Position of handle scope and interior fields
352 FrameOffset HandleScopeOffset() const {
Andreas Gampe542451c2016-07-26 09:02:02 -0700353 return FrameOffset(this->displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
Andreas Gampecf4035a2014-05-28 22:43:01 -0700354 // above Method reference
Ian Rogersb033c752011-07-20 12:22:35 -0700355 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700356
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700357 FrameOffset HandleScopeLinkOffset() const {
Mathieu Chartiere401d142015-04-22 13:56:20 -0700358 return FrameOffset(HandleScopeOffset().Int32Value() +
359 HandleScope::LinkOffset(frame_pointer_size_));
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700360 }
361
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700362 FrameOffset HandleScopeNumRefsOffset() const {
363 return FrameOffset(HandleScopeOffset().Int32Value() +
364 HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700365 }
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700366
Mathieu Chartiere401d142015-04-22 13:56:20 -0700367 FrameOffset HandleReferencesOffset() const {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700368 return FrameOffset(HandleScopeOffset().Int32Value() +
369 HandleScope::ReferencesOffset(frame_pointer_size_));
Ian Rogersb033c752011-07-20 12:22:35 -0700370 }
371
Ian Rogers2c8f6532011-09-02 17:16:34 -0700372 virtual ~JniCallingConvention() {}
373
Vladimir Marko1c3c1062019-12-03 11:18:44 +0000374 bool IsCriticalNative() const {
375 return is_critical_native_;
376 }
377
378 // Does the transition have a method pointer in the stack frame?
379 bool SpillsMethod() const {
380 // Exclude method pointer for @CriticalNative methods for optimization speed.
381 return !IsCriticalNative();
382 }
383
384 // Hidden argument register, used to pass the method pointer for @CriticalNative call.
385 virtual ManagedRegister HiddenArgumentRegister() const = 0;
386
387 // Whether to use tail call (used only for @CriticalNative).
388 virtual bool UseTailCall() const = 0;
389
390 // Whether the return type is small. Used for RequiresSmallResultTypeExtension()
391 // on architectures that require the sign/zero extension.
392 bool HasSmallReturnType() const {
393 Primitive::Type return_type = GetReturnType();
394 return return_type == Primitive::kPrimByte ||
395 return_type == Primitive::kPrimShort ||
396 return_type == Primitive::kPrimBoolean ||
397 return_type == Primitive::kPrimChar;
398 }
399
Ian Rogers2c8f6532011-09-02 17:16:34 -0700400 protected:
Ian Rogersb033c752011-07-20 12:22:35 -0700401 // Named iterator positions
402 enum IteratorPos {
403 kJniEnv = 0,
404 kObjectOrClass = 1
405 };
406
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700407 JniCallingConvention(bool is_static,
408 bool is_synchronized,
409 bool is_critical_native,
410 const char* shorty,
411 PointerSize frame_pointer_size)
412 : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size),
413 is_critical_native_(is_critical_native) {}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700414
Ian Rogers2c8f6532011-09-02 17:16:34 -0700415 protected:
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700416 size_t NumberOfExtraArgumentsForJni() const;
417
418 // Does the transition have a StackHandleScope?
Vladimir Marko1c3c1062019-12-03 11:18:44 +0000419 bool HasHandleScope() const {
420 // Exclude HandleScope for @CriticalNative methods for optimization speed.
421 return !IsCriticalNative();
422 }
423
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700424 // Does the transition have a local reference segment state?
Vladimir Marko1c3c1062019-12-03 11:18:44 +0000425 bool HasLocalReferenceSegmentState() const {
426 // Exclude local reference segment states for @CriticalNative methods for optimization speed.
427 return !IsCriticalNative();
428 }
429
430 // Does the transition back spill the return value in the stack frame?
431 bool SpillsReturnValue() const {
432 // Exclude return value for @CriticalNative methods for optimization speed.
433 return !IsCriticalNative();
434 }
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700435
436 // Are there extra JNI arguments (JNIEnv* and maybe jclass)?
Vladimir Marko1c3c1062019-12-03 11:18:44 +0000437 bool HasExtraArgumentsForJni() const {
438 // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters.
439 return !IsCriticalNative();
440 }
441
442 // Has a JNIEnv* parameter implicitly?
443 bool HasJniEnv() const {
444 // Exclude "JNIEnv*" parameter for @CriticalNative methods.
445 return HasExtraArgumentsForJni();
446 }
447
448 // Has a 'jclass' parameter implicitly?
449 bool HasSelfClass() const;
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700450
451 // Returns the position of itr_args_, fixed up by removing the offset of extra JNI arguments.
452 unsigned int GetIteratorPositionWithinShorty() const;
453
454 // Is the current argument (at the iterator) an extra argument for JNI?
455 bool IsCurrentArgExtraForJni() const;
456
457 const bool is_critical_native_;
458
459 private:
460 // Shorthand for switching on the switch value but only IF there are extra JNI arguments.
461 //
462 // Puts the case value into return_value.
463 // * (switch_value == kJniEnv) => case_jni_env
464 // * (switch_value == kObjectOrClass) => case_object_or_class
465 //
466 // Returns false otherwise (or if there are no extra JNI arguments).
467 bool SwitchExtraJniArguments(size_t switch_value,
468 bool case_jni_env,
469 bool case_object_or_class,
470 /* out parameters */
471 bool* return_value) const;
Ian Rogersb033c752011-07-20 12:22:35 -0700472};
473
474} // namespace art
475
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700476#endif // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_