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 "base/arena_object.h"
21#include "base/array_ref.h"
22#include "base/enums.h"
23#include "handle_scope.h"
24#include "primitive.h"
25#include "thread.h"
26#include "utils/managed_register.h"
27
28namespace art {
29
30// Top-level abstraction for different calling conventions.
31class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConvention> {
32 public:
33  bool IsReturnAReference() const { return shorty_[0] == 'L'; }
34
35  Primitive::Type GetReturnType() const {
36    return Primitive::GetType(shorty_[0]);
37  }
38
39  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  }
46
47  // Register that holds result of this method invocation.
48  virtual ManagedRegister ReturnRegister() = 0;
49  // Register reserved for scratch usage during procedure calls.
50  virtual ManagedRegister InterproceduralScratchRegister() = 0;
51
52  // Offset of Method within the frame.
53  FrameOffset MethodStackOffset() {
54    return displacement_;
55  }
56
57  // 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;
64    itr_slots_ = 0;
65    itr_args_ = 0;
66    itr_refs_ = 0;
67    itr_longs_and_doubles_ = 0;
68    itr_float_and_doubles_ = 0;
69  }
70
71  virtual ~CallingConvention() {}
72
73 protected:
74  CallingConvention(bool is_static,
75                    bool is_synchronized,
76                    const char* shorty,
77                    PointerSize frame_pointer_size)
78      : 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),
81        handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)),
82        is_static_(is_static), is_synchronized_(is_synchronized),
83        shorty_(shorty) {
84    num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1;
85    num_ref_args_ = is_static ? 0 : 1;  // The implicit this pointer.
86    num_float_or_double_args_ = 0;
87    num_long_or_double_args_ = 0;
88    for (size_t i = 1; i < strlen(shorty); i++) {
89      char ch = shorty_[i];
90      switch (ch) {
91      case 'L':
92        num_ref_args_++;
93        break;
94      case 'J':
95        num_long_or_double_args_++;
96        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;
104      }
105    }
106  }
107
108  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  }
124  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  }
134  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) {
148      return false;  // this argument
149    }
150    return shorty_[param] == 'J';
151  }
152  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';
160  }
161  size_t NumArgs() const {
162    return num_args_;
163  }
164  // Implicit argument count: 1 for instance functions, 0 for static functions.
165  // (The implicit argument is only relevant to the shorty, i.e.
166  // the 0th arg is not in the shorty if it's implicit).
167  size_t NumImplicitArgs() const {
168    return IsStatic() ? 0 : 1;
169  }
170  size_t NumLongOrDoubleArgs() const {
171    return num_long_or_double_args_;
172  }
173  size_t NumFloatOrDoubleArgs() const {
174    return num_float_or_double_args_;
175  }
176  size_t NumReferenceArgs() const {
177    return num_ref_args_;
178  }
179  size_t ParamSize(unsigned int param) const {
180    DCHECK_LT(param, NumArgs());
181    if (IsStatic()) {
182      param++;  // 0th argument must skip return value at start of the shorty
183    } else if (param == 0) {
184      return sizeof(mirror::HeapReference<mirror::Object>);  // this argument
185    }
186    size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[param]));
187    if (result >= 1 && result < 4) {
188      result = 4;
189    }
190    return result;
191  }
192  const char* GetShorty() const {
193    return shorty_.c_str();
194  }
195  // The slot number for current calling_convention argument.
196  // Note that each slot is 32-bit. When the current argument is bigger
197  // than 32 bits, return the first slot number for this argument.
198  unsigned int itr_slots_;
199  // The number of references iterated past.
200  unsigned int itr_refs_;
201  // The argument number along argument list for current argument.
202  unsigned int itr_args_;
203  // Number of longs and doubles seen along argument list.
204  unsigned int itr_longs_and_doubles_;
205  // Number of float and doubles seen along argument list.
206  unsigned int itr_float_and_doubles_;
207  // Space for frames below this on the stack.
208  FrameOffset displacement_;
209  // The size of a pointer.
210  const PointerSize frame_pointer_size_;
211  // The size of a reference entry within the handle scope.
212  const size_t handle_scope_pointer_size_;
213
214 private:
215  const bool is_static_;
216  const bool is_synchronized_;
217  std::string shorty_;
218  size_t num_args_;
219  size_t num_ref_args_;
220  size_t num_float_or_double_args_;
221  size_t num_long_or_double_args_;
222};
223
224// Abstraction for managed code's calling conventions
225// | { Incoming stack args } |
226// | { Prior Method* }       | <-- Prior SP
227// | { Return address }      |
228// | { Callee saves }        |
229// | { Spills ... }          |
230// | { Outgoing stack args } |
231// | { Method* }             | <-- SP
232class ManagedRuntimeCallingConvention : public CallingConvention {
233 public:
234  static std::unique_ptr<ManagedRuntimeCallingConvention> Create(ArenaAllocator* arena,
235                                                                 bool is_static,
236                                                                 bool is_synchronized,
237                                                                 const char* shorty,
238                                                                 InstructionSet instruction_set);
239
240  // Register that holds the incoming method argument
241  virtual ManagedRegister MethodRegister() = 0;
242
243  // Iterator interface
244  bool HasNext();
245  void Next();
246  bool IsCurrentParamAReference();
247  bool IsCurrentParamAFloatOrDouble();
248  bool IsCurrentParamADouble();
249  bool IsCurrentParamALong();
250  bool IsCurrentArgExplicit();  // ie a non-implict argument such as this
251  bool IsCurrentArgPossiblyNull();
252  size_t CurrentParamSize();
253  virtual bool IsCurrentParamInRegister() = 0;
254  virtual bool IsCurrentParamOnStack() = 0;
255  virtual ManagedRegister CurrentParamRegister() = 0;
256  virtual FrameOffset CurrentParamStackOffset() = 0;
257
258  virtual ~ManagedRuntimeCallingConvention() {}
259
260  // Registers to spill to caller's out registers on entry.
261  virtual const ManagedRegisterEntrySpills& EntrySpills() = 0;
262
263 protected:
264  ManagedRuntimeCallingConvention(bool is_static,
265                                  bool is_synchronized,
266                                  const char* shorty,
267                                  PointerSize frame_pointer_size)
268      : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size) {}
269};
270
271// Abstraction for JNI calling conventions
272// | { Incoming stack args }         | <-- Prior SP
273// | { Return address }              |
274// | { Callee saves }                |     ([1])
275// | { Return value spill }          |     (live on return slow paths)
276// | { Local Ref. Table State }      |
277// | { Stack Indirect Ref. Table     |
278// |   num. refs./link }             |     (here to prior SP is frame size)
279// | { Method* }                     | <-- Anchor SP written to thread
280// | { Outgoing stack args }         | <-- SP at point of call
281// | Native frame                    |
282//
283// [1] We must save all callee saves here to enable any exception throws to restore
284// callee saves for frames above this one.
285class JniCallingConvention : public CallingConvention {
286 public:
287  static std::unique_ptr<JniCallingConvention> Create(ArenaAllocator* arena,
288                                                      bool is_static,
289                                                      bool is_synchronized,
290                                                      bool is_critical_native,
291                                                      const char* shorty,
292                                                      InstructionSet instruction_set);
293
294  // Size of frame excluding space for outgoing args (its assumed Method* is
295  // always at the bottom of a frame, but this doesn't work for outgoing
296  // native args). Includes alignment.
297  virtual size_t FrameSize() = 0;
298  // Size of outgoing arguments (stack portion), including alignment.
299  // -- Arguments that are passed via registers are excluded from this size.
300  virtual size_t OutArgSize() = 0;
301  // Number of references in stack indirect reference table
302  size_t ReferenceCount() const;
303  // Location where the segment state of the local indirect reference table is saved
304  FrameOffset SavedLocalReferenceCookieOffset() const;
305  // Location where the return value of a call can be squirreled if another
306  // call is made following the native call
307  FrameOffset ReturnValueSaveLocation() const;
308  // Register that holds result if it is integer.
309  virtual ManagedRegister IntReturnRegister() = 0;
310  // Whether the compiler needs to ensure zero-/sign-extension of a small result type
311  virtual bool RequiresSmallResultTypeExtension() const = 0;
312
313  // Callee save registers to spill prior to native code (which may clobber)
314  virtual ArrayRef<const ManagedRegister> CalleeSaveRegisters() const = 0;
315
316  // Spill mask values
317  virtual uint32_t CoreSpillMask() const = 0;
318  virtual uint32_t FpSpillMask() const = 0;
319
320  // An extra scratch register live after the call
321  virtual ManagedRegister ReturnScratchRegister() const = 0;
322
323  // Iterator interface
324  bool HasNext();
325  virtual void Next();
326  bool IsCurrentParamAReference();
327  bool IsCurrentParamAFloatOrDouble();
328  bool IsCurrentParamADouble();
329  bool IsCurrentParamALong();
330  bool IsCurrentParamALongOrDouble() {
331    return IsCurrentParamALong() || IsCurrentParamADouble();
332  }
333  bool IsCurrentParamJniEnv();
334  size_t CurrentParamSize() const;
335  virtual bool IsCurrentParamInRegister() = 0;
336  virtual bool IsCurrentParamOnStack() = 0;
337  virtual ManagedRegister CurrentParamRegister() = 0;
338  virtual FrameOffset CurrentParamStackOffset() = 0;
339
340  // Iterator interface extension for JNI
341  FrameOffset CurrentParamHandleScopeEntryOffset();
342
343  // Position of handle scope and interior fields
344  FrameOffset HandleScopeOffset() const {
345    return FrameOffset(this->displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
346    // above Method reference
347  }
348
349  FrameOffset HandleScopeLinkOffset() const {
350    return FrameOffset(HandleScopeOffset().Int32Value() +
351                       HandleScope::LinkOffset(frame_pointer_size_));
352  }
353
354  FrameOffset HandleScopeNumRefsOffset() const {
355    return FrameOffset(HandleScopeOffset().Int32Value() +
356                       HandleScope::NumberOfReferencesOffset(frame_pointer_size_));
357  }
358
359  FrameOffset HandleReferencesOffset() const {
360    return FrameOffset(HandleScopeOffset().Int32Value() +
361                       HandleScope::ReferencesOffset(frame_pointer_size_));
362  }
363
364  virtual ~JniCallingConvention() {}
365
366 protected:
367  // Named iterator positions
368  enum IteratorPos {
369    kJniEnv = 0,
370    kObjectOrClass = 1
371  };
372
373  JniCallingConvention(bool is_static,
374                       bool is_synchronized,
375                       bool is_critical_native,
376                       const char* shorty,
377                       PointerSize frame_pointer_size)
378      : CallingConvention(is_static, is_synchronized, shorty, frame_pointer_size),
379        is_critical_native_(is_critical_native) {}
380
381  // Number of stack slots for outgoing arguments, above which the handle scope is
382  // located
383  virtual size_t NumberOfOutgoingStackArgs() = 0;
384
385 protected:
386  size_t NumberOfExtraArgumentsForJni() const;
387
388  // Does the transition have a StackHandleScope?
389  bool HasHandleScope() const;
390  // Does the transition have a local reference segment state?
391  bool HasLocalReferenceSegmentState() const;
392  // Has a JNIEnv* parameter implicitly?
393  bool HasJniEnv() const;
394  // Has a 'jclass' parameter implicitly?
395  bool HasSelfClass() const;
396
397  // Are there extra JNI arguments (JNIEnv* and maybe jclass)?
398  bool HasExtraArgumentsForJni() const;
399
400  // Returns the position of itr_args_, fixed up by removing the offset of extra JNI arguments.
401  unsigned int GetIteratorPositionWithinShorty() const;
402
403  // Is the current argument (at the iterator) an extra argument for JNI?
404  bool IsCurrentArgExtraForJni() const;
405
406  const bool is_critical_native_;
407
408 private:
409  // Shorthand for switching on the switch value but only IF there are extra JNI arguments.
410  //
411  // Puts the case value into return_value.
412  // * (switch_value == kJniEnv) => case_jni_env
413  // * (switch_value == kObjectOrClass) => case_object_or_class
414  //
415  // Returns false otherwise (or if there are no extra JNI arguments).
416  bool SwitchExtraJniArguments(size_t switch_value,
417                               bool case_jni_env,
418                               bool case_object_or_class,
419                               /* out parameters */
420                               bool* return_value) const;
421};
422
423}  // namespace art
424
425#endif  // ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
426