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