12faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes/*
22faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2011 The Android Open Source Project
32faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
42faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
52faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * you may not use this file except in compliance with the License.
62faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * You may obtain a copy of the License at
72faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
82faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
92faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
102faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Unless required by applicable law or agreed to in writing, software
112faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
122faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * See the License for the specific language governing permissions and
142faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * limitations under the License.
152faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes */
16578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom
1753c913bb71b218714823c8c87a1f92830c336f61Andreas Gampe#include "jni_compiler.h"
1853c913bb71b218714823c8c87a1f92830c336f61Andreas Gampe
19fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom#include <algorithm>
20700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers#include <memory>
210cfe1fb7060576d047f7f894fc0d8b87de84fcabIan Rogers#include <vector>
2265fcc2cf3c5cd97b84330c094908f3a6a7a8d4e7Dave Allison#include <fstream>
23578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom
243d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier#include "art_method.h"
2507ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "base/logging.h"
26761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes#include "base/macros.h"
27578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom#include "calling_convention.h"
280571d357843c53e042f370f5f2c2e9aa3fe803a9Ian Rogers#include "class_linker.h"
293320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom#include "compiled_method.h"
304f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers#include "dex_file-inl.h"
317940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom#include "driver/compiler_driver.h"
32c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky#include "driver/compiler_options.h"
33166db04e259ca51838c311891598664deeed85adIan Rogers#include "entrypoints/quick/quick_entrypoints.h"
3468d8b42ddec39ec0174162d90d4abaa004d1983eIan Rogers#include "jni_env_ext.h"
35166db04e259ca51838c311891598664deeed85adIan Rogers#include "utils/assembler.h"
36166db04e259ca51838c311891598664deeed85adIan Rogers#include "utils/managed_register.h"
37166db04e259ca51838c311891598664deeed85adIan Rogers#include "utils/arm/managed_register_arm.h"
3875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu#include "utils/arm64/managed_register_arm64.h"
39166db04e259ca51838c311891598664deeed85adIan Rogers#include "utils/mips/managed_register_mips.h"
406ea651f0f4c7de4580beb2e887d86802c1ae0738Maja Gagic#include "utils/mips64/managed_register_mips64.h"
41166db04e259ca51838c311891598664deeed85adIan Rogers#include "utils/x86/managed_register_x86.h"
42578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom#include "thread.h"
43b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
4446f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes#define __ jni_asm->
4546f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes
46b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogersnamespace art {
47b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
4846f060a53fffc14333096f0a48f95730ee4768eeElliott Hughesstatic void CopyParameter(Assembler* jni_asm,
4946f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes                          ManagedRuntimeCallingConvention* mr_conv,
5046f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes                          JniCallingConvention* jni_conv,
5100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                          size_t frame_size, size_t out_arg_size);
5246f060a53fffc14333096f0a48f95730ee4768eeElliott Hughesstatic void SetNativeParameter(Assembler* jni_asm,
5346f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes                               JniCallingConvention* jni_conv,
5400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                               ManagedRegister in_reg);
553e778f7ee62fe75912379531022a09230c25f5f8Elliott Hughes
56b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers// Generate the JNI bridge for the given method, general contract:
57b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers// - Arguments are in the managed runtime format, either on stack or in
58b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers//   registers, a reference to the method object is supplied as part of this
59b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers//   convention.
60b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers//
6172d32629303f8f39362a4099481f48646aed042fIan RogersCompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
6246f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes                                            uint32_t access_flags, uint32_t method_idx,
6346f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes                                            const DexFile& dex_file) {
64748474146da0c6484fa3dca0a700f612d47550c3Elliott Hughes  const bool is_native = (access_flags & kAccNative) != 0;
65748474146da0c6484fa3dca0a700f612d47550c3Elliott Hughes  CHECK(is_native);
66169c9a7f46776b235d0a37d5e0ff27682deffe06Ian Rogers  const bool is_static = (access_flags & kAccStatic) != 0;
67169c9a7f46776b235d0a37d5e0ff27682deffe06Ian Rogers  const bool is_synchronized = (access_flags & kAccSynchronized) != 0;
68169c9a7f46776b235d0a37d5e0ff27682deffe06Ian Rogers  const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
6972d32629303f8f39362a4099481f48646aed042fIan Rogers  InstructionSet instruction_set = driver->GetInstructionSet();
70af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe  const bool is_64_bit_target = Is64BitInstructionSet(instruction_set);
712c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  // Calling conventions used to iterate over parameters to method
72700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<JniCallingConvention> main_jni_conv(
7346f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes      JniCallingConvention::Create(is_static, is_synchronized, shorty, instruction_set));
74fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  bool reference_return = main_jni_conv->IsReturnAReference();
75fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom
76700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
7746f060a53fffc14333096f0a48f95730ee4768eeElliott Hughes      ManagedRuntimeCallingConvention::Create(is_static, is_synchronized, shorty, instruction_set));
782c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers
79fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  // Calling conventions to call into JNI method "end" possibly passing a returned reference, the
80fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  //     method and the current thread.
8175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  const char* jni_end_shorty;
8275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  if (reference_return && is_synchronized) {
8375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end_shorty = "ILL";
8475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  } else if (reference_return) {
8575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end_shorty = "IL";
8675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  } else if (is_synchronized) {
8775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end_shorty = "VL";
8875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  } else {
8975b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end_shorty = "V";
9075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  }
9175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu
92700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<JniCallingConvention> end_jni_conv(
93fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      JniCallingConvention::Create(is_static, is_synchronized, jni_end_shorty, instruction_set));
94fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom
952c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  // Assembler that holds generated instructions
96700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<Assembler> jni_asm(Assembler::Create(instruction_set));
97a26cb57f46fd3f27a930d9d688fe8670c1f24754David Srbecky  jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GetGenerateDebugInfo());
982c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers
992c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  // Offsets into data structures
1002c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  // TODO: if cross compiling these offsets are for the host not the target
1012c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  const Offset functions(OFFSETOF_MEMBER(JNIEnvExt, functions));
1022c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  const Offset monitor_enter(OFFSETOF_MEMBER(JNINativeInterface, MonitorEnter));
1032c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  const Offset monitor_exit(OFFSETOF_MEMBER(JNINativeInterface, MonitorExit));
1042c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers
105bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers  // 1. Build the frame saving all callee saves
106fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  const size_t frame_size(main_jni_conv->FrameSize());
107fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  const std::vector<ManagedRegister>& callee_save_regs = main_jni_conv->CalleeSaveRegisters();
108b5d09b2f87202bc132ac3991d4b6d71f4f6d9264Ian Rogers  __ BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs, mr_conv->EntrySpills());
109dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  DCHECK_EQ(jni_asm->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size));
110b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
111eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier  // 2. Set up the HandleScope
1122c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  mr_conv->ResetIterator(FrameOffset(frame_size));
113fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  main_jni_conv->ResetIterator(FrameOffset(0));
114eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier  __ StoreImmediateToFrame(main_jni_conv->HandleScopeNumRefsOffset(),
115fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom                           main_jni_conv->ReferenceCount(),
1162c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                           mr_conv->InterproceduralScratchRegister());
11775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu
118af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe  if (is_64_bit_target) {
119eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    __ CopyRawPtrFromThread64(main_jni_conv->HandleScopeLinkOffset(),
1203d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                              Thread::TopHandleScopeOffset<8>(),
1213d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                              mr_conv->InterproceduralScratchRegister());
122eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    __ StoreStackOffsetToThread64(Thread::TopHandleScopeOffset<8>(),
1233d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                  main_jni_conv->HandleScopeOffset(),
1243d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                  mr_conv->InterproceduralScratchRegister());
12575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  } else {
126eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    __ CopyRawPtrFromThread32(main_jni_conv->HandleScopeLinkOffset(),
1273d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                              Thread::TopHandleScopeOffset<4>(),
1283d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                              mr_conv->InterproceduralScratchRegister());
129eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    __ StoreStackOffsetToThread32(Thread::TopHandleScopeOffset<4>(),
1303d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                  main_jni_conv->HandleScopeOffset(),
1313d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                  mr_conv->InterproceduralScratchRegister());
13275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  }
133b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
134eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier  // 3. Place incoming reference arguments into handle scope
135fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  main_jni_conv->Next();  // Skip JNIEnv*
136bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers  // 3.5. Create Class argument for static methods out of passed method
137b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  if (is_static) {
138eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
139eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // Check handle scope offset is within frame
140eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    CHECK_LT(handle_scope_offset.Uint32Value(), frame_size);
1413d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier    // Note this LoadRef() doesn't need heap poisoning since its from the ArtMethod.
1421cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    // Note this LoadRef() does not include read barrier. It will be handled below.
143fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ LoadRef(main_jni_conv->InterproceduralScratchRegister(),
1443d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier               mr_conv->MethodRegister(), ArtMethod::DeclaringClassOffset(), false);
145fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ VerifyObject(main_jni_conv->InterproceduralScratchRegister(), false);
146eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    __ StoreRef(handle_scope_offset, main_jni_conv->InterproceduralScratchRegister());
147eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    main_jni_conv->Next();  // in handle scope so move to next argument
148b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
1492c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  while (mr_conv->HasNext()) {
150fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    CHECK(main_jni_conv->HasNext());
151fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    bool ref_param = main_jni_conv->IsCurrentParamAReference();
1522c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers    CHECK(!ref_param || mr_conv->IsCurrentParamAReference());
153eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // References need placing in handle scope and the entry value passing
154b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    if (ref_param) {
155eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      // Compute handle scope entry, note null is placed in the handle scope but its boxed value
1562cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier      // must be null.
157eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
1582cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier      // Check handle scope offset is within frame and doesn't run into the saved segment state.
159eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      CHECK_LT(handle_scope_offset.Uint32Value(), frame_size);
160eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      CHECK_NE(handle_scope_offset.Uint32Value(),
161fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom               main_jni_conv->SavedLocalReferenceCookieOffset().Uint32Value());
1622c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers      bool input_in_reg = mr_conv->IsCurrentParamInRegister();
1632c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers      bool input_on_stack = mr_conv->IsCurrentParamOnStack();
1645381cf941d26030199fcdbe61a614ff01e55a27cShih-wei Liao      CHECK(input_in_reg || input_on_stack);
1655381cf941d26030199fcdbe61a614ff01e55a27cShih-wei Liao
166b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers      if (input_in_reg) {
1672c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers        ManagedRegister in_reg  =  mr_conv->CurrentParamRegister();
1682c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers        __ VerifyObject(in_reg, mr_conv->IsCurrentArgPossiblyNull());
169eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier        __ StoreRef(handle_scope_offset, in_reg);
1705381cf941d26030199fcdbe61a614ff01e55a27cShih-wei Liao      } else if (input_on_stack) {
1712c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers        FrameOffset in_off  = mr_conv->CurrentParamStackOffset();
1722c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers        __ VerifyObject(in_off, mr_conv->IsCurrentArgPossiblyNull());
173eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier        __ CopyRef(handle_scope_offset, in_off,
1742c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                   mr_conv->InterproceduralScratchRegister());
175b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers      }
176b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    }
1772c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers    mr_conv->Next();
178fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->Next();
179b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
180b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
18100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 4. Write out the end of the quick frames.
182af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe  if (is_64_bit_target) {
18375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    __ StoreStackPointerToThread64(Thread::TopOfManagedStackOffset<8>());
18475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  } else {
18575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    __ StoreStackPointerToThread32(Thread::TopOfManagedStackOffset<4>());
18675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  }
187b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
18800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 5. Move frame down to allow space for out going args.
189fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  const size_t main_out_arg_size = main_jni_conv->OutArgSize();
1904e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  size_t current_out_arg_size = main_out_arg_size;
1914e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  __ IncreaseFrameSize(main_out_arg_size);
192b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
1931cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi  // Call the read barrier for the declaring class loaded from the method for a static call.
1941cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi  // Note that we always have outgoing param space available for at least two params.
1951cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi  if (kUseReadBarrier && is_static) {
1961cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    ThreadOffset<4> read_barrier32 = QUICK_ENTRYPOINT_OFFSET(4, pReadBarrierJni);
1971cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    ThreadOffset<8> read_barrier64 = QUICK_ENTRYPOINT_OFFSET(8, pReadBarrierJni);
1981cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
1991cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    main_jni_conv->Next();  // Skip JNIEnv.
2001cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    FrameOffset class_handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
2011cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
2021cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    // Pass the handle for the class as the first argument.
2031cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    if (main_jni_conv->IsCurrentParamOnStack()) {
2041cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      FrameOffset out_off = main_jni_conv->CurrentParamStackOffset();
2051cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      __ CreateHandleScopeEntry(out_off, class_handle_scope_offset,
2061cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi                         mr_conv->InterproceduralScratchRegister(),
2071cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi                         false);
2081cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    } else {
2091cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      ManagedRegister out_reg = main_jni_conv->CurrentParamRegister();
2101cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      __ CreateHandleScopeEntry(out_reg, class_handle_scope_offset,
2111cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi                         ManagedRegister::NoRegister(), false);
2121cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    }
2131cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    main_jni_conv->Next();
2141cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    // Pass the current thread as the second argument and call.
2151cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    if (main_jni_conv->IsCurrentParamInRegister()) {
2161cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      __ GetCurrentThread(main_jni_conv->CurrentParamRegister());
2171cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      if (is_64_bit_target) {
2181cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi        __ Call(main_jni_conv->CurrentParamRegister(), Offset(read_barrier64),
2191cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi                main_jni_conv->InterproceduralScratchRegister());
2201cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      } else {
2211cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi        __ Call(main_jni_conv->CurrentParamRegister(), Offset(read_barrier32),
2221cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi                main_jni_conv->InterproceduralScratchRegister());
2231cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      }
2241cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    } else {
2251cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      __ GetCurrentThread(main_jni_conv->CurrentParamStackOffset(),
2261cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi                          main_jni_conv->InterproceduralScratchRegister());
2271cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      if (is_64_bit_target) {
2281cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi        __ CallFromThread64(read_barrier64, main_jni_conv->InterproceduralScratchRegister());
2291cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      } else {
2301cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi        __ CallFromThread32(read_barrier32, main_jni_conv->InterproceduralScratchRegister());
2311cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi      }
2321cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    }
2331cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi    main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));  // Reset.
2341cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi  }
2351cc71ebf333ca323ae0e130fefbce4593e385c10Hiroshi Yamauchi
23600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 6. Call into appropriate JniMethodStart passing Thread* so that transition out of Runnable
23700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  //    can occur. The result is the saved JNI local state that is restored by the exit call. We
23800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  //    abuse the JNI calling convention here, that is guaranteed to support passing 2 pointer
23900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  //    arguments.
24075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  ThreadOffset<4> jni_start32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStartSynchronized)
24175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                                                : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStart);
24275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  ThreadOffset<8> jni_start64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStartSynchronized)
24375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                                                : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStart);
244fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
245eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier  FrameOffset locked_object_handle_scope_offset(0);
24600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (is_synchronized) {
24700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // Pass object for locking.
248fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->Next();  // Skip JNIEnv.
249eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    locked_object_handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
250fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
251fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    if (main_jni_conv->IsCurrentParamOnStack()) {
252fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      FrameOffset out_off = main_jni_conv->CurrentParamStackOffset();
253eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_off, locked_object_handle_scope_offset,
2543d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                mr_conv->InterproceduralScratchRegister(), false);
255df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers    } else {
256fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      ManagedRegister out_reg = main_jni_conv->CurrentParamRegister();
257eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_reg, locked_object_handle_scope_offset,
2583d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                ManagedRegister::NoRegister(), false);
259bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers    }
260fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->Next();
26100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
262fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  if (main_jni_conv->IsCurrentParamInRegister()) {
263fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ GetCurrentThread(main_jni_conv->CurrentParamRegister());
264af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe    if (is_64_bit_target) {
26575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ Call(main_jni_conv->CurrentParamRegister(), Offset(jni_start64),
2663d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier              main_jni_conv->InterproceduralScratchRegister());
26775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
26875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ Call(main_jni_conv->CurrentParamRegister(), Offset(jni_start32),
2693d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier              main_jni_conv->InterproceduralScratchRegister());
27075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
27100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else {
272fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ GetCurrentThread(main_jni_conv->CurrentParamStackOffset(),
273fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom                        main_jni_conv->InterproceduralScratchRegister());
274af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe    if (is_64_bit_target) {
27575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ CallFromThread64(jni_start64, main_jni_conv->InterproceduralScratchRegister());
27675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
27775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ CallFromThread32(jni_start32, main_jni_conv->InterproceduralScratchRegister());
27875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
27900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
28000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (is_synchronized) {  // Check for exceptions from monitor enter.
281fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ ExceptionPoll(main_jni_conv->InterproceduralScratchRegister(), main_out_arg_size);
282df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers  }
283fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  FrameOffset saved_cookie_offset = main_jni_conv->SavedLocalReferenceCookieOffset();
284fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  __ Store(saved_cookie_offset, main_jni_conv->IntReturnRegister(), 4);
285df20fe0c097073f75f22d16e72fd3636a31d3ca1Ian Rogers
286bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers  // 7. Iterate over arguments placing values from managed calling convention in
287b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  //    to the convention required for a native call (shuffling). For references
288b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  //    place an index/pointer to the reference after checking whether it is
2892cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier  //    null (which must be encoded as null).
29020cde9033d51103f31e21436e88f80e1170c78adElliott Hughes  //    Note: we do this prior to materializing the JNIEnv* and static's jclass to
2912cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier  //    give as many free registers for the shuffle as possible.
2924e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size));
29382da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao  uint32_t args_count = 0;
2942c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  while (mr_conv->HasNext()) {
29582da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao    args_count++;
2962c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers    mr_conv->Next();
297e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  }
29882da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao
29982da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao  // Do a backward pass over arguments, so that the generated code will be "mov
30082da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao  // R2, R3; mov R1, R2" instead of "mov R1, R2; mov R2, R3."
30182da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao  // TODO: A reverse iterator to improve readability.
30282da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao  for (uint32_t i = 0; i < args_count; ++i) {
303fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size));
304fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
305fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->Next();  // Skip JNIEnv*.
30682da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao    if (is_static) {
307fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      main_jni_conv->Next();  // Skip Class for now.
30882da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao    }
30900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // Skip to the argument we're interested in.
31082da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao    for (uint32_t j = 0; j < args_count - i - 1; ++j) {
3112c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers      mr_conv->Next();
312fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      main_jni_conv->Next();
31382da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao    }
314fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    CopyParameter(jni_asm.get(), mr_conv.get(), main_jni_conv.get(), frame_size, main_out_arg_size);
31582da44b625a1af03c0b768c71f1cef29831127c3Shih-wei Liao  }
316e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro  if (is_static) {
317e2d373e6e09c1df9a47e73a26254048adb31ce82Carl Shapiro    // Create argument for Class
3184e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size));
319fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
320fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    main_jni_conv->Next();  // Skip JNIEnv*
321eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
322fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    if (main_jni_conv->IsCurrentParamOnStack()) {
323fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      FrameOffset out_off = main_jni_conv->CurrentParamStackOffset();
324eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_off, handle_scope_offset,
3252c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                         mr_conv->InterproceduralScratchRegister(),
3262c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                         false);
327b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    } else {
328fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      ManagedRegister out_reg = main_jni_conv->CurrentParamRegister();
329eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_reg, handle_scope_offset,
3302c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers                         ManagedRegister::NoRegister(), false);
331b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers    }
332b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
33300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
33400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 8. Create 1st argument, the JNI environment ptr.
335fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
336dc51b79e65abcdad094ccd5e5a2caf5153433d49Ian Rogers  // Register that will hold local indirect reference table
337fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  if (main_jni_conv->IsCurrentParamInRegister()) {
338fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    ManagedRegister jni_env = main_jni_conv->CurrentParamRegister();
339fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    DCHECK(!jni_env.Equals(main_jni_conv->InterproceduralScratchRegister()));
340af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe    if (is_64_bit_target) {
34175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ LoadRawPtrFromThread64(jni_env, Thread::JniEnvOffset<8>());
34275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
34375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ LoadRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>());
34475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
345b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  } else {
346fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    FrameOffset jni_env = main_jni_conv->CurrentParamStackOffset();
347af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe    if (is_64_bit_target) {
34875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ CopyRawPtrFromThread64(jni_env, Thread::JniEnvOffset<8>(),
3493d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                main_jni_conv->InterproceduralScratchRegister());
35075b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
35175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ CopyRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>(),
3523d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier                                main_jni_conv->InterproceduralScratchRegister());
35375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
354b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
355b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
35600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 9. Plant call to native code associated with method.
3573d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier  MemberOffset jni_entrypoint_offset = ArtMethod::EntryPointFromJniOffset(
3582d7210188805292e463be4bcf7a133b654d7e0eaMathieu Chartier      InstructionSetPointerSize(instruction_set));
3592d7210188805292e463be4bcf7a133b654d7e0eaMathieu Chartier  __ Call(main_jni_conv->MethodStackOffset(), jni_entrypoint_offset,
36000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers          mr_conv->InterproceduralScratchRegister());
361bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
36200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 10. Fix differences in result widths.
363d1104322e5156669767e8b2c3b843ffaff173381Andreas Gampe  if (main_jni_conv->RequiresSmallResultTypeExtension()) {
364fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    if (main_jni_conv->GetReturnType() == Primitive::kPrimByte ||
365fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom        main_jni_conv->GetReturnType() == Primitive::kPrimShort) {
366fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      __ SignExtend(main_jni_conv->ReturnRegister(),
367fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom                    Primitive::ComponentSize(main_jni_conv->GetReturnType()));
368fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    } else if (main_jni_conv->GetReturnType() == Primitive::kPrimBoolean ||
369fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom               main_jni_conv->GetReturnType() == Primitive::kPrimChar) {
370fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      __ ZeroExtend(main_jni_conv->ReturnRegister(),
371fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom                    Primitive::ComponentSize(main_jni_conv->GetReturnType()));
372cee4d0c1c2faacf0eae748a24cc7e455e067d977jeffhao    }
373b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers  }
374b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
37500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 11. Save return value
376fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  FrameOffset return_save_location = main_jni_conv->ReturnValueSaveLocation();
377fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  if (main_jni_conv->SizeOfReturnValue() != 0 && !reference_return) {
3786ea651f0f4c7de4580beb2e887d86802c1ae0738Maja Gagic    if ((instruction_set == kMips || instruction_set == kMips64) &&
3796ea651f0f4c7de4580beb2e887d86802c1ae0738Maja Gagic        main_jni_conv->GetReturnType() == Primitive::kPrimDouble &&
3800703060875166106af3d490c6c264611aea67ec8jeffhao        return_save_location.Uint32Value() % 8 != 0) {
3810703060875166106af3d490c6c264611aea67ec8jeffhao      // Ensure doubles are 8-byte aligned for MIPS
382af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe      return_save_location = FrameOffset(return_save_location.Uint32Value() + kMipsPointerSize);
3830703060875166106af3d490c6c264611aea67ec8jeffhao    }
3844e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    CHECK_LT(return_save_location.Uint32Value(), frame_size + main_out_arg_size);
385fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ Store(return_save_location, main_jni_conv->ReturnRegister(), main_jni_conv->SizeOfReturnValue());
3865a7a74a042e73a355f5cedffa0d2faf5340028faIan Rogers  }
387726079d3e2e50854cd6ca4c393f4529a796dba58Elliott Hughes
3884e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  // Increase frame size for out args if needed by the end_jni_conv.
3894e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  const size_t end_out_arg_size = end_jni_conv->OutArgSize();
3904e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  if (end_out_arg_size > current_out_arg_size) {
3914e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    size_t out_arg_size_diff = end_out_arg_size - current_out_arg_size;
3924e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    current_out_arg_size = end_out_arg_size;
3934e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    __ IncreaseFrameSize(out_arg_size_diff);
3944e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    saved_cookie_offset = FrameOffset(saved_cookie_offset.SizeValue() + out_arg_size_diff);
3954e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    locked_object_handle_scope_offset =
3964e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko        FrameOffset(locked_object_handle_scope_offset.SizeValue() + out_arg_size_diff);
3974e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko    return_save_location = FrameOffset(return_save_location.SizeValue() + out_arg_size_diff);
3984e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  }
39900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  //     thread.
400fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  end_jni_conv->ResetIterator(FrameOffset(end_out_arg_size));
40175b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  ThreadOffset<4> jni_end32(-1);
40275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu  ThreadOffset<8> jni_end64(-1);
40300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (reference_return) {
40400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // Pass result.
40575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReferenceSynchronized)
40675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                                : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReference);
40775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndWithReferenceSynchronized)
40875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                                : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndWithReference);
409fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    SetNativeParameter(jni_asm.get(), end_jni_conv.get(), end_jni_conv->ReturnRegister());
410fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    end_jni_conv->Next();
41100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else {
41275b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndSynchronized)
41375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                                : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEnd);
41475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    jni_end64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndSynchronized)
41575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu                                : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEnd);
41600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
41700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // Pass saved local reference state.
418fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  if (end_jni_conv->IsCurrentParamOnStack()) {
419fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    FrameOffset out_off = end_jni_conv->CurrentParamStackOffset();
420fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ Copy(out_off, saved_cookie_offset, end_jni_conv->InterproceduralScratchRegister(), 4);
42100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else {
422fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    ManagedRegister out_reg = end_jni_conv->CurrentParamRegister();
42300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    __ Load(out_reg, saved_cookie_offset, 4);
42400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
425fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  end_jni_conv->Next();
426169c9a7f46776b235d0a37d5e0ff27682deffe06Ian Rogers  if (is_synchronized) {
42700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // Pass object for unlocking.
428fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    if (end_jni_conv->IsCurrentParamOnStack()) {
429fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      FrameOffset out_off = end_jni_conv->CurrentParamStackOffset();
430eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_off, locked_object_handle_scope_offset,
431fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom                         end_jni_conv->InterproceduralScratchRegister(),
43200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                         false);
43300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    } else {
434fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom      ManagedRegister out_reg = end_jni_conv->CurrentParamRegister();
435eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_reg, locked_object_handle_scope_offset,
43600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                         ManagedRegister::NoRegister(), false);
43700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    }
438fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    end_jni_conv->Next();
43900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
440fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  if (end_jni_conv->IsCurrentParamInRegister()) {
441fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ GetCurrentThread(end_jni_conv->CurrentParamRegister());
442af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe    if (is_64_bit_target) {
44375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ Call(end_jni_conv->CurrentParamRegister(), Offset(jni_end64),
44475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu              end_jni_conv->InterproceduralScratchRegister());
44575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
44675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ Call(end_jni_conv->CurrentParamRegister(), Offset(jni_end32),
44775b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu              end_jni_conv->InterproceduralScratchRegister());
44875b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
449bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers  } else {
450fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom    __ GetCurrentThread(end_jni_conv->CurrentParamStackOffset(),
451fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom                        end_jni_conv->InterproceduralScratchRegister());
452af13ad9fd18b6f75fe82e7995224c55654594f93Andreas Gampe    if (is_64_bit_target) {
45375b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ CallFromThread64(ThreadOffset<8>(jni_end64), end_jni_conv->InterproceduralScratchRegister());
45475b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    } else {
45575b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu      __ CallFromThread32(ThreadOffset<4>(jni_end32), end_jni_conv->InterproceduralScratchRegister());
45675b9113b2b0a5807043af2a669a93d1579af8e2cSerban Constantinescu    }
457bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers  }
458b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
45900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 13. Reload return value
460fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  if (main_jni_conv->SizeOfReturnValue() != 0 && !reference_return) {
46100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    __ Load(mr_conv->ReturnRegister(), return_save_location, mr_conv->SizeOfReturnValue());
46200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
46300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
46400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 14. Move frame up now we're done with the out arg space.
4654e24b9da7c5ea6e517ecdbc09aa14a0995100b7eVladimir Marko  __ DecreaseFrameSize(current_out_arg_size);
46600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
46700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // 15. Process pending exceptions from JNI call or monitor exit.
468fc7120c0293b96218d55abee29882f101acbc79bBrian Carlstrom  __ ExceptionPoll(main_jni_conv->InterproceduralScratchRegister(), 0);
46900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
4708770e5c77868dd3c6c832ba9ea68140f70e73088Mathieu Chartier  // 16. Remove activation - need to restore callee save registers since the GC may have changed
47100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  //     them.
472dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  DCHECK_EQ(jni_asm->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size));
4738770e5c77868dd3c6c832ba9ea68140f70e73088Mathieu Chartier  __ RemoveFrame(frame_size, callee_save_regs);
474dd97393aca1a3ff2abec4dc4f78d7724300971bcDavid Srbecky  DCHECK_EQ(jni_asm->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size));
47500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
476e5de95b3f9609e02fefd7cda7b21f30c9412eb4cIan Rogers  // 17. Finalize code generation
4772c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  __ EmitSlowPaths();
4782c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  size_t cs = __ CodeSize();
4793320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  std::vector<uint8_t> managed_code(cs);
4803320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  MemoryRegion code(&managed_code[0], managed_code.size());
4812c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers  __ FinalizeInstructions(code);
4828c57831b2b07185ee1986b9af68a351e1ca584c3David Srbecky
483c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky  return CompiledMethod::SwapAllocCompiledMethod(driver,
484c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 instruction_set,
485c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 ArrayRef<const uint8_t>(managed_code),
486c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 frame_size,
487c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 main_jni_conv->CoreSpillMask(),
488c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 main_jni_conv->FpSpillMask(),
489c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 nullptr,  // src_mapping_table.
490c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 ArrayRef<const uint8_t>(),  // mapping_table.
491c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 ArrayRef<const uint8_t>(),  // vmap_table.
492c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 ArrayRef<const uint8_t>(),  // native_gc_map.
493c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 ArrayRef<const uint8_t>(*jni_asm->cfi().data()),
494c6b4dd8980350aaf250f0185f73e9c42ec17cd57David Srbecky                                                 ArrayRef<const LinkerPatch>());
495b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers}
496b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers
4972cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier// Copy a single parameter from the managed to the JNI calling convention.
49800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogersstatic void CopyParameter(Assembler* jni_asm,
49900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                          ManagedRuntimeCallingConvention* mr_conv,
50000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                          JniCallingConvention* jni_conv,
50100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                          size_t frame_size, size_t out_arg_size) {
50200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  bool input_in_reg = mr_conv->IsCurrentParamInRegister();
50300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  bool output_in_reg = jni_conv->IsCurrentParamInRegister();
504eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier  FrameOffset handle_scope_offset(0);
50500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  bool null_allowed = false;
50600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  bool ref_param = jni_conv->IsCurrentParamAReference();
50700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  CHECK(!ref_param || mr_conv->IsCurrentParamAReference());
50800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  // input may be in register, on stack or both - but not none!
50900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  CHECK(input_in_reg || mr_conv->IsCurrentParamOnStack());
51000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (output_in_reg) {  // output shouldn't straddle registers and stack
51100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    CHECK(!jni_conv->IsCurrentParamOnStack());
51200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else {
51300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    CHECK(jni_conv->IsCurrentParamOnStack());
51400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
5152cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier  // References need placing in handle scope and the entry address passing.
51600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (ref_param) {
51700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    null_allowed = mr_conv->IsCurrentArgPossiblyNull();
518eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // Compute handle scope offset. Note null is placed in the handle scope but the jobject
519eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // passed to the native code must be null (not a pointer into the handle scope
52000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // as with regular references).
521eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    handle_scope_offset = jni_conv->CurrentParamHandleScopeEntryOffset();
522eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    // Check handle scope offset is within frame.
523eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier    CHECK_LT(handle_scope_offset.Uint32Value(), (frame_size + out_arg_size));
52400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
52500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (input_in_reg && output_in_reg) {
52600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    ManagedRegister in_reg = mr_conv->CurrentParamRegister();
52700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    ManagedRegister out_reg = jni_conv->CurrentParamRegister();
52800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    if (ref_param) {
529eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_reg, handle_scope_offset, in_reg, null_allowed);
53000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    } else {
53100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      if (!mr_conv->IsCurrentParamOnStack()) {
53200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        // regular non-straddling move
53300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        __ Move(out_reg, in_reg, mr_conv->CurrentParamSize());
53400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      } else {
53500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        UNIMPLEMENTED(FATAL);  // we currently don't expect to see this case
53600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      }
53700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    }
53800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else if (!input_in_reg && !output_in_reg) {
53900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    FrameOffset out_off = jni_conv->CurrentParamStackOffset();
54000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    if (ref_param) {
541eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_off, handle_scope_offset, mr_conv->InterproceduralScratchRegister(),
54200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                         null_allowed);
54300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    } else {
54400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      FrameOffset in_off = mr_conv->CurrentParamStackOffset();
54500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      size_t param_size = mr_conv->CurrentParamSize();
54600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      CHECK_EQ(param_size, jni_conv->CurrentParamSize());
54700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      __ Copy(out_off, in_off, mr_conv->InterproceduralScratchRegister(), param_size);
54800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    }
54900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else if (!input_in_reg && output_in_reg) {
55000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    FrameOffset in_off = mr_conv->CurrentParamStackOffset();
55100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    ManagedRegister out_reg = jni_conv->CurrentParamRegister();
55200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // Check that incoming stack arguments are above the current stack frame.
55300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    CHECK_GT(in_off.Uint32Value(), frame_size);
55400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    if (ref_param) {
555eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_reg, handle_scope_offset, ManagedRegister::NoRegister(), null_allowed);
55600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    } else {
55700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      size_t param_size = mr_conv->CurrentParamSize();
55800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      CHECK_EQ(param_size, jni_conv->CurrentParamSize());
55900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      __ Load(out_reg, in_off, param_size);
56000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    }
56100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else {
56200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    CHECK(input_in_reg && !output_in_reg);
56300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    ManagedRegister in_reg = mr_conv->CurrentParamRegister();
56400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    FrameOffset out_off = jni_conv->CurrentParamStackOffset();
56500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // Check outgoing argument is within frame
56600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    CHECK_LT(out_off.Uint32Value(), frame_size);
56700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    if (ref_param) {
568eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      // TODO: recycle value in in_reg rather than reload from handle scope
569eb8167a4f4d27fce0530f6724ab8032610cd146bMathieu Chartier      __ CreateHandleScopeEntry(out_off, handle_scope_offset, mr_conv->InterproceduralScratchRegister(),
57000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                         null_allowed);
57100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    } else {
57200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      size_t param_size = mr_conv->CurrentParamSize();
57300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      CHECK_EQ(param_size, jni_conv->CurrentParamSize());
57400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      if (!mr_conv->IsCurrentParamOnStack()) {
57500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        // regular non-straddling store
57600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        __ Store(out_off, in_reg, param_size);
57700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      } else {
57800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        // store where input straddles registers and stack
57900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        CHECK_EQ(param_size, 8u);
58000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        FrameOffset in_off = mr_conv->CurrentParamStackOffset();
58100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        __ StoreSpanning(out_off, in_reg, in_off, mr_conv->InterproceduralScratchRegister());
58200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      }
58300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    }
58400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
58500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers}
58600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
58700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogersstatic void SetNativeParameter(Assembler* jni_asm,
58800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                               JniCallingConvention* jni_conv,
58900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                               ManagedRegister in_reg) {
59000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  if (jni_conv->IsCurrentParamOnStack()) {
59100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    FrameOffset dest = jni_conv->CurrentParamStackOffset();
59200f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    __ StoreRawPtr(dest, in_reg);
59300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  } else {
59400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    if (!jni_conv->CurrentParamRegister().Equals(in_reg)) {
59500f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      __ Move(jni_conv->CurrentParamRegister(), in_reg, jni_conv->CurrentParamSize());
59600f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    }
59700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers  }
59800f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers}
59900f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers
60053c913bb71b218714823c8c87a1f92830c336f61Andreas GampeCompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler, uint32_t access_flags,
60153c913bb71b218714823c8c87a1f92830c336f61Andreas Gampe                                         uint32_t method_idx, const DexFile& dex_file) {
60257b86d47b66322693a070185fadfb43cb9c12eabIan Rogers  return ArtJniCompileMethodInternal(compiler, access_flags, method_idx, dex_file);
603e5de95b3f9609e02fefd7cda7b21f30c9412eb4cIan Rogers}
60453c913bb71b218714823c8c87a1f92830c336f61Andreas Gampe
60553c913bb71b218714823c8c87a1f92830c336f61Andreas Gampe}  // namespace art
606