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