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