Home | History | Annotate | Download | only in quick
      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 <android-base/logging.h>
     20 
     21 #include "arch/instruction_set.h"
     22 
     23 #ifdef ART_ENABLE_CODEGEN_arm
     24 #include "jni/quick/arm/calling_convention_arm.h"
     25 #endif
     26 
     27 #ifdef ART_ENABLE_CODEGEN_arm64
     28 #include "jni/quick/arm64/calling_convention_arm64.h"
     29 #endif
     30 
     31 #ifdef ART_ENABLE_CODEGEN_mips
     32 #include "jni/quick/mips/calling_convention_mips.h"
     33 #endif
     34 
     35 #ifdef ART_ENABLE_CODEGEN_mips64
     36 #include "jni/quick/mips64/calling_convention_mips64.h"
     37 #endif
     38 
     39 #ifdef ART_ENABLE_CODEGEN_x86
     40 #include "jni/quick/x86/calling_convention_x86.h"
     41 #endif
     42 
     43 #ifdef ART_ENABLE_CODEGEN_x86_64
     44 #include "jni/quick/x86_64/calling_convention_x86_64.h"
     45 #endif
     46 
     47 namespace art {
     48 
     49 // Managed runtime calling convention
     50 
     51 std::unique_ptr<ManagedRuntimeCallingConvention> ManagedRuntimeCallingConvention::Create(
     52     ArenaAllocator* allocator,
     53     bool is_static,
     54     bool is_synchronized,
     55     const char* shorty,
     56     InstructionSet instruction_set) {
     57   switch (instruction_set) {
     58 #ifdef ART_ENABLE_CODEGEN_arm
     59     case InstructionSet::kArm:
     60     case InstructionSet::kThumb2:
     61       return std::unique_ptr<ManagedRuntimeCallingConvention>(
     62           new (allocator) arm::ArmManagedRuntimeCallingConvention(
     63               is_static, is_synchronized, shorty));
     64 #endif
     65 #ifdef ART_ENABLE_CODEGEN_arm64
     66     case InstructionSet::kArm64:
     67       return std::unique_ptr<ManagedRuntimeCallingConvention>(
     68           new (allocator) arm64::Arm64ManagedRuntimeCallingConvention(
     69               is_static, is_synchronized, shorty));
     70 #endif
     71 #ifdef ART_ENABLE_CODEGEN_mips
     72     case InstructionSet::kMips:
     73       return std::unique_ptr<ManagedRuntimeCallingConvention>(
     74           new (allocator) mips::MipsManagedRuntimeCallingConvention(
     75               is_static, is_synchronized, shorty));
     76 #endif
     77 #ifdef ART_ENABLE_CODEGEN_mips64
     78     case InstructionSet::kMips64:
     79       return std::unique_ptr<ManagedRuntimeCallingConvention>(
     80           new (allocator) mips64::Mips64ManagedRuntimeCallingConvention(
     81               is_static, is_synchronized, shorty));
     82 #endif
     83 #ifdef ART_ENABLE_CODEGEN_x86
     84     case InstructionSet::kX86:
     85       return std::unique_ptr<ManagedRuntimeCallingConvention>(
     86           new (allocator) x86::X86ManagedRuntimeCallingConvention(
     87               is_static, is_synchronized, shorty));
     88 #endif
     89 #ifdef ART_ENABLE_CODEGEN_x86_64
     90     case InstructionSet::kX86_64:
     91       return std::unique_ptr<ManagedRuntimeCallingConvention>(
     92           new (allocator) x86_64::X86_64ManagedRuntimeCallingConvention(
     93               is_static, is_synchronized, shorty));
     94 #endif
     95     default:
     96       LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
     97       UNREACHABLE();
     98   }
     99 }
    100 
    101 bool ManagedRuntimeCallingConvention::HasNext() {
    102   return itr_args_ < NumArgs();
    103 }
    104 
    105 void ManagedRuntimeCallingConvention::Next() {
    106   CHECK(HasNext());
    107   if (IsCurrentArgExplicit() &&  // don't query parameter type of implicit args
    108       IsParamALongOrDouble(itr_args_)) {
    109     itr_longs_and_doubles_++;
    110     itr_slots_++;
    111   }
    112   if (IsParamAFloatOrDouble(itr_args_)) {
    113     itr_float_and_doubles_++;
    114   }
    115   if (IsCurrentParamAReference()) {
    116     itr_refs_++;
    117   }
    118   itr_args_++;
    119   itr_slots_++;
    120 }
    121 
    122 bool ManagedRuntimeCallingConvention::IsCurrentArgExplicit() {
    123   // Static methods have no implicit arguments, others implicitly pass this
    124   return IsStatic() || (itr_args_ != 0);
    125 }
    126 
    127 bool ManagedRuntimeCallingConvention::IsCurrentArgPossiblyNull() {
    128   return IsCurrentArgExplicit();  // any user parameter may be null
    129 }
    130 
    131 size_t ManagedRuntimeCallingConvention::CurrentParamSize() {
    132   return ParamSize(itr_args_);
    133 }
    134 
    135 bool ManagedRuntimeCallingConvention::IsCurrentParamAReference() {
    136   return IsParamAReference(itr_args_);
    137 }
    138 
    139 bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() {
    140   return IsParamAFloatOrDouble(itr_args_);
    141 }
    142 
    143 bool ManagedRuntimeCallingConvention::IsCurrentParamADouble() {
    144   return IsParamADouble(itr_args_);
    145 }
    146 
    147 bool ManagedRuntimeCallingConvention::IsCurrentParamALong() {
    148   return IsParamALong(itr_args_);
    149 }
    150 
    151 // JNI calling convention
    152 
    153 std::unique_ptr<JniCallingConvention> JniCallingConvention::Create(ArenaAllocator* allocator,
    154                                                                    bool is_static,
    155                                                                    bool is_synchronized,
    156                                                                    bool is_critical_native,
    157                                                                    const char* shorty,
    158                                                                    InstructionSet instruction_set) {
    159   switch (instruction_set) {
    160 #ifdef ART_ENABLE_CODEGEN_arm
    161     case InstructionSet::kArm:
    162     case InstructionSet::kThumb2:
    163       return std::unique_ptr<JniCallingConvention>(
    164           new (allocator) arm::ArmJniCallingConvention(
    165               is_static, is_synchronized, is_critical_native, shorty));
    166 #endif
    167 #ifdef ART_ENABLE_CODEGEN_arm64
    168     case InstructionSet::kArm64:
    169       return std::unique_ptr<JniCallingConvention>(
    170           new (allocator) arm64::Arm64JniCallingConvention(
    171               is_static, is_synchronized, is_critical_native, shorty));
    172 #endif
    173 #ifdef ART_ENABLE_CODEGEN_mips
    174     case InstructionSet::kMips:
    175       return std::unique_ptr<JniCallingConvention>(
    176           new (allocator) mips::MipsJniCallingConvention(
    177               is_static, is_synchronized, is_critical_native, shorty));
    178 #endif
    179 #ifdef ART_ENABLE_CODEGEN_mips64
    180     case InstructionSet::kMips64:
    181       return std::unique_ptr<JniCallingConvention>(
    182           new (allocator) mips64::Mips64JniCallingConvention(
    183               is_static, is_synchronized, is_critical_native, shorty));
    184 #endif
    185 #ifdef ART_ENABLE_CODEGEN_x86
    186     case InstructionSet::kX86:
    187       return std::unique_ptr<JniCallingConvention>(
    188           new (allocator) x86::X86JniCallingConvention(
    189               is_static, is_synchronized, is_critical_native, shorty));
    190 #endif
    191 #ifdef ART_ENABLE_CODEGEN_x86_64
    192     case InstructionSet::kX86_64:
    193       return std::unique_ptr<JniCallingConvention>(
    194           new (allocator) x86_64::X86_64JniCallingConvention(
    195               is_static, is_synchronized, is_critical_native, shorty));
    196 #endif
    197     default:
    198       LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
    199       UNREACHABLE();
    200   }
    201 }
    202 
    203 size_t JniCallingConvention::ReferenceCount() const {
    204   return NumReferenceArgs() + (IsStatic() ? 1 : 0);
    205 }
    206 
    207 FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
    208   size_t references_size = handle_scope_pointer_size_ * ReferenceCount();  // size excluding header
    209   return FrameOffset(HandleReferencesOffset().Int32Value() + references_size);
    210 }
    211 
    212 FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
    213   if (LIKELY(HasHandleScope())) {
    214     // Initial offset already includes the displacement.
    215     // -- Remove the additional local reference cookie offset if we don't have a handle scope.
    216     const size_t saved_local_reference_cookie_offset =
    217         SavedLocalReferenceCookieOffset().Int32Value();
    218     // Segment state is 4 bytes long
    219     const size_t segment_state_size = 4;
    220     return FrameOffset(saved_local_reference_cookie_offset + segment_state_size);
    221   } else {
    222     // Include only the initial Method* as part of the offset.
    223     CHECK_LT(displacement_.SizeValue(),
    224              static_cast<size_t>(std::numeric_limits<int32_t>::max()));
    225     return FrameOffset(displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
    226   }
    227 }
    228 
    229 bool JniCallingConvention::HasNext() {
    230   if (IsCurrentArgExtraForJni()) {
    231     return true;
    232   } else {
    233     unsigned int arg_pos = GetIteratorPositionWithinShorty();
    234     return arg_pos < NumArgs();
    235   }
    236 }
    237 
    238 void JniCallingConvention::Next() {
    239   CHECK(HasNext());
    240   if (IsCurrentParamALong() || IsCurrentParamADouble()) {
    241     itr_longs_and_doubles_++;
    242     itr_slots_++;
    243   }
    244   if (IsCurrentParamAFloatOrDouble()) {
    245     itr_float_and_doubles_++;
    246   }
    247   if (IsCurrentParamAReference()) {
    248     itr_refs_++;
    249   }
    250   // This default/fallthrough case also covers the extra JNIEnv* argument,
    251   // as well as any other single-slot primitives.
    252   itr_args_++;
    253   itr_slots_++;
    254 }
    255 
    256 bool JniCallingConvention::IsCurrentParamAReference() {
    257   bool return_value;
    258   if (SwitchExtraJniArguments(itr_args_,
    259                               false,  // JNIEnv*
    260                               true,   // jobject or jclass
    261                               /* out parameters */
    262                               &return_value)) {
    263     return return_value;
    264   } else {
    265     int arg_pos = GetIteratorPositionWithinShorty();
    266     return IsParamAReference(arg_pos);
    267   }
    268 }
    269 
    270 
    271 bool JniCallingConvention::IsCurrentParamJniEnv() {
    272   if (UNLIKELY(!HasJniEnv())) {
    273     return false;
    274   }
    275   return (itr_args_ == kJniEnv);
    276 }
    277 
    278 bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
    279   bool return_value;
    280   if (SwitchExtraJniArguments(itr_args_,
    281                               false,  // jnienv*
    282                               false,  // jobject or jclass
    283                               /* out parameters */
    284                               &return_value)) {
    285     return return_value;
    286   } else {
    287     int arg_pos = GetIteratorPositionWithinShorty();
    288     return IsParamAFloatOrDouble(arg_pos);
    289   }
    290 }
    291 
    292 bool JniCallingConvention::IsCurrentParamADouble() {
    293   bool return_value;
    294   if (SwitchExtraJniArguments(itr_args_,
    295                               false,  // jnienv*
    296                               false,  // jobject or jclass
    297                               /* out parameters */
    298                               &return_value)) {
    299     return return_value;
    300   } else {
    301     int arg_pos = GetIteratorPositionWithinShorty();
    302     return IsParamADouble(arg_pos);
    303   }
    304 }
    305 
    306 bool JniCallingConvention::IsCurrentParamALong() {
    307   bool return_value;
    308   if (SwitchExtraJniArguments(itr_args_,
    309                               false,  // jnienv*
    310                               false,  // jobject or jclass
    311                               /* out parameters */
    312                               &return_value)) {
    313     return return_value;
    314   } else {
    315     int arg_pos = GetIteratorPositionWithinShorty();
    316     return IsParamALong(arg_pos);
    317   }
    318 }
    319 
    320 // Return position of handle scope entry holding reference at the current iterator
    321 // position
    322 FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
    323   CHECK(IsCurrentParamAReference());
    324   CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
    325   int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
    326   CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
    327   return FrameOffset(result);
    328 }
    329 
    330 size_t JniCallingConvention::CurrentParamSize() const {
    331   if (IsCurrentArgExtraForJni()) {
    332     return static_cast<size_t>(frame_pointer_size_);  // JNIEnv or jobject/jclass
    333   } else {
    334     int arg_pos = GetIteratorPositionWithinShorty();
    335     return ParamSize(arg_pos);
    336   }
    337 }
    338 
    339 size_t JniCallingConvention::NumberOfExtraArgumentsForJni() const {
    340   if (LIKELY(HasExtraArgumentsForJni())) {
    341     // The first argument is the JNIEnv*.
    342     // Static methods have an extra argument which is the jclass.
    343     return IsStatic() ? 2 : 1;
    344   } else {
    345     // Critical natives exclude the JNIEnv and the jclass/this parameters.
    346     return 0;
    347   }
    348 }
    349 
    350 bool JniCallingConvention::HasHandleScope() const {
    351   // Exclude HandleScope for @CriticalNative methods for optimization speed.
    352   return is_critical_native_ == false;
    353 }
    354 
    355 bool JniCallingConvention::HasLocalReferenceSegmentState() const {
    356   // Exclude local reference segment states for @CriticalNative methods for optimization speed.
    357   return is_critical_native_ == false;
    358 }
    359 
    360 bool JniCallingConvention::HasJniEnv() const {
    361   // Exclude "JNIEnv*" parameter for @CriticalNative methods.
    362   return HasExtraArgumentsForJni();
    363 }
    364 
    365 bool JniCallingConvention::HasSelfClass() const {
    366   if (!IsStatic()) {
    367     // Virtual functions: There is never an implicit jclass parameter.
    368     return false;
    369   } else {
    370     // Static functions: There is an implicit jclass parameter unless it's @CriticalNative.
    371     return HasExtraArgumentsForJni();
    372   }
    373 }
    374 
    375 bool JniCallingConvention::HasExtraArgumentsForJni() const {
    376   // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters.
    377   return is_critical_native_ == false;
    378 }
    379 
    380 unsigned int JniCallingConvention::GetIteratorPositionWithinShorty() const {
    381   // We need to subtract out the extra JNI arguments if we want to use this iterator position
    382   // with the inherited CallingConvention member functions, which rely on scanning the shorty.
    383   // Note that our shorty does *not* include the JNIEnv, jclass/jobject parameters.
    384   DCHECK_GE(itr_args_, NumberOfExtraArgumentsForJni());
    385   return itr_args_ - NumberOfExtraArgumentsForJni();
    386 }
    387 
    388 bool JniCallingConvention::IsCurrentArgExtraForJni() const {
    389   if (UNLIKELY(!HasExtraArgumentsForJni())) {
    390     return false;  // If there are no extra args, we can never be an extra.
    391   }
    392   // Only parameters kJniEnv and kObjectOrClass are considered extra.
    393   return itr_args_ <= kObjectOrClass;
    394 }
    395 
    396 bool JniCallingConvention::SwitchExtraJniArguments(size_t switch_value,
    397                                                    bool case_jni_env,
    398                                                    bool case_object_or_class,
    399                                                    /* out parameters */
    400                                                    bool* return_value) const {
    401   DCHECK(return_value != nullptr);
    402   if (UNLIKELY(!HasExtraArgumentsForJni())) {
    403     return false;
    404   }
    405 
    406   switch (switch_value) {
    407     case kJniEnv:
    408       *return_value = case_jni_env;
    409       return true;
    410     case kObjectOrClass:
    411       *return_value = case_object_or_class;
    412       return true;
    413     default:
    414       return false;
    415   }
    416 }
    417 
    418 
    419 }  // namespace art
    420