• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 namespace panda::ecmascript {
21 
SetPageProtect(uint8_t * textStart,size_t dataSize)22 static bool SetPageProtect(uint8_t *textStart, size_t dataSize)
23 {
24     if (!Jit::GetInstance()->IsEnableJitFort()) {
25         constexpr size_t pageSize = 4096;
26         uintptr_t startPage = AlignDown(reinterpret_cast<uintptr_t>(textStart), pageSize);
27         uintptr_t endPage = AlignUp(reinterpret_cast<uintptr_t>(textStart) + dataSize, pageSize);
28         size_t protSize = endPage - startPage;
29         return PageProtect(reinterpret_cast<void*>(startPage), protSize, PAGE_PROT_EXEC_READWRITE);
30     }
31     return true;
32 }
33 
MachineCodeCopyToCache(const MachineCodeDesc & desc,uint8_t * pText)34 static int MachineCodeCopyToCache([[maybe_unused]] const MachineCodeDesc &desc, [[maybe_unused]] uint8_t *pText)
35 {
36 #ifndef JIT_ENABLE_CODE_SIGN
37     if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) {
38         LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
39         return false;
40     }
41 #endif
42     return true;
43 }
44 
SetText(const MachineCodeDesc & desc)45 bool MachineCode::SetText(const MachineCodeDesc &desc)
46 {
47     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
48     uint8_t *pText = textStart;
49     if (desc.rodataSizeBeforeTextAlign != 0) {
50         if (memcpy_s(pText, desc.rodataSizeBeforeTextAlign,
51             reinterpret_cast<uint8_t*>(desc.rodataAddrBeforeText), desc.rodataSizeBeforeText) != EOK) {
52             LOG_JIT(ERROR) << "memcpy fail in copy fast jit code";
53             return false;
54         }
55         pText += desc.rodataSizeBeforeTextAlign;
56     }
57     if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() ||
58         !desc.isAsyncCompileMode) {
59         if (MachineCodeCopyToCache(desc, pText) == false) {
60             return false;
61         }
62     }
63     pText += desc.codeSizeAlign;
64     if (desc.rodataSizeAfterTextAlign != 0) {
65         if (memcpy_s(pText, desc.rodataSizeAfterTextAlign,
66             reinterpret_cast<uint8_t*>(desc.rodataAddrAfterText), desc.rodataSizeAfterText) != EOK) {
67             LOG_JIT(ERROR) << "memcpy fail in copy fast jit code";
68             return false;
69         }
70     }
71     return true;
72 }
73 
SetNonText(const MachineCodeDesc & desc,EntityId methodId)74 bool MachineCode::SetNonText(const MachineCodeDesc &desc, EntityId methodId)
75 {
76     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
77     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
78     if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize,
79                  reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr),
80                  desc.stackMapOrOffsetTableSize) != EOK) {
81         LOG_JIT(ERROR) << "memcpy fail in copy fast jit stackmap";
82         return false;
83     }
84 
85     FuncEntryDes *funcEntry = reinterpret_cast<FuncEntryDes*>(GetFuncEntryDesAddress());
86     if (memcpy_s(funcEntry, desc.funcEntryDesSize, reinterpret_cast<uint8_t*>(desc.funcEntryDesAddr),
87         desc.funcEntryDesSize) != EOK) {
88         LOG_JIT(ERROR) << "memcpy fail in copy fast jit funcEntry";
89         return false;
90     }
91 
92     uint32_t cnt = desc.funcEntryDesSize / sizeof(FuncEntryDes);
93     ASSERT(cnt <= 2); // 2: jsfunction + deoptimize stub
94     for (uint32_t i = 0; i < cnt; i++) {
95         funcEntry->codeAddr_ += reinterpret_cast<uintptr_t>(textStart);
96         if (methodId == EntityId(funcEntry->indexInKindOrMethodId_)) {
97             SetFuncAddr(funcEntry->codeAddr_);
98         }
99         funcEntry++;
100     }
101     return true;
102 }
103 
SetData(const MachineCodeDesc & desc,JSHandle<Method> & method,size_t dataSize)104 bool MachineCode::SetData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize)
105 {
106     DISALLOW_GARBAGE_COLLECTION;
107     if (desc.codeType == MachineCodeType::BASELINE_CODE) {
108         return SetBaselineCodeData(desc, method, dataSize);
109     }
110 
111     SetOSROffset(MachineCode::INVALID_OSR_OFFSET);
112     SetOsrDeoptFlag(false);
113     SetOsrExecuteCnt(0);
114 
115     size_t instrSize = desc.rodataSizeBeforeTextAlign + desc.codeSizeAlign + desc.rodataSizeAfterTextAlign;
116 
117     SetFuncEntryDesSize(desc.funcEntryDesSizeAlign);
118     SetInstructionsSize(instrSize);
119     SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign);
120     SetPayLoadSizeInBytes(dataSize);
121     if (Jit::GetInstance()->IsEnableJitFort()) {
122         SetInstructionsAddr(desc.instructionsAddr);
123         ASSERT(desc.instructionsAddr != 0);
124         ASSERT(dataSize == (desc.funcEntryDesSizeAlign + desc.stackMapSizeAlign) ||
125                dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign));
126     } else {
127         ASSERT(dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign));
128     }
129     if (!SetText(desc)) {
130         return false;
131     }
132     if (!SetNonText(desc, method->GetMethodId())) {
133         return false;
134     }
135 
136     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
137     uint32_t cnt = desc.funcEntryDesSize / sizeof(FuncEntryDes);
138     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
139     CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName());
140     LOG_JIT(DEBUG) << "Fast JIT MachineCode :" << methodName << ", "  << " text addr:" <<
141         reinterpret_cast<void*>(GetText()) << ", size:" << instrSize  <<
142         ", stackMap addr:" << reinterpret_cast<void*>(stackmapAddr) <<
143         ", size:" << desc.stackMapSizeAlign <<
144         ", funcEntry addr:" << reinterpret_cast<void*>(GetFuncEntryDesAddress()) << ", count:" << cnt;
145 
146     if (!SetPageProtect(textStart, dataSize)) {
147         LOG_JIT(ERROR) << "MachineCode::SetData SetPageProtect failed";
148         return false;
149     }
150     return true;
151 }
152 
SetBaselineCodeData(const MachineCodeDesc & desc,JSHandle<Method> & method,size_t dataSize)153 bool MachineCode::SetBaselineCodeData(const MachineCodeDesc &desc,
154                                       JSHandle<Method> &method, size_t dataSize)
155 {
156     DISALLOW_GARBAGE_COLLECTION;
157     SetFuncEntryDesSize(0);
158 
159     size_t instrSizeAlign = desc.codeSizeAlign;
160     SetInstructionsSize(instrSizeAlign);
161 
162     SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign);
163     if (Jit::GetInstance()->IsEnableJitFort()) {
164         ASSERT(desc.instructionsAddr != 0);
165         ASSERT(dataSize == (desc.stackMapSizeAlign) ||  // reg. obj
166                dataSize == (instrSizeAlign + desc.stackMapSizeAlign)); // huge obj
167         SetInstructionsAddr(desc.instructionsAddr);
168     } else {
169         ASSERT(dataSize == (instrSizeAlign + desc.stackMapSizeAlign));
170     }
171     SetPayLoadSizeInBytes(dataSize);
172 
173     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
174     if (Jit::GetInstance()->IsEnableJitFort()) {
175         // relax assert for now until machine code padding for JitFort resolved
176         ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN) ||
177             IsAligned(reinterpret_cast<uintptr_t>(textStart), DATA_ALIGN));
178     } else {
179         ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN));
180     }
181     uint8_t *pText = textStart;
182 
183     if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() ||
184         !desc.isAsyncCompileMode) {
185         if (MachineCodeCopyToCache(desc, pText) == false) {
186             return false;
187         }
188     }
189     pText += instrSizeAlign;
190 
191     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
192     if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize,
193                  reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr),
194                  desc.stackMapOrOffsetTableSize) != EOK) {
195         LOG_BASELINEJIT(ERROR) << "memcpy fail in copy fast baselineJIT offsetTable";
196         return false;
197     }
198 
199     SetFuncAddr(reinterpret_cast<uintptr_t>(textStart));
200 
201     CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName());
202     LOG_BASELINEJIT(DEBUG) << "BaselineCode :" << methodName << ", "  << " text addr:" <<
203         reinterpret_cast<void*>(GetText()) << ", size:" << instrSizeAlign  <<
204         ", stackMap addr: 0, size: 0, funcEntry addr: 0, count 0";
205 
206     if (!SetPageProtect(textStart, dataSize)) {
207         LOG_BASELINEJIT(ERROR) << "MachineCode::SetBaseLineCodeData SetPageProtect failed";
208         return false;
209     }
210     return true;
211 }
212 
IsInText(const uintptr_t pc) const213 bool MachineCode::IsInText(const uintptr_t pc) const
214 {
215     uintptr_t textStart = GetText();
216     uintptr_t textEnd = textStart + GetTextSize();
217     return textStart <= pc && pc < textEnd;
218 }
219 
GetFuncEntryDes() const220 uintptr_t MachineCode::GetFuncEntryDes() const
221 {
222     uint32_t funcEntryCnt = GetFuncEntryDesSize() / sizeof(FuncEntryDes);
223     FuncEntryDes *funcEntryDes = reinterpret_cast<FuncEntryDes*>(GetFuncEntryDesAddress());
224     for (uint32_t i = 0; i < funcEntryCnt; i++) {
225         if (funcEntryDes->codeAddr_ == GetFuncAddr()) {
226             return reinterpret_cast<uintptr_t>(funcEntryDes);
227         }
228         funcEntryDes++;
229     }
230     UNREACHABLE();
231     return 0;
232 }
233 
CalCallSiteInfo(uintptr_t retAddr) const234 std::tuple<uint64_t, uint8_t*, int, kungfu::CalleeRegAndOffsetVec> MachineCode::CalCallSiteInfo(uintptr_t retAddr) const
235 {
236     uintptr_t textStart = GetText();
237     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
238     ASSERT(stackmapAddr != nullptr);
239 
240     uint32_t funcEntryCnt = GetFuncEntryDesSize() / sizeof(FuncEntryDes);
241     FuncEntryDes *tmpFuncEntryDes = reinterpret_cast<FuncEntryDes*>(GetFuncEntryDesAddress());
242     FuncEntryDes *funcEntryDes = nullptr;
243     ASSERT(tmpFuncEntryDes != nullptr);
244     uintptr_t pc = retAddr - 1;  // -1: for pc
245     for (uint32_t i = 0; i < funcEntryCnt; i++) {
246         if (tmpFuncEntryDes->codeAddr_ <= pc && pc < (tmpFuncEntryDes->codeAddr_ + tmpFuncEntryDes->funcSize_)) {
247             funcEntryDes = tmpFuncEntryDes;
248             break;
249         }
250         tmpFuncEntryDes++;
251     }
252 
253     if (funcEntryDes == nullptr) {
254         return {};
255     }
256 
257     int delta = funcEntryDes->fpDeltaPrevFrameSp_;
258     kungfu::CalleeRegAndOffsetVec calleeRegInfo;
259     for (uint32_t j = 0; j < funcEntryDes->calleeRegisterNum_; j++) {
260         kungfu::LLVMStackMapType::DwarfRegType reg =
261             static_cast<kungfu::LLVMStackMapType::DwarfRegType>(funcEntryDes->CalleeReg2Offset_[2 * j]);
262         kungfu::LLVMStackMapType::OffsetType offset =
263             static_cast<kungfu::LLVMStackMapType::OffsetType>(funcEntryDes->CalleeReg2Offset_[2 * j + 1]);
264         kungfu::LLVMStackMapType::DwarfRegAndOffsetType regAndOffset = std::make_pair(reg, offset);
265         calleeRegInfo.emplace_back(regAndOffset);
266     }
267     auto ret = std::make_tuple(textStart, stackmapAddr, delta, calleeRegInfo);
268     return ret;
269 }
270 
GetText() const271 uintptr_t MachineCode::GetText() const
272 {
273     if (Jit::GetInstance()->IsEnableJitFort()) {
274         return GetInstructionsAddr();
275     } else {
276         return GetFuncEntryDesAddress() + GetFuncEntryDesSize();
277     }
278 }
279 
GetStackMapOrOffsetTableAddress() const280 uint8_t *MachineCode::GetStackMapOrOffsetTableAddress() const
281 {
282     if (Jit::GetInstance()->IsEnableJitFort()) {
283         // stackmap immediately follows FuncEntryDesc area
284         return reinterpret_cast<uint8_t*>(GetFuncEntryDesAddress() + GetFuncEntryDesSize());
285     } else {
286         return reinterpret_cast<uint8_t*>(GetText() + GetInstructionsSize());
287     }
288 }
289 
290 }  // namespace panda::ecmascript
291