blob: 12afa3a014e76cacfae366cca8aa6746428ca4d3 [file] [log] [blame]
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +00001/*
2 * Copyright (C) 2019 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-inl.h"
18#include "dex/code_item_accessors.h"
19#include "entrypoints/quick/callee_save_frame.h"
Nicolas Geoffray0315efa2020-06-26 11:42:39 +010020#include "interpreter/mterp/nterp.h"
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +000021#include "nterp_helpers.h"
22#include "oat_quick_method_header.h"
23#include "quick/quick_method_frame_info.h"
24
25namespace art {
26
27/**
28 * An nterp frame follows the optimizing compiler's ABI conventions, with
29 * int/long/reference parameters being passed in core registers / stack and
30 * float/double parameters being passed in floating point registers / stack.
31 *
32 * There are no ManagedStack transitions between compiler and nterp frames.
33 *
34 * On entry, nterp will copy its parameters to a dex register array allocated on
35 * the stack. There is a fast path when calling from nterp to nterp to not
36 * follow the ABI but just copy the parameters from the caller's dex registers
37 * to the callee's dex registers.
38 *
39 * The stack layout of an nterp frame is:
40 * ----------------
41 * | | All callee save registers of the platform
42 * | callee-save | (core and floating point).
43 * | registers | On x86 and x64 this includes the return address,
44 * | | already spilled on entry.
45 * ----------------
Nicolas Geoffrayf5958f82021-06-02 14:48:14 +010046 * | x86 args | x86 only: registers used for argument passing.
47 * ----------------
Nicolas Geoffray63a57932020-01-10 14:12:26 +000048 * | alignment | Stack aligment of kStackAlignment.
49 * ----------------
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +000050 * | | Contains `registers_size` entries (of size 4) from
51 * | dex | the code item information of the method.
52 * | registers |
53 * | |
54 * ----------------
55 * | | A copy of the dex registers above, but only
56 * | reference | containing references, used for GC.
57 * | registers |
58 * | |
59 * ----------------
60 * | caller fp | Frame pointer of caller. Stored below the reference
61 * ---------------- registers array for easy access from nterp when returning.
62 * | dex_pc_ptr | Pointer to the dex instruction being executed.
63 * ---------------- Stored whenever nterp goes into the runtime.
Vladimir Marko3f04ae52020-04-24 17:19:51 +010064 * | alignment | Pointer aligment for dex_pc_ptr and caller_fp.
65 * ----------------
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +000066 * | | In case nterp calls compiled code, we reserve space
67 * | out | for out registers. This space will be used for
68 * | registers | arguments passed on stack.
69 * | |
70 * ----------------
71 * | ArtMethod* | The method being currently executed.
72 * ----------------
73 *
74 * Exception handling:
75 * Nterp follows the same convention than the compiler,
76 * with the addition of:
77 * - All catch handlers have the same landing pad.
78 * - Before doing the longjmp for exception delivery, the register containing the
79 * dex PC pointer must be updated.
80 *
81 * Stack walking:
82 * An nterp frame is walked like a compiled code frame. We add an
83 * OatQuickMethodHeader prefix to the nterp entry point, which contains:
84 * - vmap_table_offset=0 (nterp doesn't need one).
85 * - code_size=NterpEnd-NterpStart
86 */
87
88static constexpr size_t kPointerSize = static_cast<size_t>(kRuntimePointerSize);
89
Nicolas Geoffrayc39af942021-01-25 08:43:57 +000090static constexpr size_t NterpGetFrameEntrySize(InstructionSet isa) {
91 uint32_t core_spills = 0;
92 uint32_t fp_spills = 0;
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +000093 // Note: the return address is considered part of the callee saves.
Nicolas Geoffrayc39af942021-01-25 08:43:57 +000094 switch (isa) {
95 case InstructionSet::kX86:
96 core_spills = x86::X86CalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
97 fp_spills = x86::X86CalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
Nicolas Geoffrayf5958f82021-06-02 14:48:14 +010098 // x86 also saves registers used for argument passing.
99 core_spills |= x86::kX86CalleeSaveEverythingSpills;
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000100 break;
101 case InstructionSet::kX86_64:
102 core_spills =
103 x86_64::X86_64CalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
104 fp_spills = x86_64::X86_64CalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
105 break;
106 case InstructionSet::kArm:
107 case InstructionSet::kThumb2:
108 core_spills = arm::ArmCalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
109 fp_spills = arm::ArmCalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
110 break;
111 case InstructionSet::kArm64:
112 core_spills = arm64::Arm64CalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
113 fp_spills = arm64::Arm64CalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
114 break;
115 default:
116 InstructionSetAbort(isa);
117 }
118 // Note: the return address is considered part of the callee saves.
119 return (POPCOUNT(core_spills) + POPCOUNT(fp_spills)) *
120 static_cast<size_t>(InstructionSetPointerSize(isa));
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000121}
122
Nicolas Geoffrayf5958f82021-06-02 14:48:14 +0100123static uint16_t GetNumberOfOutRegs(ArtMethod* method, InstructionSet isa)
124 REQUIRES_SHARED(Locks::mutator_lock_) {
125 CodeItemDataAccessor accessor(method->DexInstructionData());
126 uint16_t out_regs = accessor.OutsSize();
127 switch (isa) {
128 case InstructionSet::kX86: {
129 // On x86, we use three slots for temporaries.
130 out_regs = std::max(out_regs, static_cast<uint16_t>(3u));
131 break;
132 }
133 default:
134 break;
135 }
136 return out_regs;
137}
138
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000139size_t NterpGetFrameSize(ArtMethod* method, InstructionSet isa) {
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000140 CodeItemDataAccessor accessor(method->DexInstructionData());
141 const uint16_t num_regs = accessor.RegistersSize();
Nicolas Geoffrayf5958f82021-06-02 14:48:14 +0100142 const uint16_t out_regs = GetNumberOfOutRegs(method, isa);
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000143 size_t pointer_size = static_cast<size_t>(InstructionSetPointerSize(isa));
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000144
Vladimir Marko3f04ae52020-04-24 17:19:51 +0100145 // Note: There may be two pieces of alignment but there is no need to align
146 // out args to `kPointerSize` separately before aligning to kStackAlignment.
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000147 DCHECK(IsAlignedParam(kStackAlignment, pointer_size));
148 DCHECK(IsAlignedParam(NterpGetFrameEntrySize(isa), pointer_size));
149 DCHECK(IsAlignedParam(kVRegSize * 2, pointer_size));
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000150 size_t frame_size =
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000151 NterpGetFrameEntrySize(isa) +
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000152 (num_regs * kVRegSize) * 2 + // dex registers and reference registers
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000153 pointer_size + // previous frame
154 pointer_size + // saved dex pc
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000155 (out_regs * kVRegSize) + // out arguments
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000156 pointer_size; // method
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000157 return RoundUp(frame_size, kStackAlignment);
158}
159
160QuickMethodFrameInfo NterpFrameInfo(ArtMethod** frame) {
161 uint32_t core_spills =
162 RuntimeCalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
163 uint32_t fp_spills =
164 RuntimeCalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
165 return QuickMethodFrameInfo(NterpGetFrameSize(*frame), core_spills, fp_spills);
166}
167
168uintptr_t NterpGetRegistersArray(ArtMethod** frame) {
169 CodeItemDataAccessor accessor((*frame)->DexInstructionData());
170 const uint16_t num_regs = accessor.RegistersSize();
Nicolas Geoffray63a57932020-01-10 14:12:26 +0000171 // The registers array is just above the reference array.
172 return NterpGetReferenceArray(frame) + (num_regs * kVRegSize);
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000173}
174
175uintptr_t NterpGetReferenceArray(ArtMethod** frame) {
Nicolas Geoffrayf5958f82021-06-02 14:48:14 +0100176 const uint16_t out_regs = GetNumberOfOutRegs(*frame, kRuntimeISA);
Nicolas Geoffray63a57932020-01-10 14:12:26 +0000177 // The references array is just above the saved frame pointer.
178 return reinterpret_cast<uintptr_t>(frame) +
179 kPointerSize + // method
Vladimir Marko3f04ae52020-04-24 17:19:51 +0100180 RoundUp(out_regs * kVRegSize, kPointerSize) + // out arguments and pointer alignment
Nicolas Geoffray63a57932020-01-10 14:12:26 +0000181 kPointerSize + // saved dex pc
182 kPointerSize; // previous frame.
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000183}
184
185uint32_t NterpGetDexPC(ArtMethod** frame) {
Nicolas Geoffrayf5958f82021-06-02 14:48:14 +0100186 const uint16_t out_regs = GetNumberOfOutRegs(*frame, kRuntimeISA);
Nicolas Geoffray63a57932020-01-10 14:12:26 +0000187 uintptr_t dex_pc_ptr = reinterpret_cast<uintptr_t>(frame) +
188 kPointerSize + // method
Vladimir Marko3f04ae52020-04-24 17:19:51 +0100189 RoundUp(out_regs * kVRegSize, kPointerSize); // out arguments and pointer alignment
Nicolas Geoffray63a57932020-01-10 14:12:26 +0000190 CodeItemInstructionAccessor instructions((*frame)->DexInstructions());
191 return *reinterpret_cast<const uint16_t**>(dex_pc_ptr) - instructions.Insns();
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000192}
193
194uint32_t NterpGetVReg(ArtMethod** frame, uint16_t vreg) {
195 return reinterpret_cast<uint32_t*>(NterpGetRegistersArray(frame))[vreg];
196}
197
Nicolas Geoffrayd7651b12019-12-18 14:57:30 +0000198uint32_t NterpGetVRegReference(ArtMethod** frame, uint16_t vreg) {
199 return reinterpret_cast<uint32_t*>(NterpGetReferenceArray(frame))[vreg];
200}
201
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000202uintptr_t NterpGetCatchHandler() {
203 // Nterp uses the same landing pad for all exceptions. The dex_pc_ptr set before
204 // longjmp will actually be used to jmp to the catch handler.
205 return reinterpret_cast<uintptr_t>(artNterpAsmInstructionEnd);
206}
207
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000208bool CanMethodUseNterp(ArtMethod* method, InstructionSet isa) {
209 return !method->IsNative() &&
210 method->IsInvokable() &&
Nicolas Geoffrayc39af942021-01-25 08:43:57 +0000211 !method->MustCountLocks() &&
212 // Proxy methods do not go through the JIT like other methods, so we don't
213 // run them with nterp.
214 !method->IsProxyMethod() &&
215 NterpGetFrameSize(method, isa) <= interpreter::kNterpMaxFrame;
216}
217
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000218} // namespace art