blob: 65221163b5adfbd4b6705953f281b716e3f2891e [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"
20#include "interpreter/interpreter_mterp_impl.h"
21#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 * ----------------
46 * | | Contains `registers_size` entries (of size 4) from
47 * | dex | the code item information of the method.
48 * | registers |
49 * | |
50 * ----------------
51 * | | A copy of the dex registers above, but only
52 * | reference | containing references, used for GC.
53 * | registers |
54 * | |
55 * ----------------
56 * | caller fp | Frame pointer of caller. Stored below the reference
57 * ---------------- registers array for easy access from nterp when returning.
58 * | dex_pc_ptr | Pointer to the dex instruction being executed.
59 * ---------------- Stored whenever nterp goes into the runtime.
60 * | alignment | Stack aligment of kStackAlignment. TODO: try to move
61 * ---------------- this below the callee-save registers.
62 * | | In case nterp calls compiled code, we reserve space
63 * | out | for out registers. This space will be used for
64 * | registers | arguments passed on stack.
65 * | |
66 * ----------------
67 * | ArtMethod* | The method being currently executed.
68 * ----------------
69 *
70 * Exception handling:
71 * Nterp follows the same convention than the compiler,
72 * with the addition of:
73 * - All catch handlers have the same landing pad.
74 * - Before doing the longjmp for exception delivery, the register containing the
75 * dex PC pointer must be updated.
76 *
77 * Stack walking:
78 * An nterp frame is walked like a compiled code frame. We add an
79 * OatQuickMethodHeader prefix to the nterp entry point, which contains:
80 * - vmap_table_offset=0 (nterp doesn't need one).
81 * - code_size=NterpEnd-NterpStart
82 */
83
84static constexpr size_t kPointerSize = static_cast<size_t>(kRuntimePointerSize);
85
86static constexpr size_t NterpGetFrameEntrySize() {
87 uint32_t core_spills =
88 RuntimeCalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
89 uint32_t fp_spills =
90 RuntimeCalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
91 // Note: the return address is considered part of the callee saves.
92 return (POPCOUNT(core_spills) + POPCOUNT(fp_spills)) * kPointerSize;
93}
94
Nicolas Geoffray00391822019-12-10 10:17:23 +000095size_t NterpGetFrameSize(ArtMethod* method) {
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +000096 CodeItemDataAccessor accessor(method->DexInstructionData());
97 const uint16_t num_regs = accessor.RegistersSize();
98 const uint16_t out_regs = accessor.OutsSize();
99
100 size_t frame_size =
101 NterpGetFrameEntrySize() +
102 (num_regs * kVRegSize) * 2 + // dex registers and reference registers
103 kPointerSize + // previous frame
104 kPointerSize + // saved dex pc
105 (out_regs * kVRegSize) + // out arguments
106 kPointerSize; // method
107 return RoundUp(frame_size, kStackAlignment);
108}
109
110QuickMethodFrameInfo NterpFrameInfo(ArtMethod** frame) {
111 uint32_t core_spills =
112 RuntimeCalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
113 uint32_t fp_spills =
114 RuntimeCalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
115 return QuickMethodFrameInfo(NterpGetFrameSize(*frame), core_spills, fp_spills);
116}
117
118uintptr_t NterpGetRegistersArray(ArtMethod** frame) {
119 CodeItemDataAccessor accessor((*frame)->DexInstructionData());
120 const uint16_t num_regs = accessor.RegistersSize();
121 // The registers array is just below the frame entry.
122 return reinterpret_cast<uintptr_t>(frame) + NterpGetFrameSize(*frame) -
123 NterpGetFrameEntrySize() -
124 (num_regs * kVRegSize);
125}
126
127uintptr_t NterpGetReferenceArray(ArtMethod** frame) {
128 CodeItemDataAccessor accessor((*frame)->DexInstructionData());
129 const uint16_t num_regs = accessor.RegistersSize();
130 // The references array is just below the registers array.
131 return NterpGetRegistersArray(frame) - (num_regs * kVRegSize);
132}
133
134uint32_t NterpGetDexPC(ArtMethod** frame) {
135 uintptr_t dex_pc_ptr = NterpGetReferenceArray(frame) -
136 kPointerSize - // saved previous frame
137 kPointerSize; // saved dex pc
138 CodeItemInstructionAccessor accessor((*frame)->DexInstructions());
139 return *reinterpret_cast<const uint16_t**>(dex_pc_ptr) - accessor.Insns();
140}
141
142uint32_t NterpGetVReg(ArtMethod** frame, uint16_t vreg) {
143 return reinterpret_cast<uint32_t*>(NterpGetRegistersArray(frame))[vreg];
144}
145
Nicolas Geoffrayd7651b12019-12-18 14:57:30 +0000146uint32_t NterpGetVRegReference(ArtMethod** frame, uint16_t vreg) {
147 return reinterpret_cast<uint32_t*>(NterpGetReferenceArray(frame))[vreg];
148}
149
Nicolas Geoffray013d1ee2019-12-04 16:18:15 +0000150uintptr_t NterpGetCatchHandler() {
151 // Nterp uses the same landing pad for all exceptions. The dex_pc_ptr set before
152 // longjmp will actually be used to jmp to the catch handler.
153 return reinterpret_cast<uintptr_t>(artNterpAsmInstructionEnd);
154}
155
156} // namespace art