1 /* 2 * Copyright (C) 2014 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 "art_method.h" 18 #include "base/utils.h" // For RoundUp(). 19 20 namespace art { 21 22 // Assembly stub that does the final part of the up-call into Java. 23 extern "C" void art_quick_invoke_stub_internal(ArtMethod*, uint32_t*, uint32_t, 24 Thread* self, JValue* result, uint32_t, uint32_t*, 25 uint32_t*); 26 27 template <bool kIsStatic> 28 static void quick_invoke_reg_setup(ArtMethod* method, uint32_t* args, uint32_t args_size, 29 Thread* self, JValue* result, const char* shorty) { 30 // Note: We do not follow aapcs ABI in quick code for both softfp and hardfp. 31 uint32_t core_reg_args[4]; // r0 ~ r3 32 uint32_t fp_reg_args[16]; // s0 ~ s15 (d0 ~ d7) 33 uint32_t gpr_index = 1; // Index into core registers. Reserve r0 for ArtMethod*. 34 uint32_t fpr_index = 0; // Index into float registers. 35 uint32_t fpr_double_index = 0; // Index into float registers for doubles. 36 uint32_t arg_index = 0; // Index into argument array. 37 const uint32_t result_in_float = (shorty[0] == 'F' || shorty[0] == 'D') ? 1 : 0; 38 39 if (!kIsStatic) { 40 // Copy receiver for non-static methods. 41 core_reg_args[gpr_index++] = args[arg_index++]; 42 } 43 44 for (uint32_t shorty_index = 1; shorty[shorty_index] != '\0'; ++shorty_index, ++arg_index) { 45 char arg_type = shorty[shorty_index]; 46 switch (arg_type) { 47 case 'D': { 48 // Copy double argument into fp_reg_args if there are still floating point reg arguments. 49 // Double should not overlap with float. 50 fpr_double_index = std::max(fpr_double_index, RoundUp(fpr_index, 2)); 51 if (fpr_double_index < arraysize(fp_reg_args)) { 52 fp_reg_args[fpr_double_index++] = args[arg_index]; 53 fp_reg_args[fpr_double_index++] = args[arg_index + 1]; 54 } 55 ++arg_index; 56 break; 57 } 58 case 'F': 59 // Copy float argument into fp_reg_args if there are still floating point reg arguments. 60 // If fpr_index is odd then its pointing at a hole next to an existing float argument. If we 61 // encounter a float argument then pick it up from that hole. In the case fpr_index is even, 62 // ensure that we don't pick up an argument that overlaps with with a double from 63 // fpr_double_index. In either case, take care not to go beyond the maximum number of 64 // floating point arguments. 65 if (fpr_index % 2 == 0) { 66 fpr_index = std::max(fpr_double_index, fpr_index); 67 } 68 if (fpr_index < arraysize(fp_reg_args)) { 69 fp_reg_args[fpr_index++] = args[arg_index]; 70 } 71 break; 72 case 'J': 73 if (gpr_index == 1) { 74 // Don't use r1-r2 as a register pair, move to r2-r3 instead. 75 gpr_index++; 76 } 77 if (gpr_index < arraysize(core_reg_args)) { 78 // Note that we don't need to do this if two registers are not available 79 // when using hard-fp. We do it anyway to leave this 80 // code simple. 81 core_reg_args[gpr_index++] = args[arg_index]; 82 } 83 ++arg_index; 84 FALLTHROUGH_INTENDED; // Fall-through to take of the high part. 85 default: 86 if (gpr_index < arraysize(core_reg_args)) { 87 core_reg_args[gpr_index++] = args[arg_index]; 88 } 89 break; 90 } 91 } 92 93 art_quick_invoke_stub_internal(method, args, args_size, self, result, result_in_float, 94 core_reg_args, fp_reg_args); 95 } 96 97 // Called by art::ArtMethod::Invoke to do entry into a non-static method. 98 // TODO: migrate into an assembly implementation as with ARM64. 99 extern "C" void art_quick_invoke_stub(ArtMethod* method, uint32_t* args, uint32_t args_size, 100 Thread* self, JValue* result, const char* shorty) { 101 quick_invoke_reg_setup<false>(method, args, args_size, self, result, shorty); 102 } 103 104 // Called by art::ArtMethod::Invoke to do entry into a static method. 105 // TODO: migrate into an assembly implementation as with ARM64. 106 extern "C" void art_quick_invoke_static_stub(ArtMethod* method, uint32_t* args, 107 uint32_t args_size, Thread* self, JValue* result, 108 const char* shorty) { 109 quick_invoke_reg_setup<true>(method, args, args_size, self, result, shorty); 110 } 111 112 } // namespace art 113