• 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/base/config.h"
18 #include "ecmascript/compiler/aot_file/func_entry_des.h"
19 #include "ecmascript/jit/jit.h"
20 #include "ecmascript/compiler/jit_compilation_env.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 #ifdef JIT_ENABLE_CODE_SIGN
42     if ((uintptr_t)desc.codeSigner == 0) {
43         if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) {
44             LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
45             return false;
46         }
47     } else {
48         LOG_JIT(DEBUG) << "Copy: " << std::hex << (uintptr_t)pText << " <- " << std::hex << (uintptr_t)desc.codeAddr
49                        << " size: " << desc.codeSize;
50         LOG_JIT(DEBUG) << "     codeSigner = " << std::hex << (uintptr_t)desc.codeSigner;
51         OHOS::Security::CodeSign::JitCodeSigner* signer =
52             reinterpret_cast<OHOS::Security::CodeSign::JitCodeSigner*>(desc.codeSigner);
53         int err = OHOS::Security::CodeSign::CopyToJitCode(signer, pText, reinterpret_cast<void*>(desc.codeAddr),
54                                                           desc.codeSize);
55         if (err != EOK) {
56             LOG_JIT(ERROR) << "     CopyToJitCode failed, err: " << err;
57             return false;
58         } else {
59             LOG_JIT(DEBUG) << "     CopyToJitCode success!!";
60         }
61         delete reinterpret_cast<OHOS::Security::CodeSign::JitCodeSigner*>(desc.codeSigner);
62     }
63 #else
64     if (memcpy_s(pText, desc.codeSizeAlign, // LCOV_EXCL_BR_LINE
65         reinterpret_cast<uint8_t*>(desc.codeAddr),
66         desc.codeSize) != EOK) {
67         LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
68         return false;
69     }
70 #endif
71     return true;
72 }
73 
SetText(const MachineCodeDesc & desc)74 bool MachineCode::SetText(const MachineCodeDesc &desc)
75 {
76     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
77     uint8_t *pText = textStart;
78     if (desc.rodataSizeBeforeTextAlign != 0) {
79         if (memcpy_s(pText, desc.rodataSizeBeforeTextAlign, // LCOV_EXCL_BR_LINE
80             reinterpret_cast<uint8_t*>(desc.rodataAddrBeforeText),
81             desc.rodataSizeBeforeText) != EOK) {
82             LOG_JIT(ERROR) << "memcpy fail in copy fast jit code";
83             return false;
84         }
85         pText += desc.rodataSizeBeforeTextAlign;
86     }
87     if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() ||
88         !desc.isAsyncCompileMode) {
89         if (MachineCodeCopyToCache(desc, pText) == false) {
90             return false;
91         }
92     }
93     pText += desc.codeSizeAlign;
94     if (desc.rodataSizeAfterTextAlign != 0) {
95         if (memcpy_s(pText, desc.rodataSizeAfterTextAlign, // LCOV_EXCL_BR_LINE
96             reinterpret_cast<uint8_t*>(desc.rodataAddrAfterText),
97             desc.rodataSizeAfterText) != EOK) {
98             LOG_JIT(ERROR) << "memcpy fail in copy fast jit code";
99             return false;
100         }
101     }
102     return true;
103 }
104 
SetNonText(const MachineCodeDesc & desc,EntityId methodId)105 bool MachineCode::SetNonText(const MachineCodeDesc &desc, EntityId methodId)
106 {
107     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
108     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
109     if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize, // LCOV_EXCL_BR_LINE
110                  reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr),
111                  desc.stackMapOrOffsetTableSize) != EOK) {
112         LOG_JIT(ERROR) << "memcpy fail in copy fast jit stackmap";
113         return false;
114     }
115 
116     FuncEntryDes *funcEntry = reinterpret_cast<FuncEntryDes*>(desc.funcEntryDesAddr);
117     if (!funcEntry) {
118         LOG_JIT(ERROR) << "funcEntry is null.";
119         return false;
120     }
121     uint32_t cnt = desc.funcEntryDesSize / sizeof(FuncEntryDes);
122     ASSERT(cnt <= 2); // 2: jsfunction + deoptimize stub
123     for (uint32_t i = 0; i < cnt; i++) {
124         if (methodId == EntityId(funcEntry->indexInKindOrMethodId_)) {
125             uint64_t codeAddr = funcEntry->codeAddr_ +
126                                 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(textStart));
127             SetFuncAddr(codeAddr);
128             break;
129         }
130         funcEntry++;
131     }
132 
133     SetIsFastCall(funcEntry->isFastCall_);
134     SetFpDeltaPrevFrameSp(funcEntry->fpDeltaPrevFrameSp_);
135     SetFuncSize(funcEntry->funcSize_);
136     SetCalleeRegisterNum(funcEntry->calleeRegisterNum_);
137     SetCalleeReg2OffsetArray(funcEntry->CalleeReg2Offset_);
138     return true;
139 }
140 
SetData(JSThread * thread,const MachineCodeDesc & desc,JSHandle<Method> & method,size_t dataSize)141 bool MachineCode::SetData(JSThread *thread, const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize)
142 {
143     DISALLOW_GARBAGE_COLLECTION;
144     if (desc.codeType == MachineCodeType::BASELINE_CODE) {
145         return SetBaselineCodeData(thread, desc, method, dataSize);
146     }
147 
148     if (desc.isHugeObj) {
149         SetLocalHeapAddress(0);
150     } else {
151         SetLocalHeapAddress(reinterpret_cast<uint64_t>(thread->GetEcmaVM()->GetHeap()));
152     }
153 
154     SetOSROffset(MachineCode::INVALID_OSR_OFFSET);
155     SetOsrDeoptFlag(false);
156     SetOsrExecuteCnt(0);
157 
158     size_t instrSize = desc.rodataSizeBeforeTextAlign + desc.codeSizeAlign + desc.rodataSizeAfterTextAlign;
159 
160     SetInstructionsSize(instrSize);
161     SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign);
162     SetHeapConstantTableSize(desc.heapConstantTableSizeAlign);
163     SetHeapConstantTableAddr(reinterpret_cast<uint64_t>(GetHeapConstantTableAddress()));
164     SetPayLoadSizeInBytes(dataSize);
165     if (Jit::GetInstance()->IsEnableJitFort()) {
166         SetInstructionsAddr(desc.instructionsAddr);
167         ASSERT(desc.instructionsAddr != 0);
168         ASSERT(dataSize == (desc.funcEntryDesSizeAlign + desc.stackMapSizeAlign + desc.heapConstantTableSizeAlign) ||
169                dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign +
170                             desc.heapConstantTableSizeAlign));
171     } else {
172         ASSERT(dataSize == (desc.funcEntryDesSizeAlign + instrSize +
173                             desc.stackMapSizeAlign + desc.heapConstantTableSizeAlign));
174     }
175     if (!SetText(desc)) {
176         return false;
177     }
178     if (!SetNonText(desc, method->GetMethodId())) {
179         return false;
180     }
181 
182     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
183     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
184     CString methodName = method->GetRecordNameStr(thread) + "." + CString(method->GetMethodName(thread));
185     LOG_JIT(DEBUG) << "Fast JIT MachineCode :" << methodName << ", "  << " text addr:" <<
186         reinterpret_cast<void*>(GetText()) << ", size:" << instrSize  <<
187         ", stackMap addr:" << reinterpret_cast<void*>(stackmapAddr) <<
188         ", size:" << desc.stackMapSizeAlign;
189 
190     if (!SetPageProtect(textStart, dataSize)) {
191         LOG_JIT(ERROR) << "MachineCode::SetData SetPageProtect failed";
192         return false;
193     }
194     return true;
195 }
196 
SetBaselineCodeData(JSThread * thread,const MachineCodeDesc & desc,JSHandle<Method> & method,size_t dataSize)197 bool MachineCode::SetBaselineCodeData(JSThread *thread, const MachineCodeDesc &desc,
198                                       JSHandle<Method> &method, size_t dataSize)
199 {
200     DISALLOW_GARBAGE_COLLECTION;
201 
202     size_t instrSizeAlign = desc.codeSizeAlign;
203     SetInstructionsSize(instrSizeAlign);
204 
205     SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign);
206     if (Jit::GetInstance()->IsEnableJitFort()) {
207         ASSERT(desc.instructionsAddr != 0);
208         ASSERT(dataSize == (desc.stackMapSizeAlign) ||  // reg. obj
209                dataSize == (instrSizeAlign + desc.stackMapSizeAlign)); // huge obj
210         SetInstructionsAddr(desc.instructionsAddr);
211     } else {
212         ASSERT(dataSize == (instrSizeAlign + desc.stackMapSizeAlign));
213     }
214     SetPayLoadSizeInBytes(dataSize);
215 
216     uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText());
217     if (Jit::GetInstance()->IsEnableJitFort()) {
218         // relax assert for now until machine code padding for JitFort resolved
219         ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN) ||
220             IsAligned(reinterpret_cast<uintptr_t>(textStart), DATA_ALIGN));
221     } else {
222         ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN));
223     }
224     uint8_t *pText = textStart;
225 
226     if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() ||
227         !desc.isAsyncCompileMode) {
228         if (MachineCodeCopyToCache(desc, pText) == false) {
229             return false;
230         }
231     }
232     pText += instrSizeAlign;
233 
234     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
235     if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize, // LCOV_EXCL_BR_LINE
236                  reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr),
237                  desc.stackMapOrOffsetTableSize) != EOK) {
238         LOG_BASELINEJIT(ERROR) << "memcpy fail in copy fast baselineJIT offsetTable";
239         return false;
240     }
241 
242     SetFuncAddr(reinterpret_cast<uintptr_t>(textStart));
243 
244     CString methodName = method->GetRecordNameStr(thread) + "." + CString(method->GetMethodName(thread));
245     LOG_BASELINEJIT(DEBUG) << "BaselineCode :" << methodName << ", "  << " text addr:" <<
246         reinterpret_cast<void*>(GetText()) << ", size:" << instrSizeAlign  <<
247         ", stackMap addr: 0, size: 0";
248 
249     if (!SetPageProtect(textStart, dataSize)) {
250         LOG_BASELINEJIT(ERROR) << "MachineCode::SetBaseLineCodeData SetPageProtect failed";
251         return false;
252     }
253     return true;
254 }
255 
IsInText(const uintptr_t pc) const256 bool MachineCode::IsInText(const uintptr_t pc) const
257 {
258     uintptr_t textStart = GetText();
259     uintptr_t textEnd = textStart + GetTextSize();
260     return textStart <= pc && pc < textEnd;
261 }
262 
CalCallSiteInfo() const263 std::tuple<uint64_t, uint8_t*, int, kungfu::CalleeRegAndOffsetVec> MachineCode::CalCallSiteInfo() const
264 {
265     uintptr_t textStart = GetText();
266     uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress();
267     ASSERT(stackmapAddr != nullptr);
268 
269     int delta = GetFpDeltaPrevFrameSp();
270     kungfu::CalleeRegAndOffsetVec calleeRegInfo;
271     for (uint32_t j = 0; j < GetCalleeRegisterNum(); j++) {
272         kungfu::LLVMStackMapType::DwarfRegType reg =
273             static_cast<kungfu::LLVMStackMapType::DwarfRegType>(GetCalleeReg2OffsetArray(2 * j));
274         kungfu::LLVMStackMapType::OffsetType offset =
275             static_cast<kungfu::LLVMStackMapType::OffsetType>(GetCalleeReg2OffsetArray(2 * j + 1));
276         kungfu::LLVMStackMapType::DwarfRegAndOffsetType regAndOffset = std::make_pair(reg, offset);
277         calleeRegInfo.emplace_back(regAndOffset);
278     }
279     auto ret = std::make_tuple(textStart, stackmapAddr, delta, calleeRegInfo);
280     return ret;
281 }
282 
GetText() const283 uintptr_t MachineCode::GetText() const
284 {
285     if (Jit::GetInstance()->IsEnableJitFort()) {
286         return GetInstructionsAddr();
287     } else {
288         return GetNonTextAddress();
289     }
290 }
291 
GetStackMapOrOffsetTableAddress() const292 uint8_t *MachineCode::GetStackMapOrOffsetTableAddress() const
293 {
294     if (Jit::GetInstance()->IsEnableJitFort()) {
295         // stackmap immediately follows MachineCode NonText area
296         return reinterpret_cast<uint8_t*>(GetNonTextAddress());
297     } else {
298         return reinterpret_cast<uint8_t*>(GetText() + GetInstructionsSize());
299     }
300 }
301 
GetHeapConstantTableAddress() const302 uint8_t *MachineCode::GetHeapConstantTableAddress() const
303 {
304     return reinterpret_cast<uint8_t*>(GetStackMapOrOffsetTableAddress() + GetStackMapOrOffsetTableSize());
305 }
306 
ProcessMarkObject()307 void MachineCode::ProcessMarkObject()
308 {
309     if (g_isEnableCMCGC) {
310         Heap* heap = reinterpret_cast<Heap*>(this->GetLocalHeapAddress());
311         // Skip HugeMachinecode or VM that is already destoryed
312         // We should implement a proper wait for VM destructor
313         if (heap && heap->GetMachineCodeSpace()) {
314             heap->GetMachineCodeSpace()->MarkJitFortMemAlive(this);
315         }
316     } else {
317         Region *region = Region::ObjectAddressToRange(this);
318         Heap *localHeap = reinterpret_cast<Heap *>(region->GetLocalHeap());
319         if (!localHeap) {
320             // it is a huge machine code object. skip
321             return;
322         }
323         ASSERT(localHeap->GetMachineCodeSpace());
324         if (localHeap->GetMachineCodeSpace()) {
325             localHeap->GetMachineCodeSpace()->MarkJitFortMemAlive(this);
326         }
327     }
328 }
329 
330 }  // namespace panda::ecmascript
331