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 "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 = kArm32QuickCodeUseSoftFloat ? 0 : 38 (shorty[0] == 'F' || shorty[0] == 'D') ? 1 : 0; 39 40 if (!kIsStatic) { 41 // Copy receiver for non-static methods. 42 core_reg_args[gpr_index++] = args[arg_index++]; 43 } 44 45 for (uint32_t shorty_index = 1; shorty[shorty_index] != '\0'; ++shorty_index, ++arg_index) { 46 char arg_type = shorty[shorty_index]; 47 if (kArm32QuickCodeUseSoftFloat) { 48 arg_type = (arg_type == 'D') ? 'J' : arg_type; // Regard double as long. 49 arg_type = (arg_type == 'F') ? 'I' : arg_type; // Regard float as int. 50 } 51 switch (arg_type) { 52 case 'D': { 53 // Copy double argument into fp_reg_args if there are still floating point reg arguments. 54 // Double should not overlap with float. 55 fpr_double_index = std::max(fpr_double_index, RoundUp(fpr_index, 2)); 56 if (fpr_double_index < arraysize(fp_reg_args)) { 57 fp_reg_args[fpr_double_index++] = args[arg_index]; 58 fp_reg_args[fpr_double_index++] = args[arg_index + 1]; 59 } 60 ++arg_index; 61 break; 62 } 63 case 'F': 64 // Copy float argument into fp_reg_args if there are still floating point reg arguments. 65 // If fpr_index is odd then its pointing at a hole next to an existing float argument. If we 66 // encounter a float argument then pick it up from that hole. In the case fpr_index is even, 67 // ensure that we don't pick up an argument that overlaps with with a double from 68 // fpr_double_index. In either case, take care not to go beyond the maximum number of 69 // floating point arguments. 70 if (fpr_index % 2 == 0) { 71 fpr_index = std::max(fpr_double_index, fpr_index); 72 } 73 if (fpr_index < arraysize(fp_reg_args)) { 74 fp_reg_args[fpr_index++] = args[arg_index]; 75 } 76 break; 77 case 'J': 78 if (gpr_index == 1 && !kArm32QuickCodeUseSoftFloat) { 79 // Don't use r1-r2 as a register pair, move to r2-r3 instead. 80 gpr_index++; 81 } 82 if (gpr_index < arraysize(core_reg_args)) { 83 // Note that we don't need to do this if two registers are not available 84 // when !kArm32QuickCodeUseSoftFloat. We do it anyway to leave this 85 // code simple. 86 core_reg_args[gpr_index++] = args[arg_index]; 87 } 88 ++arg_index; 89 FALLTHROUGH_INTENDED; // Fall-through to take of the high part. 90 default: 91 if (gpr_index < arraysize(core_reg_args)) { 92 core_reg_args[gpr_index++] = args[arg_index]; 93 } 94 break; 95 } 96 } 97 98 art_quick_invoke_stub_internal(method, args, args_size, self, result, result_in_float, 99 core_reg_args, fp_reg_args); 100 } 101 102 // Called by art::ArtMethod::Invoke to do entry into a non-static method. 103 // TODO: migrate into an assembly implementation as with ARM64. 104 extern "C" void art_quick_invoke_stub(ArtMethod* method, uint32_t* args, uint32_t args_size, 105 Thread* self, JValue* result, const char* shorty) { 106 quick_invoke_reg_setup<false>(method, args, args_size, self, result, shorty); 107 } 108 109 // Called by art::ArtMethod::Invoke to do entry into a static method. 110 // TODO: migrate into an assembly implementation as with ARM64. 111 extern "C" void art_quick_invoke_static_stub(ArtMethod* method, uint32_t* args, 112 uint32_t args_size, Thread* self, JValue* result, 113 const char* shorty) { 114 quick_invoke_reg_setup<true>(method, args, args_size, self, result, shorty); 115 } 116 117 } // namespace art 118