mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-08-27 20:40:01 -04:00
5905b54c34
Description: 1.Fix the bug that Circuit IR args gates do not match the function args of the abc file. 2.Add class ArgumentAccessor to handle args gates of Circuit IR. 3.Modify to set the AOT function entry when constpool is being parsed. 4.For functions sharing the same instructions, add a map to collect duplicate infomation. The key of the map is the current method and the value is the first method with the same nstructions to be translated. Issue: https://gitee.com/openharmony/ark_js_runtime/issues/I5DA6V Change-Id: I08e48444eb22c4fc2841e1cdae44b90286de84ac Signed-off-by: huoqingyi <huoqingyi@huawei.com>
395 lines
16 KiB
C++
395 lines
16 KiB
C++
/*
|
|
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "ecmascript/file_loader.h"
|
|
|
|
#include "ecmascript/base/config.h"
|
|
#include "ecmascript/compiler/bc_call_signature.h"
|
|
#include "ecmascript/compiler/common_stubs.h"
|
|
#include "ecmascript/llvm_stackmap_parser.h"
|
|
#include "ecmascript/ecma_vm.h"
|
|
#include "ecmascript/jspandafile/constpool_value.h"
|
|
#include "ecmascript/jspandafile/js_pandafile.h"
|
|
#include "ecmascript/jspandafile/program_object.h"
|
|
#include "ecmascript/js_runtime_options.h"
|
|
#include "ecmascript/js_thread.h"
|
|
#include "ecmascript/snapshot/mem/snapshot.h"
|
|
|
|
extern const uint8_t _binary_stub_m_start[];
|
|
extern const uint32_t _binary_stub_m_length;
|
|
|
|
namespace panda::ecmascript {
|
|
void StubModulePackInfo::Save(const std::string &filename)
|
|
{
|
|
if (!VerifyFilePath(filename, true)) {
|
|
return;
|
|
}
|
|
|
|
std::ofstream moduleFile(filename.c_str(), std::ofstream::binary);
|
|
SetStubNum(entries_.size());
|
|
/* write stub entries offset */
|
|
moduleFile.write(reinterpret_cast<char *>(&entryNum_), sizeof(entryNum_));
|
|
moduleFile.write(reinterpret_cast<char *>(entries_.data()), sizeof(FuncEntryDes) * entryNum_);
|
|
uint32_t moduleNum = GetCodeUnitsNum();
|
|
moduleFile.write(reinterpret_cast<char *>(&moduleNum), sizeof(moduleNum_));
|
|
moduleFile.write(reinterpret_cast<char *>(&totalCodeSize_), sizeof(totalCodeSize_));
|
|
for (size_t i = 0; i < moduleNum; i++) {
|
|
moduleFile.write(reinterpret_cast<char *>(&(des_[i].hostCodeSectionAddr_)),
|
|
sizeof(des_[i].hostCodeSectionAddr_));
|
|
moduleFile.write(reinterpret_cast<char *>(&(des_[i].codeSize_)),
|
|
sizeof(des_[i].codeSize_));
|
|
moduleFile.write(reinterpret_cast<char *>(des_[i].GetHostCodeSecAddr()),
|
|
des_[i].GetCodeSize());
|
|
moduleFile.write(reinterpret_cast<char *>(&(des_[i].stackMapSize_)),
|
|
sizeof(des_[i].stackMapSize_));
|
|
moduleFile.write(reinterpret_cast<char *>(des_[i].GetStackMapSecAddr()),
|
|
des_[i].GetStackMapSize());
|
|
}
|
|
moduleFile.close();
|
|
}
|
|
|
|
bool StubModulePackInfo::Load(EcmaVM *vm)
|
|
{
|
|
// now MachineCode is non movable, code and stackmap sperately is saved to MachineCode
|
|
// by calling NewMachineCodeObject.
|
|
// then MachineCode will support movable, code is saved to MachineCode and stackmap is saved
|
|
// to different heap which will be freed when stackmap is parsed by EcmaVM is started.
|
|
if (_binary_stub_m_length <= 1) {
|
|
LOG_ECMA(FATAL) << "stub.m length <= 1, is default and invalid.";
|
|
return false;
|
|
}
|
|
BinaryBufferParser binBufparser((uint8_t *)_binary_stub_m_start, _binary_stub_m_length);
|
|
binBufparser.ParseBuffer(&entryNum_, sizeof(entryNum_));
|
|
entries_.resize(entryNum_);
|
|
binBufparser.ParseBuffer(entries_.data(), sizeof(FuncEntryDes) * entryNum_);
|
|
binBufparser.ParseBuffer(&moduleNum_, sizeof(moduleNum_));
|
|
des_.resize(moduleNum_);
|
|
uint32_t totalCodeSize = 0;
|
|
binBufparser.ParseBuffer(&totalCodeSize, sizeof(totalCodeSize_));
|
|
auto factory = vm->GetFactory();
|
|
auto codeHandle = factory->NewMachineCodeObject(totalCodeSize, nullptr);
|
|
SetCode(codeHandle);
|
|
uint32_t curUnitOffset = 0;
|
|
for (size_t i = 0; i < moduleNum_; i++) {
|
|
binBufparser.ParseBuffer(&(des_[i].hostCodeSectionAddr_),
|
|
sizeof(des_[i].hostCodeSectionAddr_));
|
|
binBufparser.ParseBuffer(&(des_[i].codeSize_),
|
|
sizeof(des_[i].codeSize_));
|
|
uint32_t codeSize = des_[i].GetCodeSize();
|
|
// startAddr of current code unit on device side
|
|
uintptr_t startAddr = codeHandle->GetDataOffsetAddress() + static_cast<uintptr_t>(curUnitOffset);
|
|
binBufparser.ParseBuffer(reinterpret_cast<void *>(startAddr), codeSize);
|
|
curUnitOffset += codeSize;
|
|
des_[i].SetDeviceCodeSecAddr(startAddr);
|
|
binBufparser.ParseBuffer(&(des_[i].stackMapSize_),
|
|
sizeof(des_[i].stackMapSize_));
|
|
uint32_t stackmapSize = des_[i].GetStackMapSize();
|
|
std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize));
|
|
binBufparser.ParseBuffer(stackmapPtr.get(), stackmapSize);
|
|
if (stackmapSize != 0) {
|
|
vm->GetFileLoader()->GetStackMapParser()->CalculateStackMap(std::move(stackmapPtr),
|
|
des_[i].GetHostCodeSecAddr(), startAddr);
|
|
}
|
|
}
|
|
for (auto &funcEntryDes : GetStubs()) {
|
|
auto codeAddr = funcEntryDes.codeAddr_; // offset
|
|
auto moduleIndex = funcEntryDes.moduleIndex_;
|
|
auto startAddr = des_[moduleIndex].GetDeviceCodeSecAddr();
|
|
auto delta = funcEntryDes.fpDeltaPrevFramSp_;
|
|
uintptr_t funAddr = startAddr + codeAddr;
|
|
kungfu::Func2FpDelta fun2fpDelta;
|
|
auto funSize = funcEntryDes.funcSize_;
|
|
fun2fpDelta[funAddr] = std::make_pair(delta, funSize);
|
|
vm->GetFileLoader()->GetStackMapParser()->CalculateFuncFpDelta(fun2fpDelta);
|
|
}
|
|
for (size_t i = 0; i < entries_.size(); i++) {
|
|
auto des = des_[entries_[i].moduleIndex_];
|
|
entries_[i].codeAddr_ += des.GetDeviceCodeSecAddr();
|
|
}
|
|
COMPILER_LOG(INFO) << "Load stub file success";
|
|
return true;
|
|
}
|
|
|
|
void AOTModulePackInfo::Save(const std::string &filename)
|
|
{
|
|
if (!VerifyFilePath(filename, true)) {
|
|
return;
|
|
}
|
|
std::ofstream moduleFile(filename.c_str(), std::ofstream::binary);
|
|
SetStubNum(entries_.size());
|
|
moduleFile.write(reinterpret_cast<char *>(&entryNum_), sizeof(entryNum_));
|
|
moduleFile.write(reinterpret_cast<char *>(entries_.data()), sizeof(FuncEntryDes) * entryNum_);
|
|
uint32_t moduleNum = GetCodeUnitsNum();
|
|
moduleFile.write(reinterpret_cast<char *>(&moduleNum), sizeof(moduleNum_));
|
|
moduleFile.write(reinterpret_cast<char *>(&totalCodeSize_), sizeof(totalCodeSize_));
|
|
moduleFile.write(reinterpret_cast<char *>(aotFileHashs_.data()), sizeof(uint32_t) * moduleNum);
|
|
for (size_t i = 0; i < moduleNum; i++) {
|
|
moduleFile.write(reinterpret_cast<char *>(&(des_[i].hostCodeSectionAddr_)),
|
|
sizeof(des_[i].hostCodeSectionAddr_));
|
|
moduleFile.write(reinterpret_cast<char *>(&(des_[i].codeSize_)),
|
|
sizeof(des_[i].codeSize_));
|
|
moduleFile.write(reinterpret_cast<char *>(des_[i].GetHostCodeSecAddr()),
|
|
des_[i].GetCodeSize());
|
|
moduleFile.write(reinterpret_cast<char *>(&(des_[i].stackMapSize_)),
|
|
sizeof(des_[i].stackMapSize_));
|
|
moduleFile.write(reinterpret_cast<char *>(des_[i].GetStackMapSecAddr()),
|
|
des_[i].GetStackMapSize());
|
|
}
|
|
moduleFile.close();
|
|
}
|
|
|
|
bool AOTModulePackInfo::Load(EcmaVM *vm, const std::string &filename)
|
|
{
|
|
if (!VerifyFilePath(filename)) {
|
|
COMPILER_LOG(ERROR) << "Can not load aot file from path [ " << filename << " ], "
|
|
<< "please execute ark_aot_compiler with options --aot-file.";
|
|
return false;
|
|
}
|
|
std::ifstream moduleFile(filename.c_str(), std::ofstream::binary);
|
|
if (!moduleFile.good()) {
|
|
moduleFile.close();
|
|
return false;
|
|
}
|
|
moduleFile.read(reinterpret_cast<char *>(&entryNum_), sizeof(entryNum_));
|
|
entries_.resize(entryNum_);
|
|
moduleFile.read(reinterpret_cast<char *>(entries_.data()), sizeof(FuncEntryDes) * entryNum_);
|
|
moduleFile.read(reinterpret_cast<char *>(&moduleNum_), sizeof(moduleNum_));
|
|
des_.resize(moduleNum_);
|
|
aotFileHashs_.resize(moduleNum_);
|
|
uint32_t totalCodeSize = 0;
|
|
moduleFile.read(reinterpret_cast<char *>(&totalCodeSize), sizeof(totalCodeSize_));
|
|
[[maybe_unused]] EcmaHandleScope handleScope(vm->GetAssociatedJSThread());
|
|
auto factory = vm->GetFactory();
|
|
auto codeHandle = factory->NewMachineCodeObject(totalCodeSize, nullptr);
|
|
SetCode(codeHandle);
|
|
moduleFile.read(reinterpret_cast<char *>(aotFileHashs_.data()), sizeof(uint32_t) * moduleNum_);
|
|
uint32_t curUnitOffset = 0;
|
|
for (size_t i = 0; i < moduleNum_; i++) {
|
|
moduleFile.read(reinterpret_cast<char *>(&(des_[i].hostCodeSectionAddr_)),
|
|
sizeof(des_[i].hostCodeSectionAddr_));
|
|
moduleFile.read(reinterpret_cast<char *>(&(des_[i].codeSize_)), sizeof(des_[i].codeSize_));
|
|
uint32_t codeSize = des_[i].GetCodeSize();
|
|
uintptr_t startAddr = codeHandle->GetDataOffsetAddress() + static_cast<uintptr_t>(curUnitOffset);
|
|
moduleFile.read(reinterpret_cast<char *>(startAddr), codeSize);
|
|
curUnitOffset += codeSize;
|
|
des_[i].SetDeviceCodeSecAddr(startAddr);
|
|
moduleFile.read(reinterpret_cast<char *>(&(des_[i].stackMapSize_)), sizeof(des_[i].stackMapSize_));
|
|
uint32_t stackmapSize = des_[i].GetStackMapSize();
|
|
std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize));
|
|
moduleFile.read(reinterpret_cast<char *>(stackmapPtr.get()), stackmapSize);
|
|
if (stackmapSize != 0) {
|
|
vm->GetFileLoader()->GetStackMapParser()->CalculateStackMap(std::move(stackmapPtr),
|
|
des_[i].GetHostCodeSecAddr(), startAddr);
|
|
}
|
|
}
|
|
for (auto &funcEntryDes : GetStubs()) {
|
|
auto codeAddr = funcEntryDes.codeAddr_; // offset
|
|
auto moduleIndex = funcEntryDes.moduleIndex_;
|
|
auto delta = funcEntryDes.fpDeltaPrevFramSp_;
|
|
auto funSize = funcEntryDes.funcSize_;
|
|
auto startAddr = des_[moduleIndex].GetDeviceCodeSecAddr();
|
|
uintptr_t funAddr = startAddr + codeAddr;
|
|
kungfu::Func2FpDelta fun2fpDelta;
|
|
fun2fpDelta[funAddr] = std::make_pair(delta, funSize);
|
|
vm->GetFileLoader()->GetStackMapParser()->CalculateFuncFpDelta(fun2fpDelta);
|
|
}
|
|
|
|
for (size_t i = 0; i < entries_.size(); i++) {
|
|
auto des = des_[entries_[i].moduleIndex_];
|
|
entries_[i].codeAddr_ += des.GetDeviceCodeSecAddr();
|
|
auto curFileHash = aotFileHashs_[entries_[i].moduleIndex_];
|
|
auto curMethodId = entries_[i].indexInKind_;
|
|
vm->SaveAOTFuncEntry(curFileHash, curMethodId, entries_[i].codeAddr_);
|
|
}
|
|
moduleFile.close();
|
|
COMPILER_LOG(INFO) << "Load aot file success";
|
|
return true;
|
|
}
|
|
|
|
void ModulePackInfo::Iterate(const RootVisitor &v)
|
|
{
|
|
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&machineCodeObj_)));
|
|
}
|
|
|
|
bool ModulePackInfo::VerifyFilePath([[maybe_unused]] const std::string &filePath,
|
|
[[maybe_unused]] bool toGenerate) const
|
|
{
|
|
#ifndef PANDA_TARGET_WINDOWS
|
|
if (filePath.size() > PATH_MAX) {
|
|
return false;
|
|
}
|
|
|
|
std::vector<char> resolvedPath(PATH_MAX);
|
|
auto result = realpath(filePath.c_str(), resolvedPath.data());
|
|
if (toGenerate && errno == ENOENT) {
|
|
return true;
|
|
}
|
|
if (result == nullptr) {
|
|
return false;
|
|
}
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void FileLoader::LoadStubFile()
|
|
{
|
|
if (!stubPackInfo_.Load(vm_)) {
|
|
return;
|
|
}
|
|
auto stubs = stubPackInfo_.GetStubs();
|
|
InitializeStubEntries(stubs);
|
|
}
|
|
|
|
void FileLoader::LoadAOTFile(const std::string &fileName)
|
|
{
|
|
AOTModulePackInfo aotPackInfo_;
|
|
if (!aotPackInfo_.Load(vm_, fileName)) {
|
|
return;
|
|
}
|
|
AddAOTPackInfo(aotPackInfo_);
|
|
}
|
|
|
|
void FileLoader::TryLoadSnapshotFile()
|
|
{
|
|
const CString snapshotPath(vm_->GetJSOptions().GetSnapshotOutputFile().c_str());
|
|
Snapshot snapshot(vm_);
|
|
#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
|
|
snapshot.Deserialize(SnapshotType::TS_LOADER, snapshotPath);
|
|
#endif
|
|
}
|
|
|
|
bool FileLoader::hasLoaded(const JSPandaFile *jsPandaFile)
|
|
{
|
|
auto fileHash = jsPandaFile->GetFileUniqId();
|
|
return !(hashToEntryMap_.find(fileHash) == hashToEntryMap_.end());
|
|
}
|
|
|
|
void FileLoader::UpdateJSMethods(JSHandle<JSFunction> mainFunc, const JSPandaFile *jsPandaFile)
|
|
{
|
|
// get main func method
|
|
auto mainFuncMethodId = jsPandaFile->GetMainMethodIndex();
|
|
auto fileHash = jsPandaFile->GetFileUniqId();
|
|
auto mainEntry = GetAOTFuncEntry(fileHash, mainFuncMethodId);
|
|
JSMethod *mainMethod = jsPandaFile->FindMethods(mainFuncMethodId);
|
|
mainMethod->SetAotCodeBit(true);
|
|
mainMethod->SetNativeBit(false);
|
|
mainFunc->SetCodeEntry(reinterpret_cast<uintptr_t>(mainEntry));
|
|
}
|
|
|
|
void FileLoader::SetAOTFuncEntry(const JSPandaFile *jsPandaFile, const JSHandle<JSFunction> &func)
|
|
{
|
|
auto codeEntry = GetAOTFuncEntry(jsPandaFile->GetFileUniqId(), jsPandaFile->GetUniqueMethod(func));
|
|
func->SetCodeEntryAndMarkAOT(codeEntry);
|
|
}
|
|
|
|
void FileLoader::SetAOTFuncEntryForLiteral(const JSPandaFile *jsPandaFile, const JSHandle<TaggedArray> &obj)
|
|
{
|
|
JSThread *thread = vm_->GetJSThread();
|
|
JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
|
|
size_t elementsLen = obj->GetLength();
|
|
for (size_t i = 0; i < elementsLen; i++) {
|
|
valueHandle.Update(obj->Get(i));
|
|
if (valueHandle->IsJSFunction()) {
|
|
SetAOTFuncEntry(jsPandaFile, JSHandle<JSFunction>(valueHandle));
|
|
}
|
|
}
|
|
}
|
|
|
|
void FileLoader::AdjustBCStubAndDebuggerStubEntries(JSThread *thread,
|
|
const std::vector<ModulePackInfo::FuncEntryDes> &stubs,
|
|
const AsmInterParsedOption &asmInterOpt)
|
|
{
|
|
auto defaultBCStubDes = stubs[BytecodeStubCSigns::SingleStepDebugging];
|
|
auto defaultNonexistentBCStubDes = stubs[BytecodeStubCSigns::HandleOverflow];
|
|
auto defaultBCDebuggerStubDes = stubs[BytecodeStubCSigns::BCDebuggerEntry];
|
|
auto defaultBCDebuggerExceptionStubDes = stubs[BytecodeStubCSigns::BCDebuggerExceptionEntry];
|
|
ASSERT(defaultBCStubDes.kind_ == CallSignature::TargetKind::BYTECODE_HELPER_HANDLER);
|
|
thread->SetUnrealizedBCStubEntry(defaultBCStubDes.codeAddr_);
|
|
thread->SetNonExistedBCStubEntry(defaultNonexistentBCStubDes.codeAddr_);
|
|
#define UNDEF_STUB(name) \
|
|
thread->SetBCStubEntry(BytecodeStubCSigns::ID_##name, defaultBCStubDes.codeAddr_);
|
|
INTERPRETER_IGNORED_BC_STUB_LIST(UNDEF_STUB)
|
|
#undef UNDEF_STUB
|
|
for (int i = asmInterOpt.handleStart; i <= asmInterOpt.handleEnd && i >= 0; i++) {
|
|
thread->SetBCStubEntry(static_cast<size_t>(i), defaultBCStubDes.codeAddr_);
|
|
}
|
|
// bc debugger stub entries
|
|
thread->SetNonExistedBCDebugStubEntry(defaultNonexistentBCStubDes.codeAddr_);
|
|
for (size_t i = 0; i < BCStubEntries::EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT; i++) {
|
|
if (i == BytecodeStubCSigns::ID_ExceptionHandler) {
|
|
thread->SetBCDebugStubEntry(i, defaultBCDebuggerExceptionStubDes.codeAddr_);
|
|
continue;
|
|
}
|
|
thread->SetBCDebugStubEntry(i, defaultBCDebuggerStubDes.codeAddr_);
|
|
}
|
|
}
|
|
|
|
void FileLoader::InitializeStubEntries(const std::vector<AOTModulePackInfo::FuncEntryDes>& stubs)
|
|
{
|
|
auto thread = vm_->GetAssociatedJSThread();
|
|
for (size_t i = 0; i < stubs.size(); i++) {
|
|
auto des = stubs[i];
|
|
if (des.IsCommonStub()) {
|
|
thread->SetFastStubEntry(des.indexInKind_, des.codeAddr_);
|
|
} else if (des.IsBCStub()) {
|
|
thread->SetBCStubEntry(des.indexInKind_, des.codeAddr_);
|
|
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_LOG
|
|
std::cout << "bytecode: " << GetEcmaOpcodeStr(static_cast<EcmaOpcode>(des.indexInKind_))
|
|
<< " addr:" << des.codeAddr_ << std::endl;
|
|
#endif
|
|
} else {
|
|
thread->RegisterRTInterface(des.indexInKind_, des.codeAddr_);
|
|
#if ECMASCRIPT_ENABLE_ASM_INTERPRETER_LOG
|
|
std::cout << "runtime index: " << des.indexInKind_ << " addr:" << des.codeAddr_ << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
AsmInterParsedOption asmInterOpt = vm_->GetJSOptions().GetAsmInterParsedOption();
|
|
AdjustBCStubAndDebuggerStubEntries(thread, stubs, asmInterOpt);
|
|
}
|
|
|
|
FileLoader::~FileLoader()
|
|
{
|
|
if (stackMapParser_ != nullptr) {
|
|
delete stackMapParser_;
|
|
stackMapParser_ = nullptr;
|
|
}
|
|
}
|
|
|
|
FileLoader::FileLoader(EcmaVM *vm) : vm_(vm), factory_(vm->GetFactory())
|
|
{
|
|
bool enableLog = vm->GetJSOptions().WasSetlogCompiledMethods();
|
|
stackMapParser_ = new kungfu::LLVMStackMapParser(enableLog);
|
|
}
|
|
|
|
kungfu::LLVMStackMapParser* FileLoader::GetStackMapParser()
|
|
{
|
|
return stackMapParser_;
|
|
}
|
|
|
|
void BinaryBufferParser::ParseBuffer(void *dst, uint32_t count)
|
|
{
|
|
if (count > 0 && count + offset_ <= length_) {
|
|
if (memcpy_s(dst, count, buffer_ + offset_, count) != EOK) {
|
|
LOG_ECMA(FATAL) << "memcpy_s failed";
|
|
return;
|
|
};
|
|
offset_ = offset_ + count;
|
|
} else {
|
|
LOG_ECMA(FATAL) << "parse buffer error, length is 0 or overflow";
|
|
}
|
|
}
|
|
} |