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