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 #include "calling_convention.h"
18 
19 #include "base/logging.h"
20 #include "jni/quick/arm/calling_convention_arm.h"
21 #include "jni/quick/arm64/calling_convention_arm64.h"
22 #include "jni/quick/mips/calling_convention_mips.h"
23 #include "jni/quick/mips64/calling_convention_mips64.h"
24 #include "jni/quick/x86/calling_convention_x86.h"
25 #include "jni/quick/x86_64/calling_convention_x86_64.h"
26 
27 namespace art {
28 
29 // Managed runtime calling convention
30 
Create(bool is_static,bool is_synchronized,const char * shorty,InstructionSet instruction_set)31 ManagedRuntimeCallingConvention* ManagedRuntimeCallingConvention::Create(
32     bool is_static, bool is_synchronized, const char* shorty, InstructionSet instruction_set) {
33   switch (instruction_set) {
34     case kArm:
35     case kThumb2:
36       return new arm::ArmManagedRuntimeCallingConvention(is_static, is_synchronized, shorty);
37     case kArm64:
38       return new arm64::Arm64ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty);
39     case kMips:
40       return new mips::MipsManagedRuntimeCallingConvention(is_static, is_synchronized, shorty);
41     case kMips64:
42       return new mips64::Mips64ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty);
43     case kX86:
44       return new x86::X86ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty);
45     case kX86_64:
46       return new x86_64::X86_64ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty);
47     default:
48       LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
49       return nullptr;
50   }
51 }
52 
HasNext()53 bool ManagedRuntimeCallingConvention::HasNext() {
54   return itr_args_ < NumArgs();
55 }
56 
Next()57 void ManagedRuntimeCallingConvention::Next() {
58   CHECK(HasNext());
59   if (IsCurrentArgExplicit() &&  // don't query parameter type of implicit args
60       IsParamALongOrDouble(itr_args_)) {
61     itr_longs_and_doubles_++;
62     itr_slots_++;
63   }
64   if (IsParamAFloatOrDouble(itr_args_)) {
65     itr_float_and_doubles_++;
66   }
67   if (IsCurrentParamAReference()) {
68     itr_refs_++;
69   }
70   itr_args_++;
71   itr_slots_++;
72 }
73 
IsCurrentArgExplicit()74 bool ManagedRuntimeCallingConvention::IsCurrentArgExplicit() {
75   // Static methods have no implicit arguments, others implicitly pass this
76   return IsStatic() || (itr_args_ != 0);
77 }
78 
IsCurrentArgPossiblyNull()79 bool ManagedRuntimeCallingConvention::IsCurrentArgPossiblyNull() {
80   return IsCurrentArgExplicit();  // any user parameter may be null
81 }
82 
CurrentParamSize()83 size_t ManagedRuntimeCallingConvention::CurrentParamSize() {
84   return ParamSize(itr_args_);
85 }
86 
IsCurrentParamAReference()87 bool ManagedRuntimeCallingConvention::IsCurrentParamAReference() {
88   return IsParamAReference(itr_args_);
89 }
90 
IsCurrentParamAFloatOrDouble()91 bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() {
92   return IsParamAFloatOrDouble(itr_args_);
93 }
94 
IsCurrentParamADouble()95 bool ManagedRuntimeCallingConvention::IsCurrentParamADouble() {
96   return IsParamADouble(itr_args_);
97 }
98 
IsCurrentParamALong()99 bool ManagedRuntimeCallingConvention::IsCurrentParamALong() {
100   return IsParamALong(itr_args_);
101 }
102 
103 // JNI calling convention
104 
Create(bool is_static,bool is_synchronized,const char * shorty,InstructionSet instruction_set)105 JniCallingConvention* JniCallingConvention::Create(bool is_static, bool is_synchronized,
106                                                    const char* shorty,
107                                                    InstructionSet instruction_set) {
108   switch (instruction_set) {
109     case kArm:
110     case kThumb2:
111       return new arm::ArmJniCallingConvention(is_static, is_synchronized, shorty);
112     case kArm64:
113       return new arm64::Arm64JniCallingConvention(is_static, is_synchronized, shorty);
114     case kMips:
115       return new mips::MipsJniCallingConvention(is_static, is_synchronized, shorty);
116     case kMips64:
117       return new mips64::Mips64JniCallingConvention(is_static, is_synchronized, shorty);
118     case kX86:
119       return new x86::X86JniCallingConvention(is_static, is_synchronized, shorty);
120     case kX86_64:
121       return new x86_64::X86_64JniCallingConvention(is_static, is_synchronized, shorty);
122     default:
123       LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
124       return nullptr;
125   }
126 }
127 
ReferenceCount() const128 size_t JniCallingConvention::ReferenceCount() const {
129   return NumReferenceArgs() + (IsStatic() ? 1 : 0);
130 }
131 
SavedLocalReferenceCookieOffset() const132 FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
133   size_t references_size = handle_scope_pointer_size_ * ReferenceCount();  // size excluding header
134   return FrameOffset(HandleReferencesOffset().Int32Value() + references_size);
135 }
136 
ReturnValueSaveLocation() const137 FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
138   // Segment state is 4 bytes long
139   return FrameOffset(SavedLocalReferenceCookieOffset().Int32Value() + 4);
140 }
141 
HasNext()142 bool JniCallingConvention::HasNext() {
143   if (itr_args_ <= kObjectOrClass) {
144     return true;
145   } else {
146     unsigned int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
147     return arg_pos < NumArgs();
148   }
149 }
150 
Next()151 void JniCallingConvention::Next() {
152   CHECK(HasNext());
153   if (itr_args_ > kObjectOrClass) {
154     int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
155     if (IsParamALongOrDouble(arg_pos)) {
156       itr_longs_and_doubles_++;
157       itr_slots_++;
158     }
159   }
160   if (IsCurrentParamAFloatOrDouble()) {
161     itr_float_and_doubles_++;
162   }
163   if (IsCurrentParamAReference()) {
164     itr_refs_++;
165   }
166   itr_args_++;
167   itr_slots_++;
168 }
169 
IsCurrentParamAReference()170 bool JniCallingConvention::IsCurrentParamAReference() {
171   switch (itr_args_) {
172     case kJniEnv:
173       return false;  // JNIEnv*
174     case kObjectOrClass:
175       return true;   // jobject or jclass
176     default: {
177       int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
178       return IsParamAReference(arg_pos);
179     }
180   }
181 }
182 
IsCurrentParamJniEnv()183 bool JniCallingConvention::IsCurrentParamJniEnv() {
184   return (itr_args_ == kJniEnv);
185 }
186 
IsCurrentParamAFloatOrDouble()187 bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
188   switch (itr_args_) {
189     case kJniEnv:
190       return false;  // JNIEnv*
191     case kObjectOrClass:
192       return false;   // jobject or jclass
193     default: {
194       int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
195       return IsParamAFloatOrDouble(arg_pos);
196     }
197   }
198 }
199 
IsCurrentParamADouble()200 bool JniCallingConvention::IsCurrentParamADouble() {
201   switch (itr_args_) {
202     case kJniEnv:
203       return false;  // JNIEnv*
204     case kObjectOrClass:
205       return false;   // jobject or jclass
206     default: {
207       int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
208       return IsParamADouble(arg_pos);
209     }
210   }
211 }
212 
IsCurrentParamALong()213 bool JniCallingConvention::IsCurrentParamALong() {
214   switch (itr_args_) {
215     case kJniEnv:
216       return false;  // JNIEnv*
217     case kObjectOrClass:
218       return false;   // jobject or jclass
219     default: {
220       int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
221       return IsParamALong(arg_pos);
222     }
223   }
224 }
225 
226 // Return position of handle scope entry holding reference at the current iterator
227 // position
CurrentParamHandleScopeEntryOffset()228 FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
229   CHECK(IsCurrentParamAReference());
230   CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
231   int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
232   CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
233   return FrameOffset(result);
234 }
235 
CurrentParamSize()236 size_t JniCallingConvention::CurrentParamSize() {
237   if (itr_args_ <= kObjectOrClass) {
238     return frame_pointer_size_;  // JNIEnv or jobject/jclass
239   } else {
240     int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
241     return ParamSize(arg_pos);
242   }
243 }
244 
NumberOfExtraArgumentsForJni()245 size_t JniCallingConvention::NumberOfExtraArgumentsForJni() {
246   // The first argument is the JNIEnv*.
247   // Static methods have an extra argument which is the jclass.
248   return IsStatic() ? 2 : 1;
249 }
250 
251 }  // namespace art
252