15667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu/* 25667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * Copyright (C) 2014 The Android Open Source Project 35667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * 45667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * Licensed under the Apache License, Version 2.0 (the "License"); 55667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * you may not use this file except in compliance with the License. 65667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * You may obtain a copy of the License at 75667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * 85667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * http://www.apache.org/licenses/LICENSE-2.0 95667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * 105667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * Unless required by applicable law or agreed to in writing, software 115667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * distributed under the License is distributed on an "AS IS" BASIS, 125667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * See the License for the specific language governing permissions and 145667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu * limitations under the License. 155667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu */ 165667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 17e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier#include "art_method.h" 185667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu#include "utils.h" // For RoundUp(). 195667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 205667fdbb6e441dee7534ade18b628ed396daf593Zheng Xunamespace art { 215667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 225667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu// Assembly stub that does the final part of the up-call into Java. 23e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartierextern "C" void art_quick_invoke_stub_internal(ArtMethod*, uint32_t*, uint32_t, 245667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu Thread* self, JValue* result, uint32_t, uint32_t*, 255667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu uint32_t*); 265667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 275667fdbb6e441dee7534ade18b628ed396daf593Zheng Xutemplate <bool kIsStatic> 28e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartierstatic void quick_invoke_reg_setup(ArtMethod* method, uint32_t* args, uint32_t args_size, 295667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu Thread* self, JValue* result, const char* shorty) { 305667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // Note: We do not follow aapcs ABI in quick code for both softfp and hardfp. 315667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu uint32_t core_reg_args[4]; // r0 ~ r3 325667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu uint32_t fp_reg_args[16]; // s0 ~ s15 (d0 ~ d7) 33e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier uint32_t gpr_index = 1; // Index into core registers. Reserve r0 for ArtMethod*. 345667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu uint32_t fpr_index = 0; // Index into float registers. 355667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu uint32_t fpr_double_index = 0; // Index into float registers for doubles. 365667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu uint32_t arg_index = 0; // Index into argument array. 375667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu const uint32_t result_in_float = kArm32QuickCodeUseSoftFloat ? 0 : 385667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu (shorty[0] == 'F' || shorty[0] == 'D') ? 1 : 0; 395667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 405667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu if (!kIsStatic) { 415667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // Copy receiver for non-static methods. 425667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu core_reg_args[gpr_index++] = args[arg_index++]; 435667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 445667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 455667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu for (uint32_t shorty_index = 1; shorty[shorty_index] != '\0'; ++shorty_index, ++arg_index) { 465667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu char arg_type = shorty[shorty_index]; 475667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu if (kArm32QuickCodeUseSoftFloat) { 485667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu arg_type = (arg_type == 'D') ? 'J' : arg_type; // Regard double as long. 495667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu arg_type = (arg_type == 'F') ? 'I' : arg_type; // Regard float as int. 505667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 515667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu switch (arg_type) { 525667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu case 'D': { 535667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // Copy double argument into fp_reg_args if there are still floating point reg arguments. 545667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // Double should not overlap with float. 555667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu fpr_double_index = std::max(fpr_double_index, RoundUp(fpr_index, 2)); 565667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu if (fpr_double_index < arraysize(fp_reg_args)) { 575667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu fp_reg_args[fpr_double_index++] = args[arg_index]; 585667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu fp_reg_args[fpr_double_index++] = args[arg_index + 1]; 595667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 605667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu ++arg_index; 615667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu break; 625667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 635667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu case 'F': 645667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // Copy float argument into fp_reg_args if there are still floating point reg arguments. 655667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // If fpr_index is odd then its pointing at a hole next to an existing float argument. If we 665667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // encounter a float argument then pick it up from that hole. In the case fpr_index is even, 675667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // ensure that we don't pick up an argument that overlaps with with a double from 685667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // fpr_double_index. In either case, take care not to go beyond the maximum number of 695667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu // floating point arguments. 705667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu if (fpr_index % 2 == 0) { 715667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu fpr_index = std::max(fpr_double_index, fpr_index); 725667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 735667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu if (fpr_index < arraysize(fp_reg_args)) { 745667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu fp_reg_args[fpr_index++] = args[arg_index]; 755667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 765667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu break; 775667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu case 'J': 7869c15d340e7e76821bbc5d4494d4cef383774deeNicolas Geoffray if (gpr_index == 1 && !kArm32QuickCodeUseSoftFloat) { 7969c15d340e7e76821bbc5d4494d4cef383774deeNicolas Geoffray // Don't use r1-r2 as a register pair, move to r2-r3 instead. 8069c15d340e7e76821bbc5d4494d4cef383774deeNicolas Geoffray gpr_index++; 8169c15d340e7e76821bbc5d4494d4cef383774deeNicolas Geoffray } 825667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu if (gpr_index < arraysize(core_reg_args)) { 8369c15d340e7e76821bbc5d4494d4cef383774deeNicolas Geoffray // Note that we don't need to do this if two registers are not available 8469c15d340e7e76821bbc5d4494d4cef383774deeNicolas Geoffray // when !kArm32QuickCodeUseSoftFloat. We do it anyway to leave this 8569c15d340e7e76821bbc5d4494d4cef383774deeNicolas Geoffray // code simple. 865667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu core_reg_args[gpr_index++] = args[arg_index]; 875667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 885667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu ++arg_index; 895667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu FALLTHROUGH_INTENDED; // Fall-through to take of the high part. 905667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu default: 915667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu if (gpr_index < arraysize(core_reg_args)) { 925667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu core_reg_args[gpr_index++] = args[arg_index]; 935667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 945667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu break; 955667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 965667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu } 975667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 985667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu art_quick_invoke_stub_internal(method, args, args_size, self, result, result_in_float, 995667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu core_reg_args, fp_reg_args); 1005667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu} 1015667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 102e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier// Called by art::ArtMethod::Invoke to do entry into a non-static method. 1035667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu// TODO: migrate into an assembly implementation as with ARM64. 104e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartierextern "C" void art_quick_invoke_stub(ArtMethod* method, uint32_t* args, uint32_t args_size, 1055667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu Thread* self, JValue* result, const char* shorty) { 1065667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu quick_invoke_reg_setup<false>(method, args, args_size, self, result, shorty); 1075667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu} 1085667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 109e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier// Called by art::ArtMethod::Invoke to do entry into a static method. 1105667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu// TODO: migrate into an assembly implementation as with ARM64. 111e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartierextern "C" void art_quick_invoke_static_stub(ArtMethod* method, uint32_t* args, 1125667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu uint32_t args_size, Thread* self, JValue* result, 1135667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu const char* shorty) { 1145667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu quick_invoke_reg_setup<true>(method, args, args_size, self, result, shorty); 1155667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu} 1165667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu 1175667fdbb6e441dee7534ade18b628ed396daf593Zheng Xu} // namespace art 118