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