1/*
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 */
16
17#ifndef ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
18#define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
19
20#include <vector>
21#include "handle_scope.h"
22#include "primitive.h"
23#include "thread.h"
24#include "utils/managed_register.h"
25
26namespace art {
27
28// Top-level abstraction for different calling conventions.
29class CallingConvention {
30 public:
31  bool IsReturnAReference() const { return shorty_[0] == 'L'; }
32
33  Primitive::Type GetReturnType() const {
34    return Primitive::GetType(shorty_[0]);
35  }
36
37  size_t SizeOfReturnValue() const {
38    size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
39    if (result >= 1 && result < 4) {
40      result = 4;
41    }
42    return result;
43  }
44
45  // Register that holds result of this method invocation.
46  virtual ManagedRegister ReturnRegister() = 0;
47  // Register reserved for scratch usage during procedure calls.
48  virtual ManagedRegister InterproceduralScratchRegister() = 0;
49
50  // Offset of Method within the frame.
51  FrameOffset MethodStackOffset() {
52    return displacement_;
53  }
54
55  // Iterator interface
56
57  // Place iterator at start of arguments. The displacement is applied to
58  // frame offset methods to account for frames which may be on the stack
59  // below the one being iterated over.
60  void ResetIterator(FrameOffset displacement) {
61    displacement_ = displacement;
62    itr_slots_ = 0;
63    itr_args_ = 0;
64    itr_refs_ = 0;
65    itr_longs_and_doubles_ = 0;
66    itr_float_and_doubles_ = 0;
67  }
68
69  virtual ~CallingConvention() {}
70
71 protected:
72  CallingConvention(bool is_static, bool is_synchronized, const char* shorty,
73                    size_t frame_pointer_size)
74      : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0),
75        itr_float_and_doubles_(0), displacement_(0),
76        frame_pointer_size_(frame_pointer_size),
77        handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
78        is_static_(is_static), is_synchronized_(is_synchronized),
79        shorty_(shorty) {
80    num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
81    num_ref_args_ = is_static ? 0 : 1;  // The implicit this pointer.
82    num_float_or_double_args_ = 0;
83    num_long_or_double_args_ = 0;
84    for (size_t i = 1; i < strlen(shorty); i++) {
85      char ch = shorty_[i];
86      switch (ch) {
87      case 'L':
88        num_ref_args_++;
89        break;
90      case 'J':
91        num_long_or_double_args_++;
92        break;
93      case 'D':
94        num_long_or_double_args_++;
95        num_float_or_double_args_++;
96        break;
97      case 'F':
98        num_float_or_double_args_++;
99        break;
100      }
101    }
102  }
103
104  bool IsStatic() const {
105    return is_static_;
106  }
107  bool IsSynchronized() const {
108    return is_synchronized_;
109  }
110  bool IsParamALongOrDouble(unsigned int param) const {
111    DCHECK_LT(param, NumArgs());
112    if (IsStatic()) {
113      param++;  // 0th argument must skip return value at start of the shorty
114    } else if (param == 0) {
115      return false;  // this argument
116    }
117    char ch = shorty_[param];
118    return (ch == 'J' || ch == 'D');
119  }
120  bool IsParamAFloatOrDouble(unsigned int param) const {
121    DCHECK_LT(param, NumArgs());
122    if (IsStatic()) {
123      param++;  // 0th argument must skip return value at start of the shorty
124    } else if (param == 0) {
125      return false;  // this argument
126    }
127    char ch = shorty_[param];
128    return (ch == 'F' || ch == 'D');
129  }
130  bool IsParamADouble(unsigned int param) const {
131    DCHECK_LT(param, NumArgs());
132    if (IsStatic()) {
133      param++;  // 0th argument must skip return value at start of the shorty
134    } else if (param == 0) {
135      return false;  // this argument
136    }
137    return shorty_[param] == 'D';
138  }
139  bool IsParamALong(unsigned int param) const {
140    DCHECK_LT(param, NumArgs());
141    if (IsStatic()) {
142      param++;  // 0th argument must skip return value at start of the shorty
143    } else if (param == 0) {
144      return true;  // this argument
145    }
146    return shorty_[param] == 'J';
147  }
148  bool IsParamAReference(unsigned int param) const {
149    DCHECK_LT(param, NumArgs());
150    if (IsStatic()) {
151      param++;  // 0th argument must skip return value at start of the shorty
152    } else if (param == 0) {
153      return true;  // this argument
154    }
155    return shorty_[param] == 'L';
156  }
157  size_t NumArgs() const {
158    return num_args_;
159  }
160  size_t NumLongOrDoubleArgs() const {
161    return num_long_or_double_args_;
162  }
163  size_t NumFloatOrDoubleArgs() const {
164    return num_float_or_double_args_;
165  }
166  size_t NumReferenceArgs() const {
167    return num_ref_args_;
168  }
169  size_t ParamSize(unsigned int param) const {
170    DCHECK_LT(param, NumArgs());
171    if (IsStatic()) {
172      param++;  // 0th argument must skip return value at start of the shorty
173    } else if (param == 0) {
174      return frame_pointer_size_;  // this argument
175    }
176    size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
177    if (result >= 1 && result < 4) {
178      result = 4;
179    }
180    return result;
181  }
182  const char* GetShorty() const {
183    return shorty_.c_str();
184  }
185  // The slot number for current calling_convention argument.
186  // Note that each slot is 32-bit. When the current argument is bigger
187  // than 32 bits, return the first slot number for this argument.
188  unsigned int itr_slots_;
189  // The number of references iterated past.
190  unsigned int itr_refs_;
191  // The argument number along argument list for current argument.
192  unsigned int itr_args_;
193  // Number of longs and doubles seen along argument list.
194  unsigned int itr_longs_and_doubles_;
195  // Number of float and doubles seen along argument list.
196  unsigned int itr_float_and_doubles_;
197  // Space for frames below this on the stack.
198  FrameOffset displacement_;
199  // The size of a reference.
200  const size_t frame_pointer_size_;
201  // The size of a reference entry within the handle scope.
202  const size_t handle_scope_pointer_size_;
203
204 private:
205  const bool is_static_;
206  const bool is_synchronized_;
207  std::string shorty_;
208  size_t num_args_;
209  size_t num_ref_args_;
210  size_t num_float_or_double_args_;
211  size_t num_long_or_double_args_;
212};
213
214// Abstraction for managed code's calling conventions
215// | { Incoming stack args } |
216// | { Prior Method* }       | <-- Prior SP
217// | { Return address }      |
218// | { Callee saves }        |
219// | { Spills ... }          |
220// | { Outgoing stack args } |
221// | { Method* }             | <-- SP
222class ManagedRuntimeCallingConvention : public CallingConvention {
223 public:
224  static ManagedRuntimeCallingConvention* Create(bool is_static, bool is_synchronized,
225                                                 const char* shorty,
226                                                 InstructionSet instruction_set);
227
228  // Register that holds the incoming method argument
229  virtual ManagedRegister MethodRegister() = 0;
230
231  // Iterator interface
232  bool HasNext();
233  void Next();
234  bool IsCurrentParamAReference();
235  bool IsCurrentParamAFloatOrDouble();
236  bool IsCurrentParamADouble();
237  bool IsCurrentParamALong();
238  bool IsCurrentArgExplicit();  // ie a non-implict argument such as this
239  bool IsCurrentArgPossiblyNull();
240  size_t CurrentParamSize();
241  virtual bool IsCurrentParamInRegister() = 0;
242  virtual bool IsCurrentParamOnStack() = 0;
243  virtual ManagedRegister CurrentParamRegister() = 0;
244  virtual FrameOffset CurrentParamStackOffset() = 0;
245
246  virtual ~ManagedRuntimeCallingConvention() {}
247
248  // Registers to spill to caller's out registers on entry.
249  virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
250
251 protected:
252  ManagedRuntimeCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
253                                  size_t frame_pointer_size)
254      : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
255};
256
257// Abstraction for JNI calling conventions
258// | { Incoming stack args }         | <-- Prior SP
259// | { Return address }              |
260// | { Callee saves }                |     ([1])
261// | { Return value spill }          |     (live on return slow paths)
262// | { Local Ref. Table State }      |
263// | { Stack Indirect Ref. Table     |
264// |   num. refs./link }             |     (here to prior SP is frame size)
265// | { Method* }                     | <-- Anchor SP written to thread
266// | { Outgoing stack args }         | <-- SP at point of call
267// | Native frame                    |
268//
269// [1] We must save all callee saves here to enable any exception throws to restore
270// callee saves for frames above this one.
271class JniCallingConvention : public CallingConvention {
272 public:
273  static JniCallingConvention* Create(bool is_static, bool is_synchronized, const char* shorty,
274                                      InstructionSet instruction_set);
275
276  // Size of frame excluding space for outgoing args (its assumed Method* is
277  // always at the bottom of a frame, but this doesn't work for outgoing
278  // native args). Includes alignment.
279  virtual size_t FrameSize() = 0;
280  // Size of outgoing arguments, including alignment
281  virtual size_t OutArgSize() = 0;
282  // Number of references in stack indirect reference table
283  size_t ReferenceCount() const;
284  // Location where the segment state of the local indirect reference table is saved
285  FrameOffset SavedLocalReferenceCookieOffset() const;
286  // Location where the return value of a call can be squirreled if another
287  // call is made following the native call
288  FrameOffset ReturnValueSaveLocation() const;
289  // Register that holds result if it is integer.
290  virtual ManagedRegister IntReturnRegister() = 0;
291  // Whether the compiler needs to ensure zero-/sign-extension of a small result type
292  virtual bool RequiresSmallResultTypeExtension() const = 0;
293
294  // Callee save registers to spill prior to native code (which may clobber)
295  virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0;
296
297  // Spill mask values
298  virtual uint32_t CoreSpillMask() const = 0;
299  virtual uint32_t FpSpillMask() const = 0;
300
301  // An extra scratch register live after the call
302  virtual ManagedRegister ReturnScratchRegister() const = 0;
303
304  // Iterator interface
305  bool HasNext();
306  virtual void Next();
307  bool IsCurrentParamAReference();
308  bool IsCurrentParamAFloatOrDouble();
309  bool IsCurrentParamADouble();
310  bool IsCurrentParamALong();
311  bool IsCurrentParamJniEnv();
312  size_t CurrentParamSize();
313  virtual bool IsCurrentParamInRegister() = 0;
314  virtual bool IsCurrentParamOnStack() = 0;
315  virtual ManagedRegister CurrentParamRegister() = 0;
316  virtual FrameOffset CurrentParamStackOffset() = 0;
317
318  // Iterator interface extension for JNI
319  FrameOffset CurrentParamHandleScopeEntryOffset();
320
321  // Position of handle scope and interior fields
322  FrameOffset HandleScopeOffset() const {
323    return FrameOffset(this->displacement_.Int32Value() + sizeof(StackReference<mirror::ArtMethod>));
324    // above Method reference
325  }
326
327  FrameOffset HandleScopeLinkOffset() const {
328    return FrameOffset(HandleScopeOffset().Int32Value() + HandleScope::LinkOffset(frame_pointer_size_));
329  }
330
331  FrameOffset HandleScopeNumRefsOffset() const {
332    return FrameOffset(HandleScopeOffset().Int32Value() +
333                       HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
334  }
335
336  FrameOffset HandleerencesOffset() const {
337    return FrameOffset(HandleScopeOffset().Int32Value() +
338                       HandleScope::ReferencesOffset(frame_pointer_size_));
339  }
340
341  virtual ~JniCallingConvention() {}
342
343 protected:
344  // Named iterator positions
345  enum IteratorPos {
346    kJniEnv = 0,
347    kObjectOrClass = 1
348  };
349
350  explicit JniCallingConvention(bool is_static, bool is_synchronized, const char* shorty,
351                                size_t frame_pointer_size)
352      : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
353
354  // Number of stack slots for outgoing arguments, above which the handle scope is
355  // located
356  virtual size_t NumberOfOutgoingStackArgs() = 0;
357
358 protected:
359  size_t NumberOfExtraArgumentsForJni();
360};
361
362}  // namespace art
363
364#endif  // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
365