* Copyright (c) 2021 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.
*/
#ifndef ECMASCRIPT_COMPILER_CODE_GENERATOR_H
#define ECMASCRIPT_COMPILER_CODE_GENERATOR_H
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/binary_section.h"
#include "ecmascript/jspandafile/method_literal.h"
namespace panda::ecmascript::kungfu {
using ControlFlowGraph = std::vector<std::vector<GateRef>>;
class CompilationConfig;
class CompilerLog;
struct CodeInfo {
using sectionInfo = std::pair<uint8_t *, size_t>;
typedef uint8_t *(CodeInfo::*AllocaSectionCallback)(uintptr_t size, size_t alignSize);
class CodeSpace {
public:
static CodeSpace *GetInstance();
CodeSpace();
~CodeSpace();
uint8_t *Alloca(uintptr_t size, bool isReq, size_t alignSize);
private:
static constexpr size_t REQUIRED_SECS_LIMIT = (1 << 29);
static constexpr size_t UNREQUIRED_SECS_LIMIT = (1 << 28);
uint8_t *reqSecs_ {nullptr};
size_t reqBufPos_ {0};
uint8_t *unreqSecs_ {nullptr};
size_t unreqBufPos_ {0};
Mutex mutex_{};
};
class CodeSpaceOnDemand {
public:
PUBLIC_API CodeSpaceOnDemand() = default;
uint8_t *Alloca(uintptr_t size, bool isReq, size_t alignSize);
PUBLIC_API ~CodeSpaceOnDemand();
private:
static constexpr size_t SECTION_LIMIT = (1 << 29);
std::vector<std::pair<uint8_t *, uintptr_t>> sections_;
};
struct FuncInfo {
uint32_t addr = 0;
int32_t fp2PrevFrameSpDelta = 0;
kungfu::CalleeRegAndOffsetVec calleeRegInfo;
};
CodeInfo(CodeSpaceOnDemand &codeSpaceOnDemand, bool useOwnSpace);
~CodeInfo();
uint8_t *AllocaOnDemand(uintptr_t size, size_t alignSize = 0);
uint8_t *AllocaInReqSecBuffer(uintptr_t size, size_t alignSize = 0);
uint8_t *AllocaInNotReqSecBuffer(uintptr_t size, size_t alignSize = 0);
uint8_t *AllocaCodeSectionImp(uintptr_t size, const char *sectionName, AllocaSectionCallback allocaInReqSecBuffer);
uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName);
uint8_t *AllocaCodeSectionOnDemand(uintptr_t size, const char *sectionName);
void VerifyAddress(uintptr_t addr, uintptr_t size, uintptr_t alignSize);
uint8_t *AllocaDataSectionImp(uintptr_t size, const char *sectionName, AllocaSectionCallback allocaInReqSecBuffer,
AllocaSectionCallback allocaInNotReqSecBuffer);
uint8_t *AllocaDataSection(uintptr_t size, const char *sectionName);
uint8_t *AllocaDataSectionOnDemand(uintptr_t size, const char *sectionName);
void SaveFunc2Addr(std::string funcName, uint32_t address);
void SaveFunc2FPtoPrevSPDelta(std::string funcName, int32_t fp2PrevSpDelta);
void SaveFunc2CalleeOffsetInfo(std::string funcName, kungfu::CalleeRegAndOffsetVec calleeRegInfo);
void SavePC2DeoptInfo(uint64_t pc, std::vector<uint8_t> pc2DeoptInfo);
void SavePC2CallSiteInfo(uint64_t pc, std::vector<uint8_t> callSiteInfo);
const std::map<std::string, FuncInfo> &GetFuncInfos() const;
const std::map<uint64_t, std::vector<uint8_t>> &GetPC2DeoptInfo() const;
const std::unordered_map<uint64_t, std::vector<uint8_t>> &GetPC2CallsiteInfo() const;
void Reset();
uint8_t *GetSectionAddr(ElfSecName sec) const;
size_t GetSectionSize(ElfSecName sec) const;
std::vector<std::pair<uint8_t *, uintptr_t>> GetCodeInfo() const;
template <class Callback>
void IterateSecInfos(const Callback &cb) const
{
for (size_t i = 0; i < secInfos_.size(); i++) {
if (secInfos_[i].second == 0) {
continue;
}
cb(i, secInfos_[i]);
}
}
private:
std::array<sectionInfo, static_cast<int>(ElfSecName::SIZE)> secInfos_;
std::vector<std::pair<uint8_t *, uintptr_t>> codeInfo_ {};
std::map<std::string, FuncInfo> func2FuncInfo;
std::map<uint64_t, std::vector<uint8_t>> pc2DeoptInfo;
std::unordered_map<uint64_t, std::vector<uint8_t>> pc2CallsiteInfo;
bool alreadyPageAlign_ {false};
CodeSpaceOnDemand &codeSpaceOnDemand_;
bool useOwnSpace_ {false};
std::unique_ptr<CodeSpace> ownCodeSpace_ {nullptr};
uintptr_t lastAddr_ {0};
uintptr_t lastSize_ {0};
};
class Assembler {
public:
explicit Assembler(CodeInfo::CodeSpaceOnDemand &codeSpaceOnDemand, bool useOwnSpace)
: codeInfo_(codeSpaceOnDemand, useOwnSpace)
{}
virtual ~Assembler() = default;
virtual void Run(const CompilerLog &log, bool fastCompileMode, bool isJit = false) = 0;
uintptr_t GetSectionAddr(ElfSecName sec) const
{
return reinterpret_cast<uintptr_t>(codeInfo_.GetSectionAddr(sec));
}
uint32_t GetSectionSize(ElfSecName sec) const
{
return static_cast<uint32_t>(codeInfo_.GetSectionSize(sec));
}
template <class Callback>
void IterateSecInfos(const Callback &cb) const
{
codeInfo_.IterateSecInfos(cb);
}
const CodeInfo &GetCodeInfo() const
{
return codeInfo_;
}
void SetAotCodeCommentFile(const std::string &aotCodeCommentFile)
{
litecgCodeCommentFile_ = aotCodeCommentFile;
}
const std::string &GetAotCodeCommentFile() const
{
return litecgCodeCommentFile_;
}
protected:
CodeInfo codeInfo_;
private:
std::string litecgCodeCommentFile_ = "";
};
class CodeGeneratorImpl {
public:
CodeGeneratorImpl() = default;
virtual ~CodeGeneratorImpl() = default;
virtual void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
const CompilationConfig *cfg) = 0;
virtual void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile,
const std::string &methodName, const FrameType frameType,
bool enableOptInlining, bool enableBranchProfiling) = 0;
};
class CodeGenerator {
public:
CodeGenerator(std::unique_ptr<CodeGeneratorImpl> &impl, const std::string& methodName)
: impl_(std::move(impl)), methodName_(methodName)
{
}
~CodeGenerator() = default;
void RunForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index, const CompilationConfig *cfg)
{
impl_->GenerateCodeForStub(circuit, graph, index, cfg);
}
const std::string& GetMethodName() const
{
return methodName_;
}
void Run(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const FrameType frameType,
bool enableOptInlining, bool enableOptBranchProfiling)
{
impl_->GenerateCode(circuit, graph, cfg, methodLiteral, jsPandaFile, methodName_, frameType,
enableOptInlining, enableOptBranchProfiling);
}
private:
std::unique_ptr<CodeGeneratorImpl> impl_{nullptr};
std::string methodName_;
};
}
#endif