1 /*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/mem/machine_code.h"
17 #include "ecmascript/compiler/aot_file/func_entry_des.h"
18 #include "ecmascript/jit/jit.h"
19 #if ECMASCRIPT_ENABLE_CAST_CHECK
20 #include "ecmascript/js_tagged_value-inl.h"
21 #endif
22
23 namespace panda::ecmascript {
24
SetPageProtect(uint8_t *textStart, size_t dataSize)25 static bool SetPageProtect(uint8_t *textStart, size_t dataSize)
26 {
27 if (!Jit::GetInstance()->IsEnableJitFort()) {
28 constexpr size_t pageSize = 4096;
29 uintptr_t startPage = AlignDown(reinterpret_cast<uintptr_t>(textStart), pageSize);
30 uintptr_t endPage = AlignUp(reinterpret_cast<uintptr_t>(textStart) + dataSize, pageSize);
31 size_t protSize = endPage - startPage;
32 return PageProtect(reinterpret_cast<void*>(startPage), protSize, PAGE_PROT_EXEC_READWRITE);
33 }
34 return true;
35 }
36
MachineCodeCopyToCache([[maybe_unused]] const MachineCodeDesc &desc, [[maybe_unused]] uint8_t *pText)37 static int MachineCodeCopyToCache([[maybe_unused]] const MachineCodeDesc &desc, [[maybe_unused]] uint8_t *pText)
38 {
39 #ifndef JIT_ENABLE_CODE_SIGN
40 if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) {
41 LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
42 return false;
43 }
44 #endif
45 return true;
46 }
47
SetText(const MachineCodeDesc &desc)48 bool MachineCode::SetText(const MachineCodeDesc &desc)
49 {
50 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
51 uint8_t *pText = textStart;
52 if (desc.rodataSizeBeforeTextAlign != 0) {
53 if (memcpy_s(pText, desc.rodataSizeBeforeTextAlign,
54 reinterpret_cast<uint8_t*>(desc.rodataAddrBeforeText),
55 desc.rodataSizeBeforeText) != EOK) { // LCOV_EXCL_BR_LINE
56 LOG_JIT(ERROR) << "memcpy fail in copy fast jit code";
57 return false;
58 }
59 pText += desc.rodataSizeBeforeTextAlign;
60 }
61 if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() ||
62 !desc.isAsyncCompileMode) {
63 if (MachineCodeCopyToCache(desc, pText) == false) {
64 return false;
65 }
66 }
67 pText += desc.codeSizeAlign;
68 if (desc.rodataSizeAfterTextAlign != 0) {
69 if (memcpy_s(pText, desc.rodataSizeAfterTextAlign,
70 reinterpret_cast<uint8_t*>(desc.rodataAddrAfterText),
71 desc.rodataSizeAfterText) != EOK) { // LCOV_EXCL_BR_LINE
72 LOG_JIT(ERROR) << "memcpy fail in copy fast jit code";
73 return false;
74 }
75 }
76 return true;
77 }
78
SetNonText(const MachineCodeDesc &desc, EntityId methodId)79 bool MachineCode::SetNonText(const MachineCodeDesc &desc, EntityId methodId)
80 {
81 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
82 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
83 if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize,
84 reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr),
85 desc.stackMapOrOffsetTableSize) != EOK) { // LCOV_EXCL_BR_LINE
86 LOG_JIT(ERROR) << "memcpy fail in copy fast jit stackmap";
87 return false;
88 }
89
90 FuncEntryDes *funcEntry = reinterpret_cast<FuncEntryDes*>(desc.funcEntryDesAddr);
91 if (!funcEntry) {
92 LOG_JIT(ERROR) << "funcEntry is null.";
93 return false;
94 }
95 uint32_t cnt = desc.funcEntryDesSize / sizeof(FuncEntryDes);
96 ASSERT(cnt <= 2); // 2: jsfunction + deoptimize stub
97 for (uint32_t i = 0; i < cnt; i++) {
98 if (methodId == EntityId(funcEntry->indexInKindOrMethodId_)) {
99 uint64_t codeAddr = funcEntry->codeAddr_ +
100 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(textStart));
101 SetFuncAddr(codeAddr);
102 break;
103 }
104 funcEntry++;
105 }
106
107 SetIsFastCall(funcEntry->isFastCall_);
108 SetFpDeltaPrevFrameSp(funcEntry->fpDeltaPrevFrameSp_);
109 SetFuncSize(funcEntry->funcSize_);
110 SetCalleeRegisterNum(funcEntry->calleeRegisterNum_);
111 SetCalleeReg2OffsetArray(funcEntry->CalleeReg2Offset_);
112 return true;
113 }
114
SetData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize)115 bool MachineCode::SetData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize)
116 {
117 DISALLOW_GARBAGE_COLLECTION;
118 if (desc.codeType == MachineCodeType::BASELINE_CODE) {
119 return SetBaselineCodeData(desc, method, dataSize);
120 }
121
122 SetOSROffset(MachineCode::INVALID_OSR_OFFSET);
123 SetOsrDeoptFlag(false);
124 SetOsrExecuteCnt(0);
125
126 size_t instrSize = desc.rodataSizeBeforeTextAlign + desc.codeSizeAlign + desc.rodataSizeAfterTextAlign;
127
128 SetInstructionsSize(instrSize);
129 SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign);
130 SetPayLoadSizeInBytes(dataSize);
131 if (Jit::GetInstance()->IsEnableJitFort()) {
132 SetInstructionsAddr(desc.instructionsAddr);
133 ASSERT(desc.instructionsAddr != 0);
134 ASSERT(dataSize == (desc.funcEntryDesSizeAlign + desc.stackMapSizeAlign) ||
135 dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign));
136 } else {
137 ASSERT(dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign));
138 }
139 if (!SetText(desc)) {
140 return false;
141 }
142 if (!SetNonText(desc, method->GetMethodId())) {
143 return false;
144 }
145
146 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
147 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
148 CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName());
149 LOG_JIT(DEBUG) << "Fast JIT MachineCode :" << methodName << ", " << " text addr:" <<
150 reinterpret_cast<void*>(GetText()) << ", size:" << instrSize <<
151 ", stackMap addr:" << reinterpret_cast<void*>(stackmapAddr) <<
152 ", size:" << desc.stackMapSizeAlign;
153
154 if (!SetPageProtect(textStart, dataSize)) {
155 LOG_JIT(ERROR) << "MachineCode::SetData SetPageProtect failed";
156 return false;
157 }
158 return true;
159 }
160
SetBaselineCodeData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize)161 bool MachineCode::SetBaselineCodeData(const MachineCodeDesc &desc,
162 JSHandle<Method> &method, size_t dataSize)
163 {
164 DISALLOW_GARBAGE_COLLECTION;
165
166 size_t instrSizeAlign = desc.codeSizeAlign;
167 SetInstructionsSize(instrSizeAlign);
168
169 SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign);
170 if (Jit::GetInstance()->IsEnableJitFort()) {
171 ASSERT(desc.instructionsAddr != 0);
172 ASSERT(dataSize == (desc.stackMapSizeAlign) || // reg. obj
173 dataSize == (instrSizeAlign + desc.stackMapSizeAlign)); // huge obj
174 SetInstructionsAddr(desc.instructionsAddr);
175 } else {
176 ASSERT(dataSize == (instrSizeAlign + desc.stackMapSizeAlign));
177 }
178 SetPayLoadSizeInBytes(dataSize);
179
180 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
181 if (Jit::GetInstance()->IsEnableJitFort()) {
182 // relax assert for now until machine code padding for JitFort resolved
183 ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN) ||
184 IsAligned(reinterpret_cast<uintptr_t>(textStart), DATA_ALIGN));
185 } else {
186 ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN));
187 }
188 uint8_t *pText = textStart;
189
190 if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() ||
191 !desc.isAsyncCompileMode) {
192 if (MachineCodeCopyToCache(desc, pText) == false) {
193 return false;
194 }
195 }
196 pText += instrSizeAlign;
197
198 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
199 if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize,
200 reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr),
201 desc.stackMapOrOffsetTableSize) != EOK) { // LCOV_EXCL_BR_LINE
202 LOG_BASELINEJIT(ERROR) << "memcpy fail in copy fast baselineJIT offsetTable";
203 return false;
204 }
205
206 SetFuncAddr(reinterpret_cast<uintptr_t>(textStart));
207
208 CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName());
209 LOG_BASELINEJIT(DEBUG) << "BaselineCode :" << methodName << ", " << " text addr:" <<
210 reinterpret_cast<void*>(GetText()) << ", size:" << instrSizeAlign <<
211 ", stackMap addr: 0, size: 0";
212
213 if (!SetPageProtect(textStart, dataSize)) {
214 LOG_BASELINEJIT(ERROR) << "MachineCode::SetBaseLineCodeData SetPageProtect failed";
215 return false;
216 }
217 return true;
218 }
219
IsInText(const uintptr_t pc) const220 bool MachineCode::IsInText(const uintptr_t pc) const
221 {
222 uintptr_t textStart = GetText();
223 uintptr_t textEnd = textStart + GetTextSize();
224 return textStart <= pc && pc < textEnd;
225 }
226
CalCallSiteInfo() const227 std::tuple<uint64_t, uint8_t*, int, kungfu::CalleeRegAndOffsetVec> MachineCode::CalCallSiteInfo() const
228 {
229 uintptr_t textStart = GetText();
230 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
231 ASSERT(stackmapAddr != nullptr);
232
233 int delta = GetFpDeltaPrevFrameSp();
234 kungfu::CalleeRegAndOffsetVec calleeRegInfo;
235 for (uint32_t j = 0; j < GetCalleeRegisterNum(); j++) {
236 kungfu::LLVMStackMapType::DwarfRegType reg =
237 static_cast<kungfu::LLVMStackMapType::DwarfRegType>(GetCalleeReg2OffsetArray(2 * j));
238 kungfu::LLVMStackMapType::OffsetType offset =
239 static_cast<kungfu::LLVMStackMapType::OffsetType>(GetCalleeReg2OffsetArray(2 * j + 1));
240 kungfu::LLVMStackMapType::DwarfRegAndOffsetType regAndOffset = std::make_pair(reg, offset);
241 calleeRegInfo.emplace_back(regAndOffset);
242 }
243 auto ret = std::make_tuple(textStart, stackmapAddr, delta, calleeRegInfo);
244 return ret;
245 }
246
GetText() const247 uintptr_t MachineCode::GetText() const
248 {
249 if (Jit::GetInstance()->IsEnableJitFort()) {
250 return GetInstructionsAddr();
251 } else {
252 return GetNonTextAddress();
253 }
254 }
255
GetStackMapOrOffsetTableAddress() const256 uint8_t *MachineCode::GetStackMapOrOffsetTableAddress() const
257 {
258 if (Jit::GetInstance()->IsEnableJitFort()) {
259 // stackmap immediately follows MachineCode NonText area
260 return reinterpret_cast<uint8_t*>(GetNonTextAddress());
261 } else {
262 return reinterpret_cast<uint8_t*>(GetText() + GetInstructionsSize());
263 }
264 }
265
ProcessMarkObject()266 void MachineCode::ProcessMarkObject()
267 {
268 Region *region = Region::ObjectAddressToRange(this);
269 Heap *localHeap = reinterpret_cast<Heap *>(region->GetLocalHeap());
270 if (!localHeap) {
271 // it is a huge machine code object. skip
272 return;
273 }
274 ASSERT(localHeap->GetMachineCodeSpace());
275 if (localHeap->GetMachineCodeSpace()) {
276 localHeap->GetMachineCodeSpace()->MarkJitFortMemAlive(this);
277 }
278 }
279
280 } // namespace panda::ecmascript
281